APRでハッシュテーブル

http://d.hatena.ne.jp/kanbayashi/20071211/p1 の続き。


http://dev.ariel-networks.com/apr/apr-tutorial/sample/hashtab-sample.c
のサンプルコードをちょっと改変してコメントを追加していくという方法で説明させてもらいます。


mainは一番下に、そこから呼び出している関数はその上にあります。一番下から読んで下さい。


/**
* apr tutorial sample code
* http://dev.ariel-networks.com/apr/
*/

#include

/* ハッシュテーブルを使うのに必要なヘッダ */
#include
#include
#include

/**
ハッシュテーブルの内容を変更する
*/
static void modify_hashtab(apr_hash_t *ht, apr_pool_t *mp)
{
/* テーブルにキー "foo" に対して 値 "FOO" というマッピングを追加する */
/* 値として適当なポインタを渡してもよい */
  /* キーとしても適当なポインタを渡してもよいが、その場合はそのポインタ上のキーに相当するデータの大きさをAPR_HASH_KEY_STRINGの代わりに渡すこと */
apr_hash_set(ht, "foo", APR_HASH_KEY_STRING, "FOO");

/* マッピングを削除するためにはNULLを値として設定すればよい */
apr_hash_set(ht,"to-del", APR_HASH_KEY_STRING,"TO-DEL");
apr_hash_set(ht,"to-del", APR_HASH_KEY_STRING, NULL);

/* 値を上書きしてみる */
apr_hash_set(ht,"override", APR_HASH_KEY_STRING,"old-val");
apr_hash_set(ht,override", APR_HASH_KEY_STRING,"new-val");
}

/**
ハッシュテーブルの内容をイテレートして出力してみる
*/
static void iterate_hashtab(apr_hash_t *ht)
{
apr_hash_index_t *hi;
for (hi = apr_hash_first(NULL, ht); hi; hi = apr_hash_next(hi)) {
const char *k;
const char *v;

/* 取り出したマッピングのキーと値をそれぞれ得る */
apr_hash_this(hi, (const void**)&k, NULL, (void**)&v);
/* 出力 */
printf("ht iteration: key=%s, val=%s\n", k, v);
}
}

int main(int argc, const char *argv[])
{
/* ハッシュテーブルを使用するのに必要なメモリプール*/
apr_pool_t *mp;
/* ハッシュテーブル自身 */
apr_hash_t *ht;

/* APRの初期化。何をするにも必要。*/
apr_initialize();
/* メモリプールの初期化 */
apr_pool_create(&mp, NULL);

/* ハッシュテーブルを作成 */
ht = apr_hash_make(mp);

/* ハッシュテーブルにまとめて操作を加えてみる */
modify_hashtab(ht, mp);

/* キー "foo" に対応する値のアドレスを得る。もしなかったらNULLが返る */
/* キーが文字列じゃなかった場合、キーで設定したポインタの上にあるデータの長さをAPR_HASH_KEY_STRINGの変わりに渡すこと */
  const char *val = apr_hash_get(ht, "foo", APR_HASH_KEY_STRING);
/* 出力してみる */
  printf("val for \"foo\" is %s\n", val);


/* まとめてイテレーションしてみる */
iterate_hashtab(ht);

/* メモリプールをdestroyするとハッシュテーブルもdestroyした事になるらしい */
apr_pool_destroy(mp);

/* APRの後始末。何をするにも必要 */
apr_terminate();
return 0;
}

  • 出力


/root/work/apr# ./hashtab-sample.out
val for "foo" is FOO
ht iteration: key=override, val=new-val
ht iteration: key=foo, val=FOO
ht iteration: key=bar, val=BAR
ht iteration: key=foobar, val=BAR
ht iteration: key=barfoo, val=FOO

  • 注意
    • キーに文字列以外を渡す時は、メモリのアドレスが一致するかどうかということに気を配らなければいけません。詳しくは

http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-19.html#ss19.3
を読んで下さい。

    • mallocなどでメモリを確保したデータをキーや値として挿入した時は、値の削除を行った時には元々のメモリ領域をfreeしないとメモリリークが起きます。削除する前にそれらのアドレスをgetしておいて、削除した後にfreeしてあげましょう。
  • 今後の解説予定

ベクタとリンクドリスト(APRのはリングと言うらしい)についは解説しようと思います。