MessagePack の扱えるコンテナ型まとめ

MessagePack の C/C++ バインディング上で扱うことの出来るデータ構造に付いてのエントリその 2 である。
その1 はこちら: MessagePackの扱えるプリミティブ型まとめ
このエントリでは、値を任意数格納できるコンテナ型について述べようと思う。

参考: MessagePack公式
参考: id:viver の blog

MessagePack の扱えるコンテナ型たち

コンテナ型は、cpp/object.h にある

namespace type {
	static const unsigned char NIL					= 0x01;
	static const unsigned char BOOLEAN				= 0x02;
	static const unsigned char POSITIVE_INTEGER		= 0x03;
	static const unsigned char NEGATIVE_INTEGER		= 0x04;
	static const unsigned char DOUBLE				= 0x05;
	static const unsigned char RAW					= 0x06;
	static const unsigned char ARRAY				= 0x07;
	static const unsigned char MAP					= 0x08;
}

のうち、最後の二つの

  • Array 型
  • Map 型

である。

なお、MessagePack の実装では、Array であっても Map であっても、cpp/object.h に

struct object {
	union union_type {
		// (中略)
		struct {
			object* ptr;
			uint32_t size;
		} container;
		// (中略)
	};
	// (中略)
}

とあるとおり、object* (MessagePack で扱える値全般)の単なる並びとして実装されている。

MessagePack の Array 型

MessagePack の Array 型では、任意数の値の並びを格納できる。

Array といっても均質な型の値の配列ではなく、値を並べてただけのものであるので、Array を構成する値の型は統一されていなくても構わない。id:viver 曰く、例えば C 言語な世界においては、MessagePack の Array 型はそのまま struct に対応することが意図されているのだそうだ(いっそ、コード上でも Array ではなく Tuple と呼んだ方が良いのではないかと思わないでもない)。

MessagePack の Map 型

MessagePack の Map 型では、キーと値のペアを任意数格納できる。値のみならずキーも、MessagePack で扱うことの出来る任意の型の値を利用できる*1

ここで、MessagePack の Map 型は、キーと値を任意数並べているだけのものであるので、以下の特徴がある点に注意が必要そうだ。

  • キーと値のペアの順序が保持される
  • キーには MessagePack で使える任意のオブジェクトを入れることが出来る
    • コンテナ型や null であってもキーに出来る
  • 一つのテーブルの中に、同じ*2値のキーが複数存在することも出来る
余談: 要素の順序やキーの重複の処理について

連想配列の様々な仕様を見ていて気になる点の一つとして、要素の順序が保存されるか否か、というものがある。
MessagePack の現存する実装では、テーブルの要素の順序を覚えていて、デコードするとちゃんと再現してくれるようである。

ちなみに、連想配列に順序と言うのは違和感があるようにも思えるが、少なくない連想配列の類の仕様では順序を覚えているのも事実のようだ。
たとえば Ruby だと、最近*3Ruby では連想配列の要素順を記憶するようになったそうだ。また PHP でも連想配列には順序の概念がある(Zend の持っているデータ構造もそうなっている)。それに対して、JavaScript (JSON) では、オブジェクトのプロパティの順序は保証されない。

なので、たとえば .net framework 実装を考えた場合、MessagePack の Map 型を IDictionary などにマップすると順序の情報*4が失われてしまうので、IEnumerable> でも取り出せるといた代替手段を用意しておいた方が良さそうである。

*1:なので、Map をキーに使った Map とかも作れる

*2:MessagePack によるシリアライズ結果が同一、という意味での同じ

*3:筆者は Ruby にまったく詳しくないので、もしかしたらかなり以前からかもしれない

*4:のみならず重複する要素も