Data Pile

Against Digital Amnesia

Programming With the APR - Using APR HashTables

This short article will show how to use the Apache Portable Runtime (APR) with it’s built in hashtable.

Introduction

If you are in need to place data in a memory structure to access it quickly, you are probably best with a hash table data type. The Apache Portable Runtime (APR) luckily, along some others like e.g. apr_table_t or apr_array_header_t (both defined in apr_tables.h), provides such a data type to you.

Hashtables do have the big advantage that you can supply them any data type you like. The nect big thing with hashtables is that they are usually very efficient if the number of elements that they are holding grows.

You can download the example file here.

Let’s hash

In order to demonstrate hashtables we are using a very simple data structure which holds a date, a username and a password. We then set some values onto this data structure and save the created structure into the hashtable.

After storing that object into the hashtable we are reading the objects back from the hashtable and output it’s contents.

The c0de

Now that you do have some overview of what we are actually doing here, it’s time to show you some code. I think it pretty much speaks for itself.

You should however, if you are using strings as keys, use the special APR_HASH_KEY_STRING value to indicate a string valued key to APR. This will use strlen(key) to compute the length (NUL terminator is not included there).

Simple Usage Example Of APR Hashtables (aprHashtable.c) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <apr.h>
#include <apr_hash.h>
#include <apr_time.h>
#define APR_WANT_STDIO
#include <apr_want.h>

struct userRecord
{
  apr_time_t creationDate;
  char username[30];
  char password[30];
};

void print(struct userRecord *user)
{
  apr_pool_t *p = NULL;
  char *timeReadable = NULL;
  apr_pool_create(&p, NULL);
  int i = 0;

  timeReadable = apr_palloc(p, APR_RFC822_DATE_LEN);
  apr_rfc822_date(timeReadable, user->creationDate);

  printf("Username:\t\t %s\n", user->username);
  printf("Password:\t\t %s\n", user->password);
  printf("CreationDate:\t\t %s\n", timeReadable);

  apr_pool_destroy(p);
  return;
}

/* Compile with 
 * $> export APR_LIBS="`apr-1-config --cflags --cppflags --includes --ldflags --link-ld --libs`"
 * $> export APU_LIBS="`apu-1-config --includes --ldflags --link-ld --libs`"
 * $> gcc aprHashtable.c -o aprHashtable $APR_LIBS $APU_LIBS
 */
int main(int argc, const char* const* argv)
{
  apr_status_t rv;
  apr_pool_t *p = NULL;
  struct userRecord *cUser = NULL;
  struct userRecord *readUser = NULL;
  int i = 0;
  char countName[12];
  apr_hash_index_t *hidx = NULL;


  apr_app_initialize(&argc, &argv, NULL);
  atexit(apr_terminate);

  apr_pool_create(&p, NULL);

  apr_hash_t *ht = apr_hash_make(p);

  apr_cpystrn(countName, "Jens Frey  ", 12);

  for (i=0; i < 26; i++) {
    countName[10] = (char) i + 65;
    cUser = apr_palloc(p, sizeof(struct userRecord));
    apr_cpystrn(cUser->username, countName, strlen(countName) + 1);
    apr_cpystrn(cUser->password, "secret", strlen("secret") + 1);
    cUser->creationDate = apr_time_now();

    apr_hash_set(ht, cUser->username, APR_HASH_KEY_STRING, cUser);

    print(cUser);
  }

  for (hidx = apr_hash_first(p, ht); hidx; hidx = apr_hash_next(hidx)) {
    apr_hash_this(hidx, NULL, NULL, (void*) &readUser);
    print(readUser);
  }

  readUser = apr_hash_get(ht, "Jens Frey G", APR_HASH_KEY_STRING);
  printf("\n\n");
  print(readUser);

  printf("Hashtable size: %d bytes\n",
	 apr_hash_count(ht) * sizeof(struct userRecord)
	 + apr_hash_count(ht) * sizeof(readUser->username));

  apr_terminate();
  return rv;
}

Now go and hash some values …