APR のハッシュテーブル(再挑戦)!

前回の続きです。需要の大きい C 言語用のハッシュテーブルです。GLib のハッシュテーブルと比べてみると面白いです。

APR のハッシュテーブルは GLib よりもコンパクトにまとまってるようです。また、APR 自体もそのようです。

APR は Apache License なので、LGPL を採用する GLib よりは使いやすい……のかな。この辺りの法律的な問題はよく分かりません。

なお、ハッシュテーブルではない辞書(連想配列)型として、apr_table_t なんていうのもあります。

include <stdio.h>
#include <assert.h>

#include <apr_pools.h>
#include <apr_hash.h>

/*
 * コンパイルのしかた:
 *   gcc -Wall -pedantic `pkg-config --cflags --libs apr-1` hoge.c
 *
 * API リファレンス:
 *   https://apr.apache.org/docs/apr/1.5/group__apr__hash.html
 */

int print_key_val(void *rec, const void *key, apr_ssize_t klen,
    const void *value);

int main(int argc, char *argv[])
{
  apr_pool_t *mp;
  apr_status_t rv;

  apr_hash_t *population;
  apr_hash_index_t *iter;
  const void *key;
  apr_ssize_t klen;
  void *val;

  int i;

  apr_hash_t *another_population;
  apr_hash_t *new_population;

  /* APR の初期化 */
  rv = apr_initialize();
  assert(rv == APR_SUCCESS);
  /* メモリプールの作成 */
  apr_pool_create(&mp, NULL);

  /* ハッシュテーブルの作成
   * キーに文字列以外のデータを使う場合、apr_hash_make_custom を呼ぶ
   */
  population = apr_hash_make(mp);

  /* 要素の追加 */
  key = "横浜市";
  apr_hash_set(population, key, strlen(key), (void*)3702225);
  /* 通常の NULL 終端の文字列を渡す場合、APR_HASH_KEY_STRING を
   * キーの長さの代わりに渡すことができる
   */
  apr_hash_set(population, "大阪市", APR_HASH_KEY_STRING,
      (void*)2682140);
  apr_hash_set(population, "名古屋市", APR_HASH_KEY_STRING,
      (void*)2272075);
  apr_hash_set(population, "札幌市", APR_HASH_KEY_STRING,
      (void*)1921237);
  apr_hash_set(population, "神戸市", APR_HASH_KEY_STRING,
      (void*)1539546);

  /* 要素の取得 */
  val = apr_hash_get(population, "横浜市", APR_HASH_KEY_STRING);
  printf("%s => %d\n", (char*)key, (int)(size_t)val);

  /* 要素の削除
   * バリューに NULL を指定すればよい
   */
  apr_hash_set(population, key, APR_HASH_KEY_STRING, NULL);
  if (apr_hash_get(population, key, APR_HASH_KEY_STRING) == NULL) {
    printf("要素数: %u\n", apr_hash_count(population));
    printf("そんなキーはありません……: %s\n", (char*)key);
  }

  /* for ループ */
  printf("\n----- 全要素一覧 -----\n\n");
  for (iter = apr_hash_first(mp, population); iter;
      iter = apr_hash_next(iter)) {
    apr_hash_this(iter, &key, &klen, &val);
    /* こう書いても同じ
     *   key = apr_hash_this_key(iter);
     *   val = apr_hash_this_val(iter);
     */
    printf("%s => %d\n", (char*)key, (int)(size_t)val);
  }

  /* for each */
  printf("\n----- 全要素一覧 -----\n\n");
  i = 0;
  apr_hash_do(print_key_val, &i, population);


  another_population = apr_hash_make(mp);
  apr_hash_set(another_population, "夕張市", APR_HASH_KEY_STRING,
      (void*)10925);
  apr_hash_set(another_population, "三笠市", APR_HASH_KEY_STRING,
      (void*)10225);
  apr_hash_set(another_population, "歌志内市", APR_HASH_KEY_STRING,
      (void*)4020);

  /* ハッシュテーブルのマージ
   * 2つのテーブルのキーが衝突する際は第二引数のテーブルの値が優先する
   * キーの衝突時の挙動を指定するには、apr_hash_merge を使う
   */
  new_population = apr_hash_overlay(mp, population, another_population);
  printf("\n----- 全要素一覧 -----\n\n");
  i = 0;
  apr_hash_do(print_key_val, &i, new_population);

  /* メモリプールの破壊 */
  apr_pool_destroy(mp);

  return 0;
}

int print_key_val(void *rec, const void *key, apr_ssize_t klen,
    const void *value)
{
  printf("%d: %s => %d\n", (*(int*)rec)++, (char*)key,
      (int)(size_t)value);
  return 1;  /* 0 を返すとイテレーションが停止する */
}

実行結果:

横浜市 => 3702225
要素数: 4
そんなキーはありません……: 横浜市

----- 全要素一覧 -----

大阪市 => 2682140
名古屋市 => 2272075
神戸市 => 1539546
札幌市 => 1921237

----- 全要素一覧 -----

0: 大阪市 => 2682140
1: 名古屋市 => 2272075
2: 神戸市 => 1539546
3: 札幌市 => 1921237

----- 全要素一覧 -----

0: 神戸市 => 1539546
1: 夕張市 => 10925
2: 三笠市 => 10225
3: 札幌市 => 1921237
4: 歌志内市 => 4020
5: 名古屋市 => 2272075
6: 大阪市 => 2682140

(コウヅ)

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中