SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

GDBMであそんでみたよ

薄いwrapperから連想配列まで

  • このエントリーをはてなブックマークに追加

 ファイルに保存できる汎用の辞書:GDBM(GNU Database Manager)。C-interfaceを提供する本ライブラリを段階的に拡張し、連想配列に仕立てます。

  • このエントリーをはてなブックマークに追加

 僕の主戦場はもっぱらWindowsですけど、Linux由来のコードやライブラリのお世話になることも少なくありません。先日もファイルに保存可能な辞書(key-value store)を探してて、GDBM:GNU Database ManagerのWindows版を見つけました。マジなDatabase使うほど大層なものではなく、キーと値の組をファイルに保存し、キーから値が検索できれば十分というシチュエーションだったので、このWindows-port版GDBM、ありがたく使わせていただきました。

GDBMをハダカで使う

 GDBMのトリセツはman pageを一読していただくことにして、まずはそのまま、C-interfaceでお試しコードを書いてみましょう。

list-01
#include <iostream>
#include <cassert>
#include <array>
#include <cstring> // strlen
#include <cstdlib> // free

#define GDBM_STATIC
#include <gdbm.h>

using namespace std;

void store() {
  GDBM_FILE dbf = gdbm_open("trial.db", 512, GDBM_NEWDB, 0644, 0);
  assert( dbf != nullptr );

  array<const char*,4> keys     = { "apple",  "orange", "grape",  "apple" };
  array<const char*,4> contents = { "まっく", "みかん", "ぶどう", "りんご" };

  datum key;
  datum content;

  for ( size_t i = 0; i < keys.size(); ++i ) {
    // キーと値をdatumにセット
    key.dptr = const_cast<char*>(keys[i]);
    key.dsize = strlen(keys[i]) + 1;
    content.dptr = const_cast<char*>(contents[i]);
    content.dsize = strlen(contents[i]) + 1;
    // キーと値のペアを登録
    // ※ GDBM_REPLACEにより、appleに紐づく値は
    //    ("まっく"から"りんご"に)上書きされます
    int result = gdbm_store(dbf, key, content, GDBM_REPLACE);
    assert( result == 0 );
  }
  gdbm_close(dbf);
  cout << "3 entries stored." << endl;
}

void fetch() {
  GDBM_FILE dbf = gdbm_open("trial.db", 512, GDBM_WRCREAT, 0644, 0);
  assert( dbf != nullptr );

  array<const char*,4> keys     = { "apple",  "orange", "grape",  "peach" };

  datum key;
  datum content;

  for ( const char* target : keys ) {
    // キーをdatumにセットし、
    key.dptr = const_cast<char*>(target);
    key.dsize = strlen(target) + 1;
    // キーに紐づいた値を検索
    content = gdbm_fetch(dbf, key);
    if ( content.dptr == nullptr ) {
      cout << target << " not found..." << endl;
    } else {
      cout << target << " = " << content.dptr << endl;
      free(content.dptr);
    }  
  }
  // Database内の全エントリを列挙する
  cout << "--- list all entries ---" << endl;
  key = gdbm_firstkey(dbf);
  while ( key.dptr != nullptr ) {
    char* tmp = key.dptr;
    content = gdbm_fetch(dbf, key);
    cout << key.dptr << " = " << content.dptr << endl;
    free(content.dptr);
    key = gdbm_nextkey(dbf, key);
    free(tmp);
  }
}

int main() {
  store();
  fetch();
}

 関数 store()ではキーと値のペアの登録、fetch()ではキーに紐づいた値の検索と、全エントリの列挙を行っています。GDBMが扱うデータはキー/値のいずれもデータの先頭アドレスとデータの長さ、すなわちバイト列を対象としていますから、(ここでは文字列をキー/値としていますけど)任意の型をキー/値として利用できます。気をつけなきゃならないのは、GDBMから帰ってきたdatum内のdptrが指すのはmalloc()で確保されたメモリ・ブロックであり、これをfree()するのは利用者の責任であることです。free()を忘れると少しずつメモリを食いつぶすことになります。

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
薄いwrapperでくるむ

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

επιστημη(エピステーメー)

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/7216 2013/06/26 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング