SHOEISHA iD

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

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

特集記事

GDBMであそんでみたよ

薄いwrapperから連想配列まで

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

薄いwrapperでくるむ

 "はじめの一歩"として、GDBMをうすーいクラスの皮でくるみます。

list-02
// gdbm_db.h
#ifndef GDBM_DB_H_
#define GDBM_DB_H_

#include <stdexcept>

#define GDBM_STATIC
#include <gdbm.h>

namespace gdbm {

  class db {
  public:
    db();
    db(const char* name, int block_size =512, int read_write =GDBM_WRCREAT, int mode =0644);
   ~db();

    bool open(const char* name, int block_size =512, int read_write =GDBM_WRCREAT, int mode =0644);
    bool is_open() const;
    void close();

    int store(datum key, datum content, int flag =GDBM_REPLACE);
    datum fetch(datum key) const;
    bool exists(datum key) const;
    int remove(datum key); // gdbm_delete

    datum firstkey() const;
    datum nextkey(datum key) const;

    int reorganize();
    void sync();

    static const char* strerror(gdbm_error err);
    int setopt(int option, int* value, int size);
    int fdesc();     

  private:
    db(const db&);            // no impl. to avoid copy
    db& operator=(const db&); // no impl. to avoid copy
    static void raise_error(const char* message);
    GDBM_FILE dbf_;
  };

  class db_error : public std::runtime_error {
  public:
    db_error(const char* message) : std::runtime_error(message) {}
  };

}

#endif
list-03
// gdbm_db.cpp
#include "gdbm_db.h"

namespace gdbm {

  db::db() : dbf_(nullptr) {}

  db::db(const char* name, int block_size, int read_write, int mode) {
    open(name, block_size, read_write, mode);
  }

  db::~db() { close(); }

  bool db::open(const char* name, int block_size, int read_write, int mode) {
    dbf_ = gdbm_open(const_cast<char*>(name), block_size, read_write, mode,
                     reinterpret_cast<void(*)()>(&db::raise_error));
    return is_open();
  }

  bool db::is_open() const { return dbf_ != nullptr; }

  void db::close() { gdbm_close(dbf_); dbf_ = nullptr; }

  int db::store(datum key, datum content, int flag) {
    return gdbm_store(dbf_, key, content, flag);
  }

  datum db::fetch(datum key) const {
    return gdbm_fetch(dbf_, key);
  }

  int db::remove(datum key) {
    return gdbm_delete(dbf_, key);
  }

  bool db::exists(datum key) const {
    return gdbm_exists(dbf_, key) != 0;
  }

  datum db::firstkey() const {
    return gdbm_firstkey(dbf_);
  }

  datum db::nextkey(datum key) const {
    return gdbm_nextkey(dbf_, key);
  }

  int db::reorganize() {
    return gdbm_reorganize(dbf_);
  }

  void db::sync() {
    return gdbm_sync(dbf_);
  }

  const char* db::strerror(gdbm_error err) {
    return gdbm_strerror(err);
  }

  int db::setopt(int option, int* value, int size) {
    return gdbm_setopt(dbf_, option, value, size);
  }

  int db::fdesc() {
    return gdbm_fdesc(dbf_);
  }

  void db::raise_error(const char* message) {
    throw db_error(message);
  }

}

 中のGDBMがスケて見えるほどの薄いwrapperですが、よく使われる定数値をデフォルト引数とすることで、利用者側は多少なりとも楽ができます。

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

#include "gdbm_db.h"

using namespace std;

void store() {
  gdbm::db dbx("trial.db", 512, GDBM_NEWDB);
  assert( dbx.is_open() );

  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 ) {
    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;
    int result = dbx.store(key, content);
    assert( result == 0 );
  }
  cout << "3 entries stored." << endl;
}

void fetch() {
  gdbm::db dbx("trial.db", 512, GDBM_WRCREAT);
  assert( dbx.is_open() );

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

  datum key;
  datum content;

  for ( const char* target : keys ) {
    key.dptr = const_cast<char*>(target);
    key.dsize = strlen(target) + 1;
    content =dbx.fetch(key);
    if ( content.dptr == nullptr ) {
      cout << target << " not found..." << endl;
    } else {
      cout << target << " = " << content.dptr << endl;
      free(content.dptr);
    }  
  }
  cout << "--- list all entries ---" << endl;
  key = dbx.firstkey();
  while ( key.dptr != nullptr ) {
    char* tmp = key.dptr;
    content = dbx.fetch(key);
    cout << key.dptr << " = " << content.dptr << endl;
    free(content.dptr);
    key = dbx.nextkey(key);
    free(tmp);
  }
}

int main() try {
  store();
  fetch();
} catch ( gdbm::db_error& ex ) {
  cout << ex.what() << endl;
}

次のページ
メモリ管理を楽にする

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

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

もっと読む

この記事の著者

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

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

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

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

この記事をシェア

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

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング