2013/07/10


おなじみC/C++から使えるJSONライブラリを紹介するコーナー。まずは過去のまとめ。
最近は結構 matsuu さんのブクマから見つけて記事を書いてたけど今日はそうじゃない所からご紹介。
Jansson — C library for working with JSON data

Jansson Jansson is a C library for encoding, decoding and manipulating JSON data. It features: Simpl...

http://www.digip.org/jansson/
特徴としては
  • 簡単で直感的な API とデータモデル
  • 包括的なドキュメント
  • 他のライブラリへの依存がない
  • ユニコードのフルサポート (UTF-8)
  • 徹底したテストスーツ
こんな感じ。いつもの様にサンプル。Twitter API がバージョン 1.1 になって認証無しでは殆ど機能しなくなったので github API を使う。 #include <assert.h>
#include <string.h>
#include <memory.h>
#include <curl/curl.h>
#include <jansson.h>

typedef struct {
  char* data;   // response data from server
  size_t size;  // response size of data
} MEMFILE;

MEMFILE*
memfopen() {
  MEMFILE* mf = (MEMFILE*) malloc(sizeof(MEMFILE));
  if (mf) {
    mf->data = NULL;
    mf->size = 0;
  }
  return mf;
}

void
memfclose(MEMFILE* mf) {
  if (mf->data) free(mf->data);
  free(mf);
}

size_t
memfwrite(char* ptr, size_t size, size_t nmemb, void* stream) {
  MEMFILE* mf = (MEMFILE*) stream;
  int block = size * nmemb;
  if (!mf) return block; // through
  if (!mf->data)
    mf->data = (char*) malloc(block);
  else
    mf->data = (char*) realloc(mf->data, mf->size + block);
  if (mf->data) {
    memcpy(mf->data + mf->size, ptr, block);
    mf->size += block;
  }
  return block;
}

char*
memfstrdup(MEMFILE* mf) {
  char* buf;
  if (mf->size == 0return NULL;
  buf = (char*) malloc(mf->size + 1);
  memcpy(buf, mf->data, mf->size);
  buf[mf->size] = 0;
  return buf;
}

int
main() {
  CURL* curl;
  MEMFILE* mf = NULL;
  char* js = NULL;
  int i;

  mf = memfopen();

  curl = curl_easy_init();
  curl_easy_setopt(curl, CURLOPT_URL, "https://api.github.com/legacy/repos/search/unko");
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
  curl_easy_perform(curl);
  curl_easy_cleanup(curl);

  js = memfstrdup(mf);
  memfclose(mf);

  json_error_t error;
  json_t *result = json_loads(js, 0, &error);
  if (result == NULL) {
    fputs(error.text, stderr);
    goto leave;
  }
  json_t *repositories = json_object_get(result, "repositories");
  json_t *repository;
  json_array_foreach(repositories, i, repository) {
    printf("%s/%s%s\n",
      json_string_value(json_object_get(repository, "username")),
      json_string_value(json_object_get(repository, "name")),
      json_string_value(json_object_get(repository, "description")));
  }

  json_decref(result);
leave:
  free(js);
}
実行結果 mizzy/unko: テスト用
satorunet/unko: 
siyo/unko: unko
kotatsumikan/unko: ファイルの内容を「うんこ」に変換するコマンドです。
karr3304/unko: ブログシステム
t11086/unko: 勉強中
keamano/unko: うんこアプリ
nmbakfm/unko: install unko command on your PC
nanananamememe/unko: 
fivestar/unko: test
smellman/unko: まるでくそのようだ
susuhushi/unko: github
kjwtnb/unko: いろいろと書き捨て
kamiyama/xunko: unko
FromAtom/Test: Unko
tam33363/unko_wave: 
konyavic/unko-curry: 
konishika/unko_ng: 
oilfield/unko_hakken: oilfield
tanaton/unko2ch: 2ちゃんねる過去ログ転送サービス
kenmaz/cocos2d_UnkoYoke: simple unko game
mattn/Plack-Middleware-ReplaceToUnko: plack middleware for replacing images to shit image that referer from external sites.
legokichi/superUnkoChanLv200: roombaProgramming
Plavender/Unkown: 
omomuron/unkonow: 
FanPF/unkown: I don't  kown
ThievingSix/UnkosAMI: 
nakajijapan/unkore_iphone: iPhone Game - Bureau of Nakajima Cleansing
比較する物としては parson が一番近いです。parson は各JSON 型がそれぞれ別のC言語型として扱われている為、value と object/array/number/boolean/string といったデータ型の交換が必要で、parson では json_value_get_array という関数の様に value → array という型変換はもちろん、array 内要素の value から目的の型への変換が必要になったりします。
しかし jansson の場合は全て json_t 型のポインタで交換されていて、特に型交換する必要もなく、型チェックが必要な場合は json_is_array という関数でチェックが可能なのでとても直感的に、かつシームレスに処理が書けます。
そして parson の一番の欠点としてシリアライザが無い事が挙げられますが、jansson には存在します(json_dumps等)。
この点から見て、僕が把握しているC言語から使えるJSONパーサだと、現状 jansson が一番扱いやすいと思います。
ライセンスはMIT、チュートリアルが少ないですがAPIドキュメントはしっかり書いてあります。

ぜひ仕事でも使って行きたいと思います。
Posted at by



2013/07/04


先日、某所で何人かに遊んで貰ったので、ここにも書いて皆に遊んでもらおうと思います。
mattn/habatobi-vim - GitHub
https://github.com/mattn/habatobi-vim
:Habatobi を実行すると起動します。j と k を交互にタイプすると走り出すので jkjkjkjkjkjkjkjk... とタイプして下さい。
赤い線の前でスペースキーをタイプするとジャンプします。
記録が出て、どうこうなる訳ではないですが息抜きのつもりでどうぞ。
habatobi
Posted at by




unqlite これまで組み込みDBだと SQLite が一般的でしたが、ローカルであっても NoSQL したい、組み込みで使いたい、というニーズはあるかと思います。 そんな場合、UnQLite を使うと便利そうです。
UnQLite - An Embeddable NoSQL Database Engine

UnQLite is a self-contained C library without dependency. It requires very minimal support from exte...

http://unqlite.org/
unqlite/unqlite - GitHub

README.md UnQLite UnQLite is a in-process software library which implements a self-contained, server...

https://github.com/unqlite/unqlite
特徴としては以下の通り。
  • サーバの要らない NoSQL データベースエンジン
  • トランザクショナル(ACID)データベース
  • ゼロコンフィグレーション
  • 単一のデータベースファイルでテンポラリファイルを使用しない
  • クロスプラットフォームなファイルフォーマット
  • UnQLite は依存の無いCライブラリを内蔵している
  • 標準でキーバリューストアを提供している
  • Jx9によるドキュメントストア(JSON)データベース
  • カーソルをサポートしており、リニアレコードをトラバース出来る
  • プラッガブルランタイムによりストレージエンジンを交換出来る
  • ディスクだけでなくインメモリデータベースもサポート
  • O(1) での検索をサポートした強力なストレージエンジンを構築
  • スレッドセーフで再入可能
  • 単純で綺麗で簡単にAPIが使える
  • テラバイトサイズのデータベースをサポート
  • BSDライセンス
  • 融合: UnQLiteとJx9が単一のソースコードで結合されたC言語ソースファイル
  • 可用性の高いオンラインサポート
詳しい詳細は以下を参照
UnQLite - Distinctive Features

The following page enumerates distinctive features of the UnQLite Database Engine and the Jx9 Embedd...

http://unqlite.org/features.html
試しに幾らかプログラムを書いてみた。
まずは単純にストアする物。 #include "unqlite.h"

int
main(int argc, char* argv[]) {
  int rc;
  unqlite *db;
  char buf[256];
  unqlite_int64 buflen = sizeof(buf);

  rc = unqlite_open(&db, "test.db", UNQLITE_OPEN_CREATE);
  if (rc != UNQLITE_OK) return;

  rc = unqlite_kv_store_fmt(db, "mattn", -1"俺の%s""塩");
  if (rc != UNQLITE_OK) goto leave;

  rc = unqlite_kv_fetch(db , "mattn", -1, buf, &buflen);
  if (rc != UNQLITE_OK) goto leave;

  buf[buflen] = 0;
  puts(buf);

leave:
  if (rc != UNQLITE_OK) {
    const char *pbuf;
    int len;
    unqlite_config(db, UNQLITE_CONFIG_ERR_LOG, &pbuf, &len);
    if (len > 0) {
      puts(pbuf);
    }
    if (rc != UNQLITE_BUSY && rc != UNQLITE_NOTIMPLEMENTED) {
      unqlite_rollback(db);
    }
  }
  unqlite_close(db);
}
使い方はそんなに難しくないですが、エラーを取るのに何手か掛かるのは少し面倒臭いです。 次に結合
#include "unqlite.h"

int
main(int argc, char* argv[]) {
  int rc;
  unqlite *db;
  char buf[256];
  unqlite_int64 buflen = sizeof(buf);

  rc = unqlite_open(&db, "test.db", UNQLITE_OPEN_CREATE);
  if (rc != UNQLITE_OK) return;

  rc = unqlite_kv_store(db, "mattn", -1"じゅげむ"12);
  if (rc != UNQLITE_OK) goto leave;

  rc = unqlite_kv_append(db, "mattn", -1"じゅげむ2"12);
  if (rc != UNQLITE_OK) goto leave;

  rc = unqlite_kv_append(db, "mattn", -1"ごこうの"12);
  if (rc != UNQLITE_OK) goto leave;

  rc = unqlite_kv_append(db, "mattn", -1"すりきれ"12);
  if (rc != UNQLITE_OK) goto leave;

  rc = unqlite_kv_fetch(db , "mattn", -1, buf, &buflen);
  if (rc != UNQLITE_OK) goto leave;

  buf[buflen] = 0;
  puts(buf);

leave:
  if (rc != UNQLITE_OK) {
    const char *pbuf;
    int len;
    unqlite_config(db, UNQLITE_CONFIG_ERR_LOG, &pbuf, &len);
    if (len > 0) {
      puts(pbuf);
    }
    if (rc != UNQLITE_BUSY && rc != UNQLITE_NOTIMPLEMENTED) {
      unqlite_rollback(db);
    }
  }
  unqlite_close(db);
}
伸長も楽ちん。
実は UnQLite には Jx9 という組み込み言語が内蔵されており、データベースをスクリプトで操作出来る様になっています。
#include "unqlite.h"
#include <stdio.h>

static int
printer(const void *out,unsigned int len,void *data) {
  return fwrite(out, len, 1stdout) > 0 ? UNQLITE_OK : UNQLITE_ABORT;
}

int
main(int argc, char* argv[]) {
  int rc;
  unqlite *db;
  unqlite_vm* vm;

  rc = unqlite_open(&db, "test.db", UNQLITE_OPEN_CREATE);
  if (rc != UNQLITE_OK) return;

  rc = unqlite_compile_file(db, "mattn.jx9", &vm);
  if (rc != UNQLITE_OK) goto leave;

  rc = unqlite_vm_config(vm, UNQLITE_VM_CONFIG_OUTPUT, printer, 0);
  if (rc != UNQLITE_OK) goto leave;

  rc = unqlite_vm_exec(vm);
  if (rc != UNQLITE_OK) goto leave;

leave:
  if (rc != UNQLITE_OK) {
    const char *pbuf;
    int len;
    unqlite_config(db, UNQLITE_CONFIG_ERR_LOG, &pbuf, &len);
    if (len > 0) {
      puts(pbuf);
    }
    if (rc != UNQLITE_BUSY && rc != UNQLITE_NOTIMPLEMENTED) {
      unqlite_rollback(db);
    }
  }
  if (vm) unqlite_vm_release(vm);
  unqlite_close(db);
}
この様に Jx9 ファイルをコンパイル実行するコードを書いて if (!db_exists('users')) {
  $rc = db_create('users');
  if (!$rc) {
    print db_errlog();
    return;
  }
}
$users = [
{
   name: 'james',
   age : 27,
   mail: 'dude@example.com'
},
{
   name: 'robert',
   age : 35,
   mail: 'rob@example.com'
},
{
   name: 'monji',
   age : 47,
   mail: 'monji@example.com'
},
{
   name: 'barzini',
   age : 52,
   mail: 'barz@mobster.com'
}
];
$rc = db_store('users', $users);
if (!$rc) {
  print db_errlog();
  return;
}
$rc = db_store('users', {name: 'mattn', age: 18, mail: 'mattn.jp@gmail.com'});
if (!$rc) {
  print db_errlog();
  return;
}
print "Total number of stored records: ", db_total_records('users'), JX9_EOL;
スクリプトを書きます。実行すると users データベースに JSON の様な構造でデータが格納されます。

なかなか面白いですね。
もう少し拡張すれば、ひとりぼっちTreasure Dataも作れそうな気がしました。
残念ながら、他の NoSQL と速度比較した資料を見つけ出せなかったので、時間が出来たらベンチマークも走らせてみたいと思いました。
これからこの UnQLite の各言語バインディングも出てくるんじゃないかと思います。
組み込みソフトウェア開発スタートアップ: ITエンジニアのための組み込み技術入門 (DESIGN WAVE MOOK) 組み込みソフトウェア開発スタートアップ: ITエンジニアのための組み込み技術入門 (DESIGN WAVE MOOK)
デザインウェーブマガジン編集部
CQ出版 単行本 / ¥2,420 (2005年07月01日)
 
発送可能時間:

Posted at by