Compare commits

..

204 Commits

Author SHA1 Message Date
frsyuki
f5453d38ec cpp: version 0.5.2 2010-07-14 17:06:16 +09:00
frsyuki
331bf0af21 cpp: type::raw_ref::str(), operator==, operator!=, operator< and operator> are now const 2010-07-14 17:04:41 +09:00
frsyuki
167e2475d8 cpp: generate version.h using AC_OUTPUT macro in ./configure 2010-07-06 23:30:15 +09:00
frsyuki
fe77251242 cpp: fixes missing dependency to generate version.h 2010-07-06 19:16:49 +09:00
frsyuki
0c331d2887 cpp: updates vcproj 2010-07-06 18:18:28 +09:00
frsyuki
39facd5dc6 cpp: version 0.5.1 2010-07-06 17:59:07 +09:00
frsyuki
a2bd5ae638 cpp: ./configure supports --disable-cxx option not to build/install C++ API 2010-07-06 17:45:15 +09:00
frsyuki
c57f616141 cpp: adds MSGPACK_VERSION{,_MAJOR,_MINOR} macros and msgpack{,_major,_minor} functions 2010-07-06 17:10:25 +09:00
frsyuki
3af10a1d00 cpp: adds MSGPACK_VERSION{,_MAJOR,_MINOR} macros and msgpack{,_major,_minor} functions 2010-07-06 17:00:58 +09:00
frsyuki
b3987e2402 Merge branch 'master' of github.com:msgpack/msgpack 2010-07-06 12:26:30 +09:00
frsyuki
71dd44f430 cpp: adds operator<<(std::ostream&, const tuple<Type...>&) (experimental) 2010-07-06 12:26:21 +09:00
UENISHI Kota
584462f9b9 erlang: improved spec. 2010-07-01 01:16:25 +09:00
UENISHI Kota
ff5d5d7cbc erlang: updated the comments 2010-07-01 01:14:38 +09:00
UENISHI Kota
370e92b1a6 erlang: just a golf. 2010-07-01 01:14:20 +09:00
UENISHI Kota
2469768a85 erlang: reducing unnecessary binary matching in unpack_/2
* more efficient unpack_/1 by Vincent de Phille's code. thanks.
2010-07-01 01:07:56 +09:00
UENISHI Kota
acb8fa613e erlang: adding shorthand fix for {more, undefined} problem 2010-07-01 01:02:19 +09:00
UENISHI Kota
83b4b7d83d erlang: more suitable variable name and removing unnecessary guards. 2010-07-01 00:58:48 +09:00
frsyuki
20de730541 ruby: 0.4.3 2010-06-29 15:39:47 +09:00
frsyuki
134c27c900 Merge branch 'master' of github.com:msgpack/msgpack 2010-06-29 15:13:21 +09:00
frsyuki
123ae024c6 ruby: MessagePack::VERSION constant 2010-06-29 15:12:52 +09:00
frsyuki
34a29cd0a5 ruby: fixes SEGV problem caused by GC bug at MessagePack_Unpacker_mark. 2010-06-29 14:56:23 +09:00
frsyuki
9fffa9800a ruby: fixes RDoc of Unpacker#execute and Unpacker#execute_impl 2010-06-29 14:54:09 +09:00
UENISHI Kota
358457f49d erlang: bad wrong export.. 2010-06-29 00:25:58 +09:00
UENISHI Kota
90e305d789 erlang: explicit API for serializing proplists,
so as not to make wrong call of pack({proplists()}).
2010-06-29 00:23:49 +09:00
UENISHI Kota
b471e52e28 erlang: explicit API for serializing proplists,
so as not to make wrong call of pack({proplists()}).
2010-06-29 00:21:47 +09:00
UENISHI Kota
9b5fc37399 Merge branch 'master' of http://github.com/vincentdephily/msgpack 2010-06-29 00:10:10 +09:00
Vincent de Phily
537322e3b5 Big speedup (around 40%) of maps and arrays encoding by using proper tail recursion. 2010-06-28 14:17:44 +02:00
Vincent de Phily
279121f87f erlang: Use a simple proplist instead of a dict.
A dict is overkill (code, cpu, memory) in most cases, and proplist<->dict conversion can easily be done by the libray user if desired.
        This is in line with other erlang libraries I've seen for various encoding schemes.
        The map encoder had a bug until I looked at it (see previous commit), so I guess it wasn't used much yet and a change is ok at this stage.
        The chosen representation for maps is a tuple containing the proplist as the only element.
2010-06-28 11:56:12 +02:00
UENISHI Kota
a1b2b41cdc erlang: bugfix(serialization of -234 goes <<208,22>> while it should go int16 <<0xD1, ...>>) 2010-06-26 08:40:36 +09:00
Vincent de Phily
0cca90c21d Fix encoding of fixmap type.
The tag value was wrong, and a missing /binary flag caused an error.
2010-06-25 17:32:11 +02:00
UENISHI Kota
ad052cb510 updated readme 2010-06-25 01:26:57 +09:00
UENISHI Kota
57f0598373 erlang: code refined and tests added 2010-06-25 00:44:14 +09:00
UENISHI Kota
92d192277e erlang: unpack_map's silly bug fixed. use dict:store/3.... 2010-06-25 00:22:53 +09:00
UENISHI Kota
2cdfbd8970 erlang: testing pack_map/unpack_map with a silly bug 2010-06-24 07:26:34 +09:00
UENISHI Kota
bc0c5f0cdc erlang: (un)pack_map improved, incremental unpacking 2010-06-23 09:02:53 +09:00
UENISHI Kota
230ee3a03b erlang: too short binary to decode causes error {more, Int}. 2010-06-23 01:26:10 +09:00
UENISHI Kota
ab0bf37d30 Merge branch 'master' of ssh://github.com/msgpack/msgpack 2010-06-22 11:44:25 +09:00
UENISHI Kota
b1e66256ce erlang: external APIs' type/specs. 2010-06-22 11:28:36 +09:00
UENISHI Kota
fd80693420 erlang: tests improved and code refined. 2010-06-22 11:15:18 +09:00
Naoki INADA
f222f5ed9b Python: 0.1.4 2010-06-15 18:06:58 +09:00
INADA Naoki
59603b902a Python: add "load(s)/dump(s)" alias for compatibility to simplejson/marshal/pickle. 2010-06-15 17:51:24 +09:00
frsyuki
82a5dd6cf9 java: update 2010-06-10 14:02:58 -07:00
frsyuki
a97f9081a3 Merge branch 'master' of github.com:msgpack/msgpack 2010-06-03 22:04:36 +09:00
frsyuki
b3e0ad1303 ruby: 0.4.2 2010-06-03 22:00:15 +09:00
frsyuki
251090406a ruby: adds a test case for buffering 2010-06-03 21:52:01 +09:00
frsyuki
9c3ed173b1 ruby: fixes buffering routine 2010-06-03 21:51:40 +09:00
UENISHI Kota
7cd41aeb72 erlang: tracing crosslang.rb moving to ../test 2010-06-03 00:17:17 +09:00
UENISHI Kota
8ecaf7ad4c Merge branch 'master' of ssh://github.com/msgpack/msgpack 2010-06-03 00:14:19 +09:00
frsyuki
d4049fe593 ruby: add test/test_cases.rb 2010-06-01 16:35:21 +09:00
frsyuki
989b14b519 update test/README.md 2010-06-01 15:58:44 +09:00
frsyuki
fb3e11408c add test/cases.json 2010-06-01 15:56:29 +09:00
frsyuki
3d3af3284e cpp: adds Doxyfile 2010-06-01 08:43:30 +09:00
frsyuki
eabcf15790 cpp: update tests 2010-06-01 07:16:25 +09:00
frsyuki
684bca203a cpp: adds msgpack_unpacker_next and msgpack_unpack_next 2010-06-01 07:15:58 +09:00
frsyuki
d42ecccf6f cpp: msgpack::unpack returns void 2010-06-01 07:13:47 +09:00
frsyuki
5a92c861e3 cpp: adds msgpack_vrefbuffer_new and msgpack_vrefbuffer_free 2010-06-01 07:11:01 +09:00
frsyuki
103b14ea3c cpp: adds msgpack_zbuffer_new and msgpack_zbuffer_free 2010-06-01 07:10:39 +09:00
frsyuki
e49f091b4e cpp: adds msgpack_sbuffer_new and msgpack_sbuffer_free 2010-06-01 07:10:17 +09:00
frsyuki
6056f93910 cpp: add cases.mpac test 2010-06-01 05:15:36 +09:00
frsyuki
18fa2d1af4 Merge branch 'master' of github.com:msgpack/msgpack 2010-06-01 04:47:37 +09:00
frsyuki
062ed8a4c4 add test/cases.mpac and test/cases_compact.mpac 2010-06-01 04:47:28 +09:00
UENISHI Kota
49f3872d04 erlang: temporary documentation and .gitignore 2010-06-01 00:31:12 +09:00
UENISHI Kota
d9b467098a erlang: added more cross-language tests. better type specification. 2010-05-31 23:56:06 +09:00
UENISHI Kota
7d1e51437e erlang: added usage of cross-language test. 2010-05-31 23:13:32 +09:00
frsyuki
f5a7d444e2 Merge branch 'master' of github.com:msgpack/msgpack 2010-05-31 17:32:51 +09:00
frsyuki
a0071c2f9f add crosslang.rb 2010-05-31 17:27:51 +09:00
frsyuki
98a5e43883 add crosslang.cc 2010-05-31 17:16:40 +09:00
UENISHI Kota
f40ebe5b43 Merge branch 'master' of ssh://github.com/msgpack/msgpack 2010-05-31 00:26:49 +09:00
UENISHI Kota
d7d78d9a2b added more tests,
and OMake continuous building.
2010-05-31 00:25:53 +09:00
Hideyuki Tanaka
5a12d36a0a incr version 2010-05-30 19:45:00 +09:00
Hideyuki Tanaka
e61dc76ae1 fix peek object 2010-05-30 19:11:04 +09:00
Hideyuki Tanaka
0da22193bd fix typo 2010-05-30 17:20:49 +09:00
Hideyuki Tanaka
d43921823e fix initialize pointer 2010-05-30 17:19:43 +09:00
UENISHI Kota
6b5b76b0c9 initial import from http://bitbucket.org/kuenishi/messagepack-for-erlang 2010-05-30 15:01:10 +09:00
frsyuki
602971408b cpp: move source files into src/ directory 2010-05-30 03:02:40 +09:00
frsyuki
2f5d83f07d cpp: type::tuple& operator>>: fix conversion type 2010-05-30 01:45:07 +09:00
frsyuki
81b0c316cd java: Unpacker: rewind internal buffer on filled <= offset 2010-05-30 01:39:48 +09:00
frsyuki
6df86384ca java: update javadoc 2010-05-29 07:54:49 +09:00
frsyuki
3fbcde4bd7 ruby: don't use rb_enc_set/get on ruby 1.8 2010-05-26 18:11:09 +09:00
frsyuki
293293c23c ruby: set mp->user.source = Qnil before tempalte_execute_do on Unpacker#each 2010-05-26 18:01:27 +09:00
frsyuki
47185d757e ruby: version 0.4.0 2010-05-26 07:55:02 +09:00
frsyuki
94c3998507 ruby: update gemspec 2010-05-26 07:43:05 +09:00
frsyuki
5fa589691c ruby: use malloc/realloc for stream buffer 2010-05-26 07:01:28 +09:00
frsyuki
26bc835c7e ruby: buffer rewinding 2010-05-26 04:30:49 +09:00
frsyuki
fc7da17fa2 cpp: add sbuffer::clear() and vrefbuffer::clear() 2010-05-25 02:57:37 +09:00
frsyuki
dbebe9771b ruby: update rdoc 2010-05-25 02:55:58 +09:00
frsyuki
d0af8aa9f1 ruby: rdoc 2010-05-23 21:10:49 +09:00
Kazuki Ohta
f8173e93f5 java: version 0.3 (added CHANGES.txt and LICENSE.txt) 2010-05-23 01:48:20 +09:00
frsyuki
fa6ea6848f java: fixed problem that empty array and empty map don't check Schema 2010-05-23 01:38:01 +09:00
frsyuki
5982970e21 java: fixed problem that empty array and empty map don't check Schema 2010-05-23 01:34:45 +09:00
Kazuki Ohta
c43e5e0c95 java: added testcases for empty array and empty map 2010-05-23 01:31:15 +09:00
frsyuki
b4fc79c38e java: fixes compile error 2010-05-22 17:05:17 +09:00
frsyuki
b9cb270b8f java: add Unpacker.unpack(MessageUnpackable) and Unpacker.tryUnpackNil() 2010-05-22 03:34:43 +09:00
frsyuki
1fe35d7efe java: fix Packer.packByte 2010-05-22 03:34:17 +09:00
frsyuki
ec8c19b1f0 java: javadoc 2010-05-20 17:32:15 +09:00
frsyuki
c2525bcc05 java: add Unpacker.wrap method 2010-05-20 06:19:26 +09:00
frsyuki
985c31b378 java: add Unpacker.wrap method 2010-05-20 06:18:32 +09:00
frsyuki
135a9f5586 java: fix direct conversion API 2010-05-20 05:44:44 +09:00
frsyuki
979ff80982 java: redesign 2010-05-20 03:49:26 +09:00
frsyuki
6cde9f3a9d Merge branch 'master' of github.com:msgpack/msgpack 2010-05-19 16:31:16 +09:00
frsyuki
5cad81bf4c cpp: fix return type mismatch in zone.c 2010-05-18 14:48:36 +09:00
frsyuki
18967162cf cpp: fix return type mismatch in unpack.c 2010-05-18 14:48:23 +09:00
tokuhirom
6ea75f3a9f Perl: do not use done_testing 2010-05-17 05:52:32 +09:00
tokuhirom
f51123d009 oops 2010-05-17 05:49:39 +09:00
tokuhirom
be6376ee2d Perl: build_requires and requires are duped. 2010-05-08 12:02:31 +09:00
tokuhirom
120a85a3e5 Perl: releng for 0.12 2010-05-05 17:28:38 +09:00
tokuhirom
262fe96c29 Perl: PERL_NO_GET_CONTEXT makes horrible dTHXs. remove it. 2010-05-05 17:25:45 +09:00
tokuhirom
1864df5ed0 Perl: cleanup Makefile.PL 2010-05-05 17:25:25 +09:00
tokuhirom
09bae0a9e8 Perl: Test::Requires is not needed for this test. 2010-05-05 17:25:08 +09:00
tokuhirom
ebe41a24f1 perl: releng for data-messagepack 0.11 2010-05-05 16:59:31 +09:00
tokuhirom
f0f574a15b Perl: releng for 0.10 2010-05-05 16:55:06 +09:00
tokuhirom
9420436c09 Perl: added test case 2010-05-05 16:22:40 +09:00
tokuhirom
2b8f853b96 Perl: fixed some issues. thanks to gfx++
http://gist.github.com/387743
2010-05-05 16:17:57 +09:00
tokuhirom
2c2bf60d0c Perl: added README file. 2010-05-05 15:50:07 +09:00
Hideyuki Tanaka
62b82448d5 Merge branch 'master' of git@github.com:msgpack/msgpack 2010-05-05 04:33:11 +09:00
Hideyuki Tanaka
2f12e6c3d0 remove compiler warnings 2010-05-05 04:28:04 +09:00
Kazuki Ohta
8ce23f8e3e java: fixed pom.xml to work "mvn deploy" command 2010-05-04 18:33:29 +09:00
Hideyuki Tanaka
dbe760d6e2 make () to OBJECT instance (Nil) 2010-05-04 16:24:45 +09:00
Hideyuki Tanaka
674c26d9c7 fix feed function from Handle 2010-05-04 16:22:04 +09:00
tokuhirom
7b68b04efd Perl: change for release Data-MessagePack-0.09_01 2010-05-03 01:36:48 +09:00
tokuhirom
e0b65bf196 Merge branch 'master' of git@github.com:msgpack/msgpack 2010-05-03 01:20:00 +09:00
tokuhirom
77f5cb1f1f Perl: updated docs. 2010-05-03 01:09:21 +09:00
tokuhirom
2a222737f8 Merge branch 'master' of git@github.com:msgpack/msgpack 2010-05-03 01:04:50 +09:00
tokuhirom
77d48f9cee Perl: fixed memory leak issue 2010-05-03 00:46:15 +09:00
tokuhirom
c77eac325e Perl: added failing test case for memory leaks 2010-05-03 00:22:16 +09:00
tokuhirom
517ced2a54 Perl: added more test case for streaming unpacker 2010-05-03 00:08:02 +09:00
tokuhirom
70d2c47367 perl: added more test case for streaming deserializer. 2010-05-02 22:09:18 +09:00
frsyuki
e57084f6df cpp: update ChangeLog 2010-04-29 23:45:48 +09:00
frsyuki
8783cf8ec3 cpp: fixes unpacker::next 2010-04-29 22:32:43 +09:00
frsyuki
2af7a7c6ac Merge branch 'master' of github.com:msgpack/msgpack 2010-04-29 22:15:17 +09:00
frsyuki
91a1f8d9e1 cpp: new streaming deserialier API. 2010-04-29 22:15:03 +09:00
Kazuki Ohta
fc5e8ddca1 java: add Unpacker.feed() function for java.nio.ByteBuffer 2010-04-29 21:27:41 +09:00
frsyuki
6352472c5f python: sourceforge.jp -> sourceforge.net 2010-04-29 09:06:46 +09:00
Naoki INADA
833ee6484c Release msgpack-python 0.1.3 2010-04-29 07:52:32 +09:00
Naoki INADA
dda3d24bca Add download url. 2010-04-29 07:08:41 +09:00
Naoki INADA
f77d76a320 Add COPYING file to python package. 2010-04-29 07:01:16 +09:00
frsyuki
c51fabf6ed msgpack/pack_template.h: don't evaluate undefined macro 2010-04-29 02:39:53 +09:00
frsyuki
b10cb658ca pack_template.h: template_unsigned_long:
wrong size checking on !defined(SIZEOF_SHORT) && !defined(SHRT_MAX)"
2010-04-29 00:39:45 +09:00
frsyuki
68f60568ac cpp: build libmsgpackc.so for backward compatibility. 2010-04-26 21:52:19 +09:00
frsyuki
9fbca83ac0 cpp: add test/{zone,pack_unpack,streaming,object,convert,buffer}.cc 2010-04-25 18:08:14 +09:00
frsyuki
d19bfaa2cb cpp: fixes msgpack_vc8.vcproj 2010-04-25 09:09:06 +09:00
frsyuki
53d5ddb345 cpp: fixes operator<<(packer<Stream>&, const object&) 2010-04-25 08:26:42 +09:00
frsyuki
0a5c2e7ab9 c,cpp: MSGPACK_OBJECT_NIL = 0x00 2010-04-25 08:16:12 +09:00
frsyuki
35802ba949 cpp: msgpack_object_equal 2010-04-25 08:00:04 +09:00
frsyuki
72160aac9a cpp: combines libmsgpackc and libmsgpack into libmsgpack 2010-04-25 07:56:19 +09:00
frsyuki
9df6916029 cpp: object::object(const T& v, zone* z) 2 2010-04-25 06:39:12 +09:00
frsyuki
9bfa2354ff cpp: fixes serialization of object::type == DOUBLE 2010-04-25 02:37:04 +09:00
frsyuki
7d945d3c8e cpp: explicit object(const T& v) 2010-04-25 02:30:53 +09:00
frsyuki
05e28752f1 cpp: MSGPACK_DEFINE defines T::msgpack_object(object*, zone*) 2010-04-25 01:57:05 +09:00
frsyuki
01b6673528 cpp: bool operator==(object& x, const T& y) 2010-04-25 01:24:24 +09:00
frsyuki
4e85ebbf98 cpp: object::object(const T& v, zone* z) 2010-04-25 01:12:25 +09:00
frsyuki
120e8bffd7 cpp: object::object(const T& v) and object::operator=(const T& v) 2010-04-25 00:03:09 +09:00
frsyuki
8335823748 ruby-0.3.9 2010-04-23 20:24:36 +09:00
frsyuki
c9fcf4020f ruby: streaming deserializer test 2010-04-23 20:18:48 +09:00
frsyuki
b10a736744 ruby: fixese backward compatibility of streaming deserializer 2010-04-23 18:13:36 +09:00
frsyuki
60fbaf7612 ruby: 0.3.8 2010-04-22 14:56:25 +09:00
frsyuki
d24193630e reverts variable-length stack: avoids memory leak 2010-04-22 14:46:54 +09:00
frsyuki
354af69f62 ruby: fixes SEGV on MessagePack_Unpacker_each 2010-04-22 14:38:10 +09:00
Taro L. Saito
bccac610a4 changed the src/test folder 2010-04-20 00:05:26 +09:00
Taro L. Saito
5aa6209664 add README 2010-04-19 23:52:40 +09:00
Taro L. Saito
d693d92702 removed unnecessary settings 2010-04-19 23:34:18 +09:00
Taro L. Saito
f2622e54e3 moved src and test codes to src/{main,test}/java 2010-04-19 23:05:00 +09:00
Taro L. Saito
20fe9b6dde added pom.xml 2010-04-19 22:39:53 +09:00
Kazuki Ohta
11f7aa4212 cpp: fixed small typo in configure.in 2010-04-18 15:11:50 +09:00
Hideyuki Tanaka
f53c351fd2 haskell binding 2010-04-18 02:17:49 +09:00
Kazuki Ohta
fb96617377 java: add javadoc,javadoc-jar,pom,dist,mvn-install,mvn-deploy ANT tasks.
Now maven2 repository for msgpack is created at the following URL.
  - http://msgpack.sourceforge.net/maven2/
2010-04-18 01:18:40 +09:00
frsyuki
05b8c00ee7 cpp: fixes windows compatibility 2010-04-18 00:39:45 +09:00
frsyuki
58854fdae9 cpp: add cpp/README.md 2010-04-18 00:39:23 +09:00
frsyuki
fd31ff772f Merge branch 'master' of github.com:msgpack/msgpack 2010-04-18 00:08:17 +09:00
frsyuki
ab8e0c9e31 c,cpp: reforms source tree 2010-04-18 00:08:03 +09:00
Kazuki Ohta
abeed3be84 java: add tests for array and map 2010-04-17 23:25:42 +09:00
Kazuki Ohta
a65438c6fe java: skip building jar file for the faster testing 2010-04-17 22:53:56 +09:00
frsyuki
c3f43fb0cf template_execute: fixes embed stack 2010-04-17 22:43:11 +09:00
Kazuki Ohta
2807504a81 java: add tests for float, double, nil, boolean, string 2010-04-17 22:10:41 +09:00
Kazuki Ohta
08b716c96d java: add TestPackUnpack for int 2010-04-17 21:16:32 +09:00
Kazuki Ohta
b4b1f0a2c9 introduce JUnit framework for testing. 2010-04-17 20:17:43 +09:00
frsyuki
228f742b2f ruby: set encoding to 'ASCII-8BIT' before deserializing on ruby-1.9 2010-04-17 20:02:47 +09:00
frsyuki
a55affe4d5 ruby: add Symbol#to_msgpack 2010-04-17 16:16:56 +09:00
frsyuki
a6ec726ed7 malloc/realloc the stack when its length becomes > MSGPACK_EMBED_STACK_SIZE 2010-04-14 21:11:31 +09:00
frsyuki
87835a4e60 ruby: remove init_stack, adopt rb_gc_mark_maybe 2010-04-14 21:08:06 +09:00
Masahiro Nakagawa
1f18af4395 c: fixes comment in pack_template.h 2010-04-08 23:01:19 +09:00
frsyuki
e79747a600 cpp: msgpack/pack.hpp: fixes header 2010-04-07 20:02:00 +09:00
Masahiro Nakagawa
bd36ac2c0c cpp: fixes argument type of pack_int* methods 2010-04-07 19:54:14 +09:00
frsyuki
c6186f2c01 ruby: version 0.3.7 2010-04-06 17:59:34 +09:00
frsyuki
d639f57470 ruby: fixes Segmentation fault on MessagePack.unpack(nil) 2010-04-06 17:46:38 +09:00
Hideyuki TAKEI
99a2d28592 import MessagePack for PHP 2010-04-05 00:10:28 +09:00
frsyuki
254ee80c16 c: fixes msgpack_zbuffer_write: error checking 2010-04-04 22:11:16 +09:00
frsyuki
e43f57fe1a c: fixes msgpack_zbuffer_flush: error checking 2010-04-04 22:06:27 +09:00
Masahiro Nakagawa
f88c029a4c c: fixes msgpack_zbuffer_flush 2010-04-04 21:55:00 +09:00
frsyuki
93c3cbeaef ruby fixes gemspec: require_paths = ["lib"] 2010-04-04 21:45:56 +09:00
frsyuki
88c77b793f Merge branch 'master' of github.com:msgpack/msgpack 2010-04-04 21:40:19 +09:00
frsyuki
11286524a5 ruby: fixes 'File not found: lib' message on gem installation 2010-04-02 03:22:29 +09:00
frsyuki
7c863c341e ruby: use gem-compile gem instead of some scripts to create binary gems 2010-04-02 02:19:41 +09:00
moaikids
3416cf984e fix: org.msgpack.impl.UnpackerImpl.java CS_MAP_16 deserialize bug(line.388) 2010-04-01 23:15:36 +09:00
moaikids
1784746e7e fix: CS_MAP_16 deserialize bug(line.388) 2010-04-01 23:13:56 +09:00
Keiji Muraishi
6c6df1adaf should raise TypeError on find unsupported value 2010-03-31 17:29:07 +09:00
Keiji Muraishi
f91e1c17c0 fix typo in Makefile 2010-03-31 17:09:00 +09:00
frsyuki
58201b95f2 ruby: version 0.3.4 2010-03-31 13:46:28 +09:00
frsyuki
fcce8f6d51 ruby: use 'readpartial' instead of 'sysread' if !io.respond_to?(:sysread) 2010-03-31 12:00:26 +09:00
frsyuki
f7bdda8828 cpp: fixes pack_short(int) -> pack_short(short) 2010-03-29 21:18:01 +09:00
frsyuki
df5a60fd5b ruby: append_buffer calls "<<" method if the buffer object.class != String 2010-03-26 15:16:13 +09:00
frsyuki
5782ab7ccc c,cpp: add msgpack_zbuffer and msgpack::zbuffer 2010-03-26 14:33:49 +09:00
frsyuki
72e3f98213 cpp: alias pack(Stream* s, const T& v) -> pack(Stream& const T& v) 2010-03-26 14:30:50 +09:00
frsyuki
1b1433a664 ruby: copy the deserialized string if length <= RSTRING_EMBED_LEN_MAX 2010-03-26 14:29:49 +09:00
220 changed files with 13698 additions and 2496 deletions

View File

@@ -1,18 +0,0 @@
if ENABLE_CXX
SUBDIRS = c cpp
else
SUBDIRS = c
endif
nobase_include_HEADERS = \
msgpack/pack_define.h \
msgpack/pack_template.h \
msgpack/unpack_define.h \
msgpack/unpack_template.h \
msgpack/sysdep.h
EXTRA_DIST = \
msgpack_vc8.vcproj \
msgpack_vc8.sln \
msgpack_vc8.postbuild.bat

70
README
View File

@@ -1,70 +0,0 @@
MessagePack
-----------
Binary-based efficient data interchange format.
*Requirements
MessagePack is only tested on Linux and Mac OS X, but it may run on other
UNIX-like platforms.
gcc >= 4.1 is required to build.
*Installation
Simply run ./configure && make && make install to install C and C++ binding.
$ ./configure
$ make
$ sudo make install
To install Ruby binding, run ./makegem.sh script on ruby/ directory and install
generated gem package.
$ cd ruby
$ ./makegem.sh
$ gem install msgpack-*.gem
*Usage
C++:
include msgpack.hpp header and link libmsgpack library.
see example/simple.cc for example.
g++ simple.cc -lmsgpack
g++ stream.cc -lmsgpack -lpthread
C:
include msgpack.h header and link libmsgpackc library.
see example/simple.c for example.
gcc simple.c -lmsgpackc
Ruby:
require msgpack library.
see example/simple.rb for example.
ruby -rubygems simple.rb
API Document is available at http://msgpack.sourceforge.jp/.
Copyright (C) 2008-2010 FURUHASHI Sadayuki
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

37
README.md Normal file
View File

@@ -0,0 +1,37 @@
MessagePack
===========
Extremely efficient object serialization library. It's like JSON, but very fast and small.
## What's MessagePack?
MessagePack is a binary-based efficient object serialization library. It enables to exchange structured objects between many languages like JSON. But unlike JSON, it is very fast and small.
Typical small integer (like flags or error code) is saved only in 1 byte, and typical short string only needs 1 byte except the length of the string itself. \[1,2,3\] (3 elements array) is serialized in 4 bytes using MessagePack as follows:
require 'msgpack'
msg = [1,2,3].to_msgpack #=> "\x93\x01\x02\x03"
MessagePack.unpack(msg) #=> [1,2,3]
## Performance
![Serialization + Deserialization Speed Test](http://msgpack.sourceforge.net/index/speedtest.png)
In this test, it measured the elapsed time of serializing and deserializing 200,000 target objects. The target object consists of the three integers and 512 bytes string.
The source code of this test is available from [frsyuki' serializer-speed-test repository.](http://github.com/frsyuki/serializer-speed-test)
## Getting Started
Usage and other documents about implementations in each language are found at [the web site.](http://msgpack.sourceforge.net/)
## Learn More
- [Project Web Site](http://msgpack.sourceforge.net/)
- [MessagePack format specification](http://msgpack.sourceforge.net/spec)
- [Repository at github](http://github.com/msgpack/msgpack)
- [Wiki](http://msgpack.sourceforge.net/start)
- [MessagePack-RPC](http://github.com/msgpack/msgpack-rpc)

View File

@@ -1,28 +0,0 @@
lib_LTLIBRARIES = libmsgpackc.la
libmsgpackc_la_SOURCES = \
unpack.c \
object.c \
vrefbuffer.c \
zone.c
nobase_include_HEADERS = \
msgpack.h \
msgpack/sbuffer.h \
msgpack/vrefbuffer.h \
msgpack/pack.h \
msgpack/unpack.h \
msgpack/object.h \
msgpack/zone.h
# -version-info CURRENT:REVISION:AGE
libmsgpackc_la_LDFLAGS = -version-info 2:0:0
check_PROGRAMS = \
msgpackc_test
msgpackc_test_SOURCES = test.cpp
msgpackc_test_CXXFLAGS = -I$(top_srcdir) -I$(top_srcdir)/c
msgpackc_test_LDADD = libmsgpackc.la -lgtest_main
TESTS = $(check_PROGRAMS)

323
c/bench.c
View File

@@ -1,323 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <msgpack/pack.h>
#include <msgpack/unpack.h>
#include <yajl/yajl_parse.h>
#include <yajl/yajl_gen.h>
static struct timeval g_timer;
void reset_timer()
{
gettimeofday(&g_timer, NULL);
}
void show_timer(size_t bufsz)
{
struct timeval endtime;
gettimeofday(&endtime, NULL);
double sec = (endtime.tv_sec - g_timer.tv_sec)
+ (double)(endtime.tv_usec - g_timer.tv_usec) / 1000 / 1000;
printf("%f sec\n", sec);
printf("%f MB\n", ((double)bufsz)/1024/1024);
printf("%f Mbps\n", ((double)bufsz)*8/sec/1000/1000);
}
static int reformat_null(void * ctx) { return 1; }
static int reformat_boolean(void * ctx, int boolean) { return 1; }
static int reformat_number(void * ctx, const char * s, unsigned int l) { return 1; }
static int reformat_string(void * ctx, const unsigned char * stringVal, unsigned int stringLen) { return 1; }
static int reformat_map_key(void * ctx, const unsigned char * stringVal, unsigned int stringLen) { return 1; }
static int reformat_start_map(void * ctx) { return 1; }
static int reformat_end_map(void * ctx) { return 1; }
static int reformat_start_array(void * ctx) { return 1; }
static int reformat_end_array(void * ctx) { return 1; }
static void* unpack_uint8(void* data, uint8_t d) { return NULL; }
static void* unpack_uint16(void* data, uint16_t d) { return NULL; }
static void* unpack_uint32(void* data, uint32_t d) { return NULL; }
static void* unpack_uint64(void* data, uint64_t d) { return NULL; }
static void* unpack_int8(void* data, int8_t d) { return NULL; }
static void* unpack_int16(void* data, int16_t d) { return NULL; }
static void* unpack_int32(void* data, int32_t d) { return NULL; }
static void* unpack_int64(void* data, int64_t d) { return NULL; }
static void* unpack_float(void* data, float d) { return NULL; }
static void* unpack_double(void* data, double d) { return NULL; }
static void* unpack_nil(void* data) { return NULL; }
static void* unpack_true(void* data) { return NULL; }
static void* unpack_false(void* data) { return NULL; }
static void* unpack_array(void* data, unsigned int n) { return NULL; }
static void unpack_array_item(void* data, void* c, void* o) { }
static void* unpack_map(void* data, unsigned int n) { return NULL; }
static void unpack_map_item(void* data, void* c, void* k, void* v) { }
static void* unpack_raw(void* data, const char* b, const char* p, unsigned int l) { /*printf("unpack raw %p %lu\n",p,l);*/ return NULL; }
typedef struct {
size_t allocated;
size_t length;
char* buffer;
} pack_buffer;
static const size_t PACK_INITIAL_BUFFER_SIZE = 32*1024;
static void pack_buffer_init(pack_buffer* data)
{
data->buffer = malloc(PACK_INITIAL_BUFFER_SIZE);
data->length = 0;
data->allocated = PACK_INITIAL_BUFFER_SIZE;
}
static void pack_buffer_reset(pack_buffer* data)
{
data->buffer = realloc(data->buffer, PACK_INITIAL_BUFFER_SIZE);
data->allocated = PACK_INITIAL_BUFFER_SIZE;
data->length = 0;
}
static void pack_buffer_free(pack_buffer* data)
{
free(data->buffer);
}
static void pack_append_buffer(void* user, const char* b, unsigned int l)
{
pack_buffer* data = (pack_buffer*)user;
if(data->allocated - data->length < l) {
data->buffer = realloc(data->buffer, data->allocated*2);
data->allocated *= 2;
}
memcpy(data->buffer + data->length, b, l);
data->length += l;
}
static const unsigned int TASK_INT_NUM = 1<<24;
static const unsigned int TASK_STR_LEN = 1<<15;
//static const unsigned int TASK_INT_NUM = 1<<20;
//static const unsigned int TASK_STR_LEN = 1<<12;
static const char* TASK_STR_PTR;
void bench_json(void)
{
puts("== JSON ==");
yajl_gen_config gcfg = {0, NULL};
yajl_gen g = yajl_gen_alloc(&gcfg);
yajl_parser_config hcfg = { 0, 0 };
yajl_callbacks callbacks = {
reformat_null,
reformat_boolean,
NULL,
NULL,
reformat_number,
reformat_string,
reformat_start_map,
reformat_map_key,
reformat_end_map,
reformat_start_array,
reformat_end_array
};
yajl_handle h = yajl_alloc(&callbacks, &hcfg, NULL);
const unsigned char * buf;
unsigned int len;
puts("generate integer");
reset_timer();
{
unsigned int i;
yajl_gen_array_open(g);
for(i=0; i < TASK_INT_NUM; ++i) {
yajl_gen_integer(g, i);
}
yajl_gen_array_close(g);
}
show_timer(len);
yajl_gen_get_buf(g, &buf, &len);
puts("----");
puts("parse integer");
reset_timer();
{
yajl_status stat = yajl_parse(h, buf, len);
if (stat != yajl_status_ok && stat != yajl_status_insufficient_data) {
unsigned char * str = yajl_get_error(h, 1, buf, len);
fprintf(stderr, (const char *) str);
}
}
show_timer(len);
//yajl_gen_clear(g);
yajl_gen_free(g);
g = yajl_gen_alloc(&gcfg);
yajl_free(h);
h = yajl_alloc(&callbacks, &hcfg, NULL);
puts("----");
puts("generate string");
reset_timer();
{
unsigned int i;
yajl_gen_array_open(g);
for(i=0; i < TASK_STR_LEN; ++i) {
yajl_gen_string(g, (const unsigned char*)TASK_STR_PTR, i);
}
yajl_gen_array_close(g);
}
show_timer(len);
yajl_gen_get_buf(g, &buf, &len);
puts("----");
puts("parse string");
reset_timer();
{
yajl_status stat = yajl_parse(h, buf, len);
if (stat != yajl_status_ok && stat != yajl_status_insufficient_data) {
unsigned char * str = yajl_get_error(h, 1, buf, len);
fprintf(stderr, (const char *) str);
}
}
show_timer(len);
yajl_gen_free(g);
yajl_free(h);
}
void bench_msgpack(void)
{
puts("== MessagePack ==");
pack_buffer mpkbuf;
pack_buffer_init(&mpkbuf);
msgpack_pack_t* mpk = msgpack_pack_new(
&mpkbuf, pack_append_buffer);
msgpack_unpack_callback cb = {
unpack_uint8,
unpack_uint16,
unpack_uint32,
unpack_uint64,
unpack_int8,
unpack_int16,
unpack_int32,
unpack_int64,
unpack_float,
unpack_double,
unpack_nil,
unpack_true,
unpack_false,
unpack_array,
unpack_array_item,
unpack_map,
unpack_map_item,
unpack_raw,
};
msgpack_unpack_t* mupk = msgpack_unpack_new(NULL, &cb);
size_t len;
const char* buf;
puts("pack integer");
reset_timer();
{
unsigned int i;
msgpack_pack_array(mpk, TASK_INT_NUM);
for(i=0; i < TASK_INT_NUM; ++i) {
msgpack_pack_unsigned_int(mpk, i);
}
}
show_timer(mpkbuf.length);
len = mpkbuf.length;
buf = mpkbuf.buffer;
puts("----");
puts("unpack integer");
reset_timer();
{
size_t off = 0;
int ret = msgpack_unpack_execute(mupk, buf, len, &off);
if(ret < 0) {
fprintf(stderr, "Parse error.\n");
} else if(ret == 0) {
fprintf(stderr, "Not finished.\n");
}
}
show_timer(mpkbuf.length);
pack_buffer_reset(&mpkbuf);
msgpack_unpack_reset(mupk);
puts("----");
puts("pack string");
reset_timer();
{
unsigned int i;
msgpack_pack_array(mpk, TASK_STR_LEN);
for(i=0; i < TASK_STR_LEN; ++i) {
msgpack_pack_raw(mpk, i);
msgpack_pack_raw_body(mpk, TASK_STR_PTR, i);
}
}
show_timer(mpkbuf.length);
len = mpkbuf.length;
buf = mpkbuf.buffer;
puts("----");
puts("unpack string");
reset_timer();
{
size_t off = 0;
int ret = msgpack_unpack_execute(mupk, buf, len, &off);
if(ret < 0) {
fprintf(stderr, "Parse error.\n");
} else if(ret == 0) {
fprintf(stderr, "Not finished.\n");
}
}
show_timer(mpkbuf.length);
msgpack_unpack_free(mupk);
msgpack_pack_free(mpk);
pack_buffer_free(&mpkbuf);
}
int main(int argc, char* argv[])
{
char* str = malloc(TASK_STR_LEN);
memset(str, 'a', TASK_STR_LEN);
TASK_STR_PTR = str;
bench_msgpack();
bench_json();
return 0;
}

View File

@@ -1,9 +0,0 @@
CFLAGS += -Wall -g -I. -I.. -O4
LDFLAGS += -lyajl
all: bench
bench: bench.o pack.o unpack.o pack.h unpack.h
$(CC) bench.o pack.o unpack.o $(CFLAGS) $(LDFLAGS) -o $@

View File

@@ -1,123 +0,0 @@
/*
* MessagePack for C unpacking routine
*
* Copyright (C) 2008-2009 FURUHASHI Sadayuki
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MSGPACK_UNPACKER_H__
#define MSGPACK_UNPACKER_H__
#include "msgpack/zone.h"
#include "msgpack/object.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct msgpack_unpacker {
char* buffer;
size_t used;
size_t free;
size_t off;
size_t parsed;
msgpack_zone* z;
size_t initial_buffer_size;
void* ctx;
} msgpack_unpacker;
bool msgpack_unpacker_init(msgpack_unpacker* mpac, size_t initial_buffer_size);
void msgpack_unpacker_destroy(msgpack_unpacker* mpac);
msgpack_unpacker* msgpack_unpacker_new(size_t initial_buffer_size);
void msgpack_unpacker_free(msgpack_unpacker* mpac);
static inline bool msgpack_unpacker_reserve_buffer(msgpack_unpacker* mpac, size_t size);
static inline char* msgpack_unpacker_buffer(msgpack_unpacker* mpac);
static inline size_t msgpack_unpacker_buffer_capacity(const msgpack_unpacker* mpac);
static inline void msgpack_unpacker_buffer_consumed(msgpack_unpacker* mpac, size_t size);
int msgpack_unpacker_execute(msgpack_unpacker* mpac);
msgpack_object msgpack_unpacker_data(msgpack_unpacker* mpac);
msgpack_zone* msgpack_unpacker_release_zone(msgpack_unpacker* mpac);
void msgpack_unpacker_reset_zone(msgpack_unpacker* mpac);
void msgpack_unpacker_reset(msgpack_unpacker* mpac);
static inline size_t msgpack_unpacker_message_size(const msgpack_unpacker* mpac);
typedef enum {
MSGPACK_UNPACK_SUCCESS = 2,
MSGPACK_UNPACK_EXTRA_BYTES = 1,
MSGPACK_UNPACK_CONTINUE = 0,
MSGPACK_UNPACK_PARSE_ERROR = -1,
} msgpack_unpack_return;
msgpack_unpack_return
msgpack_unpack(const char* data, size_t len, size_t* off,
msgpack_zone* z, msgpack_object* result);
static inline size_t msgpack_unpacker_parsed_size(const msgpack_unpacker* mpac);
bool msgpack_unpacker_flush_zone(msgpack_unpacker* mpac);
bool msgpack_unpacker_expand_buffer(msgpack_unpacker* mpac, size_t size);
bool msgpack_unpacker_reserve_buffer(msgpack_unpacker* mpac, size_t size)
{
if(mpac->free >= size) { return true; }
return msgpack_unpacker_expand_buffer(mpac, size);
}
char* msgpack_unpacker_buffer(msgpack_unpacker* mpac)
{
return mpac->buffer + mpac->used;
}
size_t msgpack_unpacker_buffer_capacity(const msgpack_unpacker* mpac)
{
return mpac->free;
}
void msgpack_unpacker_buffer_consumed(msgpack_unpacker* mpac, size_t size)
{
mpac->used += size;
mpac->free -= size;
}
size_t msgpack_unpacker_message_size(const msgpack_unpacker* mpac)
{
return mpac->parsed - mpac->off + mpac->used;
}
size_t msgpack_unpacker_parsed_size(const msgpack_unpacker* mpac)
{
return mpac->parsed;
}
#ifdef __cplusplus
}
#endif
#endif /* msgpack/unpack.h */

View File

@@ -1,61 +0,0 @@
AC_INIT(msgpack/unpack_template.h)
AC_CONFIG_AUX_DIR(ac)
AM_INIT_AUTOMAKE(msgpack, 0.4.3)
AC_CONFIG_HEADER(config.h)
AC_SUBST(CFLAGS)
if test "" = "$CFLAGS"; then
CFLAGS="-g -O4"
fi
AC_PROG_CC
CFLAGS="-O4 -Wall $CFLAGS -I.."
AC_MSG_CHECKING([if c++ api is enabled])
AC_ARG_ENABLE(cxx,
AS_HELP_STRING([--disable-cxx],
[don't build c++ api.]) )
AC_MSG_RESULT($enable_cxx)
if test "$enable_cxx" != "no"; then
AC_SUBST(CXXFLAGS)
if test "" = "$CXXFLAGS"; then
CXXFLAGS="-g -O4"
fi
fi
# FIXME enable_cxx
AC_PROG_CXX
CXXFLAGS="-O4 -Wall $CXXFLAGS -I.. -I../c"
# FIXME enable_cxx
AC_LANG_PUSH([C++])
AC_CHECK_HEADERS(tr1/unordered_map)
AC_CHECK_HEADERS(tr1/unordered_set)
AC_LANG_POP([C++])
AC_CACHE_CHECK([for __sync_* atomic operations], msgpack_cv_atomic_ops, [
AC_TRY_LINK([
int atomic_sub(int i) { return __sync_sub_and_fetch(&i, 1); }
int atomic_add(int i) { return __sync_add_and_fetch(&i, 1); }
], [], msgpack_cv_atomic_ops="yes")
])
if test "$msgpack_cv_atomic_ops" != "yes"; then
AC_MSG_ERROR([__sync_* atomic operations are not supported.
Note that gcc < 4.1 is not supported.
If you are using gcc >= 4.1 and the default target CPU architecture is "i386", try to
add CFLAGS="--march=i686" and CXXFLAGS="-march=i668" options to ./configure as follows:
$ ./configure CFLAGS="-march=i686" CXXFLAGS="-march=i686"
])
fi
AM_CONDITIONAL(ENABLE_CXX, test "$enable_cxx" != "no")
AC_PROG_LIBTOOL
AC_OUTPUT([Makefile c/Makefile cpp/Makefile])

25
cpp/ChangeLog Normal file
View File

@@ -0,0 +1,25 @@
2010-07-14 version 0.5.2:
* type::raw::str(), operator==, operator!=, operator< and operator> are now const
* generates version.h using AC_OUTPUT macro in ./configure
2010-07-06 version 0.5.1:
* Add msgpack_vrefbuffer_new and msgpack_vrefbuffer_free
* Add msgpack_sbuffer_new and msgpack_sbuffer_free
* Add msgpack_unpacker_next and msgpack_unpack_next
* msgpack::unpack returns void
* Add MSGPACK_VERSION{,_MAJOR,_MINOR} macros to check header version
* Add msgpack_version{,_major,_minor} functions to check library version
* ./configure supports --disable-cxx option not to build C++ API
2010-04-29 version 0.5.0:
* msgpack_object_type is changed. MSGPACK_OBJECT_NIL is now 0x00.
* New safe streaming deserializer API.
* Add object::object(const T&) and object::operator=(const T&)
* Add operator==(object, const T&)
* MSGPACK_DEFINE macro defines msgpack_object(object* obj, zone* z)
* C++ programs doesn't need to link "msgpackc" library.

1552
cpp/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,44 +1,18 @@
lib_LTLIBRARIES = libmsgpack.la
SUBDIRS = src test
libmsgpack_la_SOURCES = \
object.cpp
DOC_FILES = \
README.md \
LICENSE \
NOTICE \
msgpack_vc8.vcproj \
msgpack_vc8.sln \
msgpack_vc8.postbuild.bat
nobase_include_HEADERS = \
msgpack.hpp \
msgpack/sbuffer.hpp \
msgpack/vrefbuffer.hpp \
msgpack/pack.hpp \
msgpack/unpack.hpp \
msgpack/object.hpp \
msgpack/zone.hpp \
msgpack/type.hpp \
msgpack/type/bool.hpp \
msgpack/type/float.hpp \
msgpack/type/int.hpp \
msgpack/type/list.hpp \
msgpack/type/deque.hpp \
msgpack/type/map.hpp \
msgpack/type/nil.hpp \
msgpack/type/pair.hpp \
msgpack/type/raw.hpp \
msgpack/type/set.hpp \
msgpack/type/string.hpp \
msgpack/type/vector.hpp \
msgpack/type/tuple.hpp \
msgpack/type/define.hpp \
msgpack/type/tr1/unordered_map.hpp \
msgpack/type/tr1/unordered_set.hpp
EXTRA_DIST = \
$(DOC_FILES)
libmsgpack_la_LIBADD = -L../c -lmsgpackc
doxygen:
./preprocess clean
cd src && $(MAKE) doxygen
./preprocess
# -version-info CURRENT:REVISION:AGE
libmsgpack_la_LDFLAGS = -version-info 2:0:0
check_PROGRAMS = \
msgpack_test
msgpack_test_SOURCES = test.cpp
msgpack_test_CXXFLAGS = -I$(top_srcdir) -I$(top_srcdir)/c -I$(top_srcdir)/cpp
msgpack_test_LDADD = libmsgpack.la -lgtest_main
TESTS = $(check_PROGRAMS)

View File

78
cpp/README.md Normal file
View File

@@ -0,0 +1,78 @@
MessagePack for C/C++
=====================
Binary-based efficient object serialization library.
## Installation
Download latest package from [releases of MessagePack](http://sourceforge.net/projects/msgpack/files/) and extract it.
On UNIX-like platform, run ./configure && make && sudo make install:
$ ./configure
$ make
$ sudo make install
On Windows, open msgpack_vc8.vcproj file and build it using batch build. DLLs are built on lib folder, and the headers are built on include folder.
To use the library in your program, include msgpack.hpp header and link msgpack and msgpackc library.
## Example
#include <msgpack.hpp>
#include <vector>
int main(void) {
// This is target object.
std::vector<std::string> target;
target.push_back("Hello,");
target.push_back("World!");
// Serialize it.
msgpack::sbuffer buffer; // simple buffer
msgpack::pack(&buffer, target);
// Deserialize the serialized data.
msgpack::zone mempool; // this manages the life of deserialized object
msgpack::object obj;
msgpack::unpack_return ret =
msgpack::unpack(buffer.data, buffer.size, NULL, &mempool, &obj);
if(ret != msgapck::UNPACK_SUCCESS) {
// error check
exit(1);
}
// Print the deserialized object to stdout.
std::cout << obj << std::endl; // ["Hello," "World!"]
// Convert the deserialized object to staticaly typed object.
std::vector<std::string> result;
obj.convert(&result);
// If the type is mismatched, it throws msgpack::type_error.
obj.as<int>(); // type is mismatched, msgpack::type_error is thrown
}
API document and other example codes are available at the [wiki.](http://msgpack.sourceforge.net/start)
## License
Copyright (C) 2008-2010 FURUHASHI Sadayuki
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
See also NOTICE file.

View File

@@ -1,188 +0,0 @@
#include <msgpack/unpack.hpp>
#include <msgpack/pack.hpp>
#include <string.h>
#include <sys/time.h>
#include <iostream>
#include <stdexcept>
#include <string>
static const unsigned int TASK_INT_NUM = 1<<24;
static const unsigned int TASK_STR_LEN = 1<<15;
//static const unsigned int TASK_INT_NUM = 1<<22;
//static const unsigned int TASK_STR_LEN = 1<<13;
static const char* TASK_STR_PTR;
class simple_timer {
public:
void reset() { gettimeofday(&m_timeval, NULL); }
void show_stat(size_t bufsz)
{
struct timeval endtime;
gettimeofday(&endtime, NULL);
double sec = (endtime.tv_sec - m_timeval.tv_sec)
+ (double)(endtime.tv_usec - m_timeval.tv_usec) / 1000 / 1000;
std::cout << sec << " sec" << std::endl;
std::cout << (double(bufsz)/1024/1024) << " MB" << std::endl;
std::cout << (bufsz/sec/1000/1000*8) << " Mbps" << std::endl;
}
private:
timeval m_timeval;
};
class simple_buffer {
public:
static const size_t DEFAULT_INITIAL_SIZE = 32*1024;//512*1024*1024*2;
simple_buffer(size_t initial_size = DEFAULT_INITIAL_SIZE) :
m_storage((char*)malloc(initial_size)),
m_allocated(initial_size),
m_used(0)
{
if(!m_storage) { throw std::bad_alloc(); }
}
~simple_buffer()
{
free(m_storage);
}
public:
inline void write(const char* buf, size_t len)
{
if(m_allocated - m_used < len) {
expand_buffer(len);
}
memcpy(m_storage + m_used, buf, len);
m_used += len;
}
void clear()
{
m_used = 0;
}
private:
void expand_buffer(size_t req)
{
size_t nsize = m_allocated * 2;
size_t at_least = m_used + req;
while(nsize < at_least) { nsize *= 2; }
char* tmp = (char*)realloc(m_storage, nsize);
if(!tmp) { throw std::bad_alloc(); }
m_storage = tmp;
m_allocated = nsize;
}
public:
size_t size() const { return m_used; }
const char* data() const { return m_storage; }
private:
char* m_storage;
size_t m_allocated;
size_t m_used;
};
void bench_msgpack_int()
{
simple_buffer buf;
simple_timer timer;
std::cout << "----" << std::endl;
std::cout << "pack integer" << std::endl;
timer.reset();
{
msgpack::packer<simple_buffer> pk(buf);
pk.pack_array(TASK_INT_NUM);
for(unsigned int i=0; i < TASK_INT_NUM; ++i) {
pk.pack_unsigned_int(i);
}
}
timer.show_stat(buf.size());
std::cout << "----" << std::endl;
std::cout << "unpack integer" << std::endl;
msgpack::zone z;
msgpack::object obj;
timer.reset();
{
obj = msgpack::unpack(buf.data(), buf.size(), z);
}
timer.show_stat(buf.size());
/*
std::cout << "----" << std::endl;
std::cout << "dynamic pack integer" << std::endl;
buf.clear();
timer.reset();
msgpack::pack(buf, obj);
timer.show_stat(buf.size());
*/
}
void bench_msgpack_str()
{
simple_buffer buf;
simple_timer timer;
std::cout << "----" << std::endl;
std::cout << "pack string" << std::endl;
timer.reset();
{
msgpack::packer<simple_buffer> pk(buf);
pk.pack_array(TASK_STR_LEN);
for(unsigned int i=0; i < TASK_STR_LEN; ++i) {
pk.pack_raw(i);
pk.pack_raw_body(TASK_STR_PTR, i);
}
}
timer.show_stat(buf.size());
std::cout << "----" << std::endl;
std::cout << "unpack string" << std::endl;
msgpack::zone z;
msgpack::object obj;
timer.reset();
{
obj = msgpack::unpack(buf.data(), buf.size(), z);
}
timer.show_stat(buf.size());
/*
std::cout << "----" << std::endl;
std::cout << "dynamic pack string" << std::endl;
buf.clear();
timer.reset();
msgpack::pack(buf, obj);
timer.show_stat(buf.size());
*/
}
int main(void)
{
char* str = (char*)malloc(TASK_STR_LEN);
memset(str, 'a', TASK_STR_LEN);
TASK_STR_PTR = str;
bench_msgpack_int();
bench_msgpack_str();
return 0;
}

View File

@@ -1,9 +0,0 @@
CXXFLAGS += -Wall -g -I. -I.. -O4
LDFLAGS +=
all: bench
bench: bench.o unpack.o zone.o object.o pack.hpp unpack.hpp zone.hpp object.hpp
$(CXX) bench.o unpack.o zone.o object.o $(CXXFLAGS) $(LDFLAGS) -o $@

View File

@@ -32,7 +32,16 @@ fi
mkdir -p ac
(cd cpp && ./preprocess.sh $@; cd ..)
test -f AUTHORS || touch AUTHORS
test -f COPYING || touch COPYING
test -f ChangeLog || touch ChangeLog
test -f NEWS || touch NEWS
test -f README || cp -f README.md README
if ! ./preprocess; then
exit 1
fi
ACLOCAL="aclocal"

75
cpp/configure.in Normal file
View File

@@ -0,0 +1,75 @@
AC_INIT(src/object.cpp)
AC_CONFIG_AUX_DIR(ac)
AM_INIT_AUTOMAKE(msgpack, 0.5.2)
AC_CONFIG_HEADER(config.h)
AC_SUBST(CFLAGS)
CFLAGS="-O4 -Wall $CFLAGS"
AC_SUBST(CXXFLAGS)
CXXFLAGS="-O4 -Wall $CXXFLAGS"
AC_PROG_CC
AC_MSG_CHECKING([if C++ API is enabled])
AC_ARG_ENABLE(cxx,
AS_HELP_STRING([--disable-cxx],
[don't build C++ API]) )
AC_MSG_RESULT([$enable_cxx])
if test "$enable_cxx" != "no"; then
AC_PROG_CXX
AM_PROG_CC_C_O
fi
AM_CONDITIONAL(ENABLE_CXX, test "$enable_cxx" != "no")
AC_PROG_LIBTOOL
AM_PROG_AS
AC_MSG_CHECKING([if debug option is enabled])
AC_ARG_ENABLE(debug,
AS_HELP_STRING([--disable-debug],
[disable assert macros and omit -g option]) )
AC_MSG_RESULT([$enable_debug])
if test "$enable_debug" != "no"; then
CXXFLAGS="$CXXFLAGS -g"
CFLAGS="$CFLAGS -g"
else
CXXFLAGS="$CXXFLAGS -DNDEBUG"
CFLAGS="$CFLAGS -DNDEBUG"
fi
AC_CACHE_CHECK([for __sync_* atomic operations], msgpack_cv_atomic_ops, [
AC_TRY_LINK([
int atomic_sub(int i) { return __sync_sub_and_fetch(&i, 1); }
int atomic_add(int i) { return __sync_add_and_fetch(&i, 1); }
], [], msgpack_cv_atomic_ops="yes")
])
if test "$msgpack_cv_atomic_ops" != "yes"; then
AC_MSG_ERROR([__sync_* atomic operations are not supported.
Note that gcc < 4.1 is not supported.
If you are using gcc >= 4.1 and the default target CPU architecture is "i386", try to
add CFLAGS="--march=i686" and CXXFLAGS="-march=i686" options to ./configure as follows:
$ ./configure CFLAGS="-march=i686" CXXFLAGS="-march=i686"
])
fi
major=`echo $VERSION | sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
minor=`echo $VERSION | sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
AC_SUBST(VERSION_MAJOR, $major)
AC_SUBST(VERSION_MINOR, $minor)
AC_OUTPUT([Makefile
src/Makefile
src/msgpack/version.h
test/Makefile])

View File

@@ -0,0 +1,44 @@
IF NOT EXIST include MKDIR include
IF NOT EXIST include\msgpack MKDIR include\msgpack
IF NOT EXIST include\msgpack\type MKDIR include\msgpack\type
IF NOT EXIST include\msgpack\type\tr1 MKDIR include\msgpack\type\tr1
copy src\msgpack\pack_define.h include\msgpack\
copy src\msgpack\pack_template.h include\msgpack\
copy src\msgpack\unpack_define.h include\msgpack\
copy src\msgpack\unpack_template.h include\msgpack\
copy src\msgpack\sysdep.h include\msgpack\
copy src\msgpack.h include\
copy src\msgpack\sbuffer.h include\msgpack\
copy src\msgpack\version.h include\msgpack\
copy src\msgpack\vrefbuffer.h include\msgpack\
copy src\msgpack\zbuffer.h include\msgpack\
copy src\msgpack\pack.h include\msgpack\
copy src\msgpack\unpack.h include\msgpack\
copy src\msgpack\object.h include\msgpack\
copy src\msgpack\zone.h include\msgpack\
copy src\msgpack.hpp include\
copy src\msgpack\sbuffer.hpp include\msgpack\
copy src\msgpack\vrefbuffer.hpp include\msgpack\
copy src\msgpack\zbuffer.hpp include\msgpack\
copy src\msgpack\pack.hpp include\msgpack\
copy src\msgpack\unpack.hpp include\msgpack\
copy src\msgpack\object.hpp include\msgpack\
copy src\msgpack\zone.hpp include\msgpack\
copy src\msgpack\type.hpp include\msgpack\type\
copy src\msgpack\type\bool.hpp include\msgpack\type\
copy src\msgpack\type\float.hpp include\msgpack\type\
copy src\msgpack\type\int.hpp include\msgpack\type\
copy src\msgpack\type\list.hpp include\msgpack\type\
copy src\msgpack\type\deque.hpp include\msgpack\type\
copy src\msgpack\type\map.hpp include\msgpack\type\
copy src\msgpack\type\nil.hpp include\msgpack\type\
copy src\msgpack\type\pair.hpp include\msgpack\type\
copy src\msgpack\type\raw.hpp include\msgpack\type\
copy src\msgpack\type\set.hpp include\msgpack\type\
copy src\msgpack\type\string.hpp include\msgpack\type\
copy src\msgpack\type\vector.hpp include\msgpack\type\
copy src\msgpack\type\tuple.hpp include\msgpack\type\
copy src\msgpack\type\define.hpp include\msgpack\type\
copy src\msgpack\type\tr1\unordered_map.hpp include\msgpack\type\
copy src\msgpack\type\tr1\unordered_set.hpp include\msgpack\type\

96
msgpack_vc8.vcproj → cpp/msgpack_vc8.vcproj Executable file → Normal file
View File

@@ -43,7 +43,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="cpp;c;."
AdditionalIncludeDirectories="."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
MinimalRebuild="true"
BasicRuntimeChecks="1"
@@ -64,7 +64,7 @@
/>
<Tool
Name="VCLibrarianTool"
OutputFile="lib\$(ProjectName)d.lib"
OutputFile="lib\msgpackd.lib"
/>
<Tool
Name="VCALinkTool"
@@ -110,7 +110,7 @@
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="cpp;c;."
AdditionalIncludeDirectories="."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
@@ -129,7 +129,7 @@
/>
<Tool
Name="VCLibrarianTool"
OutputFile="lib\$(ProjectName).lib"
OutputFile="lib\msgpack.lib"
/>
<Tool
Name="VCALinkTool"
@@ -157,35 +157,7 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\c\object.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
CompileAs="2"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\cpp\object.cpp"
>
</File>
<File
RelativePath=".\c\unpack.c"
RelativePath=".\src\objectc.c"
>
<FileConfiguration
Name="Debug|Win32"
@@ -205,7 +177,7 @@
</FileConfiguration>
</File>
<File
RelativePath=".\c\vrefbuffer.c"
RelativePath=".\src\unpack.c"
>
<FileConfiguration
Name="Debug|Win32"
@@ -225,7 +197,7 @@
</FileConfiguration>
</File>
<File
RelativePath=".\c\zone.c"
RelativePath=".\src\version.c"
>
<FileConfiguration
Name="Debug|Win32"
@@ -244,6 +216,50 @@
/>
</FileConfiguration>
</File>
<File
RelativePath=".\src\vrefbuffer.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\src\zone.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\src\object.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
@@ -251,23 +267,23 @@
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\msgpack\pack_define.h"
RelativePath=".\src\msgpack\pack_define.h"
>
</File>
<File
RelativePath=".\msgpack\pack_template.h"
RelativePath=".\src\msgpack\pack_template.h"
>
</File>
<File
RelativePath=".\msgpack\sysdep.h"
RelativePath=".\src\msgpack\sysdep.h"
>
</File>
<File
RelativePath=".\msgpack\unpack_define.h"
RelativePath=".\src\msgpack\unpack_define.h"
>
</File>
<File
RelativePath=".\msgpack\unpack_template.h"
RelativePath=".\src\msgpack\unpack_template.h"
>
</File>
</Filter>

31
cpp/preprocess Executable file
View File

@@ -0,0 +1,31 @@
#!/bin/sh
preprocess() {
ruby -r erb -e 'puts ERB.new(ARGF.read).result' $1.erb > $1.tmp
if [ "$?" != 0 ]; then
echo ""
echo "** preprocess failed **"
echo ""
exit 1
else
mv $1.tmp $1
fi
}
if [ "$1" == "clean" ];then
rm -f src/msgpack/type/tuple.hpp
rm -f src/msgpack/type/define.hpp
rm -f src/msgpack/zone.hpp
else
preprocess src/msgpack/type/tuple.hpp
preprocess src/msgpack/type/define.hpp
preprocess src/msgpack/zone.hpp
fi
cp -f ../msgpack/sysdep.h src/msgpack/
cp -f ../msgpack/pack_define.h src/msgpack/
cp -f ../msgpack/pack_template.h src/msgpack/
cp -f ../msgpack/unpack_define.h src/msgpack/
cp -f ../msgpack/unpack_template.h src/msgpack/
cp -f ../test/cases.mpac test/
cp -f ../test/cases_compact.mpac test/

View File

@@ -1,17 +0,0 @@
#!/bin/sh
preprocess() {
ruby -r erb -e 'puts ERB.new(ARGF.read).result' $1.erb > $1.tmp
if [ "$?" != 0 ]; then
echo ""
echo "** preprocess failed **"
echo ""
else
mv $1.tmp $1
fi
}
preprocess msgpack/type/tuple.hpp
preprocess msgpack/type/define.hpp
preprocess msgpack/zone.hpp

100
cpp/src/Makefile.am Normal file
View File

@@ -0,0 +1,100 @@
lib_LTLIBRARIES = libmsgpack.la
libmsgpack_la_SOURCES = \
unpack.c \
objectc.c \
version.c \
vrefbuffer.c \
zone.c
if ENABLE_CXX
libmsgpack_la_SOURCES += \
object.cpp
endif
# -version-info CURRENT:REVISION:AGE
libmsgpack_la_LDFLAGS = -version-info 3:0:0
# backward compatibility
lib_LTLIBRARIES += libmsgpackc.la
libmsgpackc_la_SOURCES = \
unpack.c \
objectc.c \
version.c \
vrefbuffer.c \
zone.c
libmsgpackc_la_LDFLAGS = -version-info 2:0:0
nobase_include_HEADERS = \
msgpack/pack_define.h \
msgpack/pack_template.h \
msgpack/unpack_define.h \
msgpack/unpack_template.h \
msgpack/sysdep.h \
msgpack.h \
msgpack/sbuffer.h \
msgpack/version.h \
msgpack/vrefbuffer.h \
msgpack/zbuffer.h \
msgpack/pack.h \
msgpack/unpack.h \
msgpack/object.h \
msgpack/zone.h
if ENABLE_CXX
nobase_include_HEADERS += \
msgpack.hpp \
msgpack/sbuffer.hpp \
msgpack/vrefbuffer.hpp \
msgpack/zbuffer.hpp \
msgpack/pack.hpp \
msgpack/unpack.hpp \
msgpack/object.hpp \
msgpack/zone.hpp \
msgpack/type.hpp \
msgpack/type/bool.hpp \
msgpack/type/float.hpp \
msgpack/type/int.hpp \
msgpack/type/list.hpp \
msgpack/type/deque.hpp \
msgpack/type/map.hpp \
msgpack/type/nil.hpp \
msgpack/type/pair.hpp \
msgpack/type/raw.hpp \
msgpack/type/set.hpp \
msgpack/type/string.hpp \
msgpack/type/vector.hpp \
msgpack/type/tuple.hpp \
msgpack/type/define.hpp \
msgpack/type/tr1/unordered_map.hpp \
msgpack/type/tr1/unordered_set.hpp
endif
EXTRA_DIST = \
msgpack/version.h.in \
msgpack/zone.hpp.erb \
msgpack/type/define.hpp.erb \
msgpack/type/tuple.hpp.erb
doxygen_c:
cat ../Doxyfile > Doxyfile_c
echo "FILE_PATTERNS = *.h" >> Doxyfile_c
echo "OUTPUT_DIRECTORY = doc_c" >> Doxyfile_c
echo "PROJECT_NAME = \"MessagePack for C\"" >> Doxyfile_c
doxygen Doxyfile_c
doxygen_cpp:
cat ../Doxyfile > Doxyfile_cpp
echo "FILE_PATTERNS = *.hpp" >> Doxyfile_cpp
echo "OUTPUT_DIRECTORY = doc_cpp" >> Doxyfile_cpp
echo "PROJECT_NAME = \"MessagePack for C++\"" >> Doxyfile_cpp
doxygen Doxyfile_cpp
doxygen: doxygen_c doxygen_cpp

View File

@@ -15,9 +15,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @defgroup msgpack MessagePack C
* @{
* @}
*/
#include "msgpack/object.h"
#include "msgpack/zone.h"
#include "msgpack/pack.h"
#include "msgpack/unpack.h"
#include "msgpack/sbuffer.h"
#include "msgpack/vrefbuffer.h"
#include "msgpack/version.h"

View File

@@ -26,15 +26,21 @@ extern "C" {
#endif
/**
* @defgroup msgpack_object Dynamically typed object
* @ingroup msgpack
* @{
*/
typedef enum {
MSGPACK_OBJECT_NIL = 0x01,
MSGPACK_OBJECT_BOOLEAN = 0x02,
MSGPACK_OBJECT_POSITIVE_INTEGER = 0x03,
MSGPACK_OBJECT_NEGATIVE_INTEGER = 0x04,
MSGPACK_OBJECT_DOUBLE = 0x05,
MSGPACK_OBJECT_RAW = 0x06,
MSGPACK_OBJECT_ARRAY = 0x07,
MSGPACK_OBJECT_MAP = 0x08,
MSGPACK_OBJECT_NIL = 0x00,
MSGPACK_OBJECT_BOOLEAN = 0x01,
MSGPACK_OBJECT_POSITIVE_INTEGER = 0x02,
MSGPACK_OBJECT_NEGATIVE_INTEGER = 0x03,
MSGPACK_OBJECT_DOUBLE = 0x04,
MSGPACK_OBJECT_RAW = 0x05,
MSGPACK_OBJECT_ARRAY = 0x06,
MSGPACK_OBJECT_MAP = 0x07,
} msgpack_object_type;
@@ -79,6 +85,10 @@ typedef struct msgpack_object_kv {
void msgpack_object_print(FILE* out, msgpack_object o);
bool msgpack_object_equal(const msgpack_object x, const msgpack_object y);
/** @} */
#ifdef __cplusplus
}

View File

@@ -20,6 +20,7 @@
#include "msgpack/object.h"
#include "msgpack/pack.hpp"
#include "msgpack/zone.hpp"
#include <string.h>
#include <stdexcept>
#include <typeinfo>
@@ -34,14 +35,14 @@ class type_error : public std::bad_cast { };
namespace type {
enum object_type {
NIL = 0x01,
BOOLEAN = 0x02,
POSITIVE_INTEGER = 0x03,
NEGATIVE_INTEGER = 0x04,
DOUBLE = 0x05,
RAW = 0x06,
ARRAY = 0x07,
MAP = 0x08,
NIL = MSGPACK_OBJECT_NIL,
BOOLEAN = MSGPACK_OBJECT_BOOLEAN,
POSITIVE_INTEGER = MSGPACK_OBJECT_POSITIVE_INTEGER,
NEGATIVE_INTEGER = MSGPACK_OBJECT_NEGATIVE_INTEGER,
DOUBLE = MSGPACK_OBJECT_DOUBLE,
RAW = MSGPACK_OBJECT_RAW,
ARRAY = MSGPACK_OBJECT_ARRAY,
MAP = MSGPACK_OBJECT_MAP,
};
}
@@ -88,8 +89,21 @@ struct object {
void convert(T* v) const;
object();
object(msgpack_object obj);
operator msgpack_object();
object(msgpack_object o);
template <typename T>
explicit object(const T& v);
template <typename T>
object(const T& v, zone* z);
template <typename T>
object& operator=(const T& v);
operator msgpack_object() const;
struct with_zone;
private:
struct implicit_type;
@@ -103,18 +117,44 @@ struct object_kv {
object val;
};
struct object::with_zone : object {
with_zone(msgpack::zone* zone) : zone(zone) { }
msgpack::zone* zone;
private:
with_zone();
};
bool operator==(const object x, const object y);
bool operator!=(const object x, const object y);
template <typename T>
bool operator==(const object x, const T& y);
template <typename T>
bool operator==(const T& y, const object x);
template <typename T>
bool operator!=(const object x, const T& y);
template <typename T>
bool operator!=(const T& y, const object x);
std::ostream& operator<< (std::ostream& s, const object o);
// serialize operator
template <typename Stream, typename T>
packer<Stream>& operator<< (packer<Stream>& o, const T& v);
// convert operator
template <typename T>
T& operator>> (object o, T& v);
// deconvert operator
template <typename T>
void operator<< (object::with_zone& o, const T& v);
struct object::implicit_type {
implicit_type(object o) : obj(o) { }
@@ -179,26 +219,40 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const T& v)
return o;
}
template <typename T>
void operator<< (object::with_zone& o, const T& v)
{
v.msgpack_object(static_cast<object*>(&o), o.zone);
}
inline bool operator==(const object x, const object y)
{
return msgpack_object_equal(x, y);
}
template <typename T>
inline bool operator==(const object x, const T& y)
try {
return x == object(y);
} catch (msgpack::type_error&) {
return false;
}
inline bool operator!=(const object x, const object y)
{ return !(x == y); }
template <typename T>
inline bool operator==(const T& y, const object x)
{ return x == y; }
inline object::object() { }
template <typename T>
inline bool operator!=(const object x, const T& y)
{ return !(x == y); }
inline object::object(msgpack_object obj)
{
// FIXME beter way?
::memcpy(this, &obj, sizeof(obj));
}
inline object::operator msgpack_object()
{
// FIXME beter way?
msgpack_object obj;
::memcpy(&obj, this, sizeof(obj));
return obj;
}
template <typename T>
inline bool operator!=(const T& y, const object x)
{ return x != y; }
inline object::implicit_type object::convert() const
@@ -221,6 +275,55 @@ inline T object::as() const
}
inline object::object()
{
type = type::NIL;
}
template <typename T>
inline object::object(const T& v)
{
*this << v;
}
template <typename T>
inline object& object::operator=(const T& v)
{
*this = object(v);
return *this;
}
template <typename T>
object::object(const T& v, zone* z)
{
with_zone oz(z);
oz << v;
type = oz.type;
via = oz.via;
}
inline object::object(msgpack_object o)
{
// FIXME beter way?
::memcpy(this, &o, sizeof(o));
}
inline void operator<< (object& o, msgpack_object v)
{
// FIXME beter way?
::memcpy(&o, &v, sizeof(v));
}
inline object::operator msgpack_object() const
{
// FIXME beter way?
msgpack_object obj;
::memcpy(&obj, this, sizeof(obj));
return obj;
}
// obsolete
template <typename T>
inline void convert(T& v, object o)
@@ -260,35 +363,15 @@ packer<Stream>& operator<< (packer<Stream>& o, const object& v)
return o;
case type::POSITIVE_INTEGER:
if(v.via.u64 <= (uint64_t)std::numeric_limits<uint16_t>::max()) {
if(v.via.u64 <= (uint16_t)std::numeric_limits<uint8_t>::max()) {
o.pack_uint8(v.via.u64);
} else {
o.pack_uint16(v.via.u64);
}
} else {
if(v.via.u64 <= (uint64_t)std::numeric_limits<uint32_t>::max()) {
o.pack_uint32(v.via.u64);
} else {
o.pack_uint64(v.via.u64);
}
}
o.pack_uint64(v.via.u64);
return o;
case type::NEGATIVE_INTEGER:
if(v.via.i64 >= (int64_t)std::numeric_limits<int16_t>::min()) {
if(v.via.i64 >= (int64_t)std::numeric_limits<int8_t>::min()) {
o.pack_int8(v.via.i64);
} else {
o.pack_int16(v.via.i64);
}
} else {
if(v.via.i64 >= (int64_t)std::numeric_limits<int32_t>::min()) {
o.pack_int64(v.via.i64);
} else {
o.pack_int64(v.via.i64);
}
}
o.pack_int64(v.via.i64);
return o;
case type::DOUBLE:
o.pack_double(v.via.dec);
return o;
case type::RAW:

View File

@@ -27,6 +27,19 @@ extern "C" {
#endif
/**
* @defgroup msgpack_buffer Buffers
* @ingroup msgpack
* @{
* @}
*/
/**
* @defgroup msgpack_pack Serializer
* @ingroup msgpack
* @{
*/
typedef int (*msgpack_packer_write)(void* data, const char* buf, unsigned int len);
typedef struct msgpack_packer {
@@ -74,6 +87,8 @@ static int msgpack_pack_raw_body(msgpack_packer* pk, const void* b, size_t l);
int msgpack_pack_object(msgpack_packer* pk, msgpack_object d);
/** @} */
#define msgpack_pack_inline_func(name) \
inline int msgpack_pack ## name

View File

@@ -1,7 +1,7 @@
//
// MessagePack for C++ serializing routine
//
// Copyright (C) 2008-2009 FURUHASHI Sadayuki
// Copyright (C) 2008-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ namespace msgpack {
template <typename Stream>
class packer {
public:
packer(Stream* s);
packer(Stream& s);
~packer();
@@ -39,12 +40,12 @@ public:
packer<Stream>& pack_uint16(uint16_t d);
packer<Stream>& pack_uint32(uint32_t d);
packer<Stream>& pack_uint64(uint64_t d);
packer<Stream>& pack_int8(uint8_t d);
packer<Stream>& pack_int16(uint16_t d);
packer<Stream>& pack_int32(uint32_t d);
packer<Stream>& pack_int64(uint64_t d);
packer<Stream>& pack_int8(int8_t d);
packer<Stream>& pack_int16(int16_t d);
packer<Stream>& pack_int32(int32_t d);
packer<Stream>& pack_int64(int64_t d);
packer<Stream>& pack_short(int d);
packer<Stream>& pack_short(short d);
packer<Stream>& pack_int(int d);
packer<Stream>& pack_long(long d);
packer<Stream>& pack_long_long(long long d);
@@ -111,6 +112,12 @@ private:
};
template <typename Stream, typename T>
inline void pack(Stream* s, const T& v)
{
packer<Stream>(s).pack(v);
}
template <typename Stream, typename T>
inline void pack(Stream& s, const T& v)
{
@@ -133,6 +140,9 @@ inline void pack(Stream& s, const T& v)
#include "msgpack/pack_template.h"
template <typename Stream>
packer<Stream>::packer(Stream* s) : m_stream(*s) { }
template <typename Stream>
packer<Stream>::packer(Stream& s) : m_stream(s) { }
@@ -156,24 +166,24 @@ inline packer<Stream>& packer<Stream>::pack_uint64(uint64_t d)
{ _pack_uint64(m_stream, d); return *this; }
template <typename Stream>
inline packer<Stream>& packer<Stream>::pack_int8(uint8_t d)
inline packer<Stream>& packer<Stream>::pack_int8(int8_t d)
{ _pack_int8(m_stream, d); return *this; }
template <typename Stream>
inline packer<Stream>& packer<Stream>::pack_int16(uint16_t d)
inline packer<Stream>& packer<Stream>::pack_int16(int16_t d)
{ _pack_int16(m_stream, d); return *this; }
template <typename Stream>
inline packer<Stream>& packer<Stream>::pack_int32(uint32_t d)
inline packer<Stream>& packer<Stream>::pack_int32(int32_t d)
{ _pack_int32(m_stream, d); return *this; }
template <typename Stream>
inline packer<Stream>& packer<Stream>::pack_int64(uint64_t d)
inline packer<Stream>& packer<Stream>::pack_int64(int64_t d)
{ _pack_int64(m_stream, d); return *this;}
template <typename Stream>
inline packer<Stream>& packer<Stream>::pack_short(int d)
inline packer<Stream>& packer<Stream>::pack_short(short d)
{ _pack_short(m_stream, d); return *this; }
template <typename Stream>

View File

@@ -21,14 +21,17 @@
#include <stdlib.h>
#include <string.h>
#ifndef MSGPACK_SBUFFER_INIT_SIZE
#define MSGPACK_SBUFFER_INIT_SIZE 2048
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup msgpack_sbuffer Simple buffer
* @ingroup msgpack_buffer
* @{
*/
typedef struct msgpack_sbuffer {
size_t size;
char* data;
@@ -45,6 +48,22 @@ static inline void msgpack_sbuffer_destroy(msgpack_sbuffer* sbuf)
free(sbuf->data);
}
static inline msgpack_sbuffer* msgpack_sbuffer_new(void)
{
return (msgpack_sbuffer*)calloc(1, sizeof(msgpack_sbuffer));
}
static inline void msgpack_sbuffer_free(msgpack_sbuffer* sbuf)
{
if(sbuf == NULL) { return; }
msgpack_sbuffer_destroy(sbuf);
free(sbuf);
}
#ifndef MSGPACK_SBUFFER_INIT_SIZE
#define MSGPACK_SBUFFER_INIT_SIZE 8192
#endif
static inline int msgpack_sbuffer_write(void* data, const char* buf, unsigned int len)
{
msgpack_sbuffer* sbuf = (msgpack_sbuffer*)data;
@@ -76,6 +95,13 @@ static inline char* msgpack_sbuffer_release(msgpack_sbuffer* sbuf)
return tmp;
}
static inline void msgpack_sbuffer_clear(msgpack_sbuffer* sbuf)
{
sbuf->size = 0;
}
/** @} */
#ifdef __cplusplus
}

View File

@@ -72,6 +72,11 @@ public:
return msgpack_sbuffer_release(this);
}
void clear()
{
msgpack_sbuffer_clear(this);
}
private:
void expand_buffer(size_t len)
{

View File

@@ -39,6 +39,15 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const bool& v)
return o;
}
inline void operator<< (object& o, bool v)
{
o.type = type::BOOLEAN;
o.via.boolean = v;
}
inline void operator<< (object::with_zone& o, bool v)
{ static_cast<object&>(o) << v; }
} // namespace msgpack

View File

@@ -27,6 +27,11 @@
void msgpack_unpack(msgpack::object o) \
{ \
msgpack::type::make_define(__VA_ARGS__).msgpack_unpack(o); \
}\
template <typename MSGPACK_OBJECT> \
void msgpack_object(MSGPACK_OBJECT* o, msgpack::zone* z) const \
{ \
msgpack::type::make_define(__VA_ARGS__).msgpack_object(o, z); \
}
namespace msgpack {
@@ -51,6 +56,12 @@ struct define<> {
{
if(o.type != type::ARRAY) { throw type_error(); }
}
void msgpack_object(msgpack::object* o, msgpack::zone* z) const
{
o->type = type::ARRAY;
o->via.array.ptr = NULL;
o->via.array.size = 0;
}
};
<%0.upto(GENERATION_LIMIT) {|i|%>
template <typename A0<%1.upto(i) {|j|%>, typename A<%=j%><%}%>>
@@ -73,6 +84,14 @@ struct define<A0<%1.upto(i) {|j|%>, A<%=j%><%}%>> {
<%0.upto(i) {|j|%>
if(size <= <%=j%>) { return; } o.via.array.ptr[<%=j%>].convert(&a<%=j%>);<%}%>
}
void msgpack_object(msgpack::object* o, msgpack::zone* z) const
{
o->type = type::ARRAY;
o->via.array.ptr = (object*)z->malloc(sizeof(object)*<%=i+1%>);
o->via.array.size = <%=i+1%>;
<%0.upto(i) {|j|%>
o->via.array.ptr[<%=j%>] = object(a<%=j%>, z);<%}%>
}
<%0.upto(i) {|j|%>
A<%=j%>& a<%=j%>;<%}%>
};

View File

@@ -49,6 +49,27 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::deque<T>& v)
return o;
}
template <typename T>
inline void operator<< (object::with_zone& o, const std::deque<T>& v)
{
o.type = type::ARRAY;
if(v.empty()) {
o.via.array.ptr = NULL;
o.via.array.size = 0;
} else {
object* p = (object*)o.zone->malloc(sizeof(object)*v.size());
object* const pend = p + v.size();
o.via.array.ptr = p;
o.via.array.size = v.size();
typename std::deque<T>::const_iterator it(v.begin());
do {
*p = object(*it, o.zone);
++p;
++it;
} while(p < pend);
}
}
} // namespace msgpack

View File

@@ -57,6 +57,25 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const double& v)
}
inline void operator<< (object& o, float v)
{
o.type = type::DOUBLE;
o.via.dec = v;
}
inline void operator<< (object& o, double v)
{
o.type = type::DOUBLE;
o.via.dec = v;
}
inline void operator<< (object::with_zone& o, float v)
{ static_cast<object&>(o) << v; }
inline void operator<< (object::with_zone& o, double v)
{ static_cast<object&>(o) << v; }
} // namespace msgpack
#endif /* msgpack/type/float.hpp */

View File

@@ -56,7 +56,7 @@ namespace detail {
throw type_error();
}
};
template <typename T>
static inline T convert_integer(object o)
{
@@ -141,6 +141,70 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const unsigned long long&
{ o.pack_unsigned_long_long(v); return o; }
inline void operator<< (object& o, signed char v)
{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }
inline void operator<< (object& o, signed short v)
{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }
inline void operator<< (object& o, signed int v)
{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }
inline void operator<< (object& o, signed long v)
{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }
inline void operator<< (object& o, signed long long v)
{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }
inline void operator<< (object& o, unsigned char v)
{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }
inline void operator<< (object& o, unsigned short v)
{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }
inline void operator<< (object& o, unsigned int v)
{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }
inline void operator<< (object& o, unsigned long v)
{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }
inline void operator<< (object& o, unsigned long long v)
{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }
inline void operator<< (object::with_zone& o, signed char v)
{ static_cast<object&>(o) << v; }
inline void operator<< (object::with_zone& o, signed short v)
{ static_cast<object&>(o) << v; }
inline void operator<< (object::with_zone& o, signed int v)
{ static_cast<object&>(o) << v; }
inline void operator<< (object::with_zone& o, signed long v)
{ static_cast<object&>(o) << v; }
inline void operator<< (object::with_zone& o, signed long long v)
{ static_cast<object&>(o) << v; }
inline void operator<< (object::with_zone& o, unsigned char v)
{ static_cast<object&>(o) << v; }
inline void operator<< (object::with_zone& o, unsigned short v)
{ static_cast<object&>(o) << v; }
inline void operator<< (object::with_zone& o, unsigned int v)
{ static_cast<object&>(o) << v; }
inline void operator<< (object::with_zone& o, unsigned long v)
{ static_cast<object&>(o) << v; }
inline void operator<< (object::with_zone& o, unsigned long long v)
{ static_cast<object&>(o) << v; }
} // namespace msgpack
#endif /* msgpack/type/int.hpp */

View File

@@ -49,6 +49,27 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::list<T>& v)
return o;
}
template <typename T>
inline void operator<< (object::with_zone& o, const std::list<T>& v)
{
o.type = type::ARRAY;
if(v.empty()) {
o.via.array.ptr = NULL;
o.via.array.size = 0;
} else {
object* p = (object*)o.zone->malloc(sizeof(object)*v.size());
object* const pend = p + v.size();
o.via.array.ptr = p;
o.via.array.size = v.size();
typename std::list<T>::const_iterator it(v.begin());
do {
*p = object(*it, o.zone);
++p;
++it;
} while(p < pend);
}
}
} // namespace msgpack

View File

@@ -70,6 +70,28 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const type::assoc_vector<K
return o;
}
template <typename K, typename V>
inline void operator<< (object::with_zone& o, const type::assoc_vector<K,V>& v)
{
o.type = type::MAP;
if(v.empty()) {
o.via.map.ptr = NULL;
o.via.map.size = 0;
} else {
object_kv* p = (object_kv*)o.zone->malloc(sizeof(object_kv)*v.size());
object_kv* const pend = p + v.size();
o.via.map.ptr = p;
o.via.map.size = v.size();
typename type::assoc_vector<K,V>::const_iterator it(v.begin());
do {
p->key = object(it->first, o.zone);
p->val = object(it->second, o.zone);
++p;
++it;
} while(p < pend);
}
}
template <typename K, typename V>
inline std::map<K, V> operator>> (object o, std::map<K, V>& v)
@@ -104,6 +126,28 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::map<K,V>& v)
return o;
}
template <typename K, typename V>
inline void operator<< (object::with_zone& o, const std::map<K,V>& v)
{
o.type = type::MAP;
if(v.empty()) {
o.via.map.ptr = NULL;
o.via.map.size = 0;
} else {
object_kv* p = (object_kv*)o.zone->malloc(sizeof(object_kv)*v.size());
object_kv* const pend = p + v.size();
o.via.map.ptr = p;
o.via.map.size = v.size();
typename std::map<K,V>::const_iterator it(v.begin());
do {
p->key = object(it->first, o.zone);
p->val = object(it->second, o.zone);
++p;
++it;
} while(p < pend);
}
}
template <typename K, typename V>
inline std::multimap<K, V> operator>> (object o, std::multimap<K, V>& v)
@@ -132,6 +176,28 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::multimap<K,V>&
return o;
}
template <typename K, typename V>
inline void operator<< (object::with_zone& o, const std::multimap<K,V>& v)
{
o.type = type::MAP;
if(v.empty()) {
o.via.map.ptr = NULL;
o.via.map.size = 0;
} else {
object_kv* p = (object_kv*)o.zone->malloc(sizeof(object_kv)*v.size());
object_kv* const pend = p + v.size();
o.via.map.ptr = p;
o.via.map.size = v.size();
typename std::multimap<K,V>::const_iterator it(v.begin());
do {
p->key = object(it->first, o.zone);
p->val = object(it->second, o.zone);
++p;
++it;
} while(p < pend);
}
}
} // namespace msgpack

View File

@@ -42,6 +42,22 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const type::nil& v)
return o;
}
inline void operator<< (object& o, type::nil v)
{
o.type = type::NIL;
}
inline void operator<< (object::with_zone& o, type::nil v)
{ static_cast<object&>(o) << v; }
template <>
inline void object::as<void>() const
{
msgpack::type::nil v;
convert(&v);
}
} // namespace msgpack

View File

@@ -43,6 +43,17 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::pair<T1, T2>& v
return o;
}
template <typename T1, typename T2>
inline void operator<< (object::with_zone& o, const std::pair<T1, T2>& v)
{
o.type = type::ARRAY;
object* p = (object*)o.zone->malloc(sizeof(object)*2);
o.via.array.ptr = p;
o.via.array.size = 2;
p[0] = object(v.first, o.zone);
p[1] = object(v.second, o.zone);
}
} // namespace msgpack

View File

@@ -33,25 +33,25 @@ struct raw_ref {
uint32_t size;
const char* ptr;
std::string str() { return std::string(ptr, size); }
std::string str() const { return std::string(ptr, size); }
bool operator== (const raw_ref& x)
bool operator== (const raw_ref& x) const
{
return size == x.size && memcmp(ptr, x.ptr, size) == 0;
}
bool operator!= (const raw_ref& x)
bool operator!= (const raw_ref& x) const
{
return !(*this != x);
}
bool operator< (const raw_ref& x)
bool operator< (const raw_ref& x) const
{
if(size == x.size) { return memcmp(ptr, x.ptr, size) < 0; }
else { return size < x.size; }
}
bool operator> (const raw_ref& x)
bool operator> (const raw_ref& x) const
{
if(size == x.size) { return memcmp(ptr, x.ptr, size) > 0; }
else { return size > x.size; }
@@ -77,6 +77,16 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const type::raw_ref& v)
return o;
}
inline void operator<< (object& o, const type::raw_ref& v)
{
o.type = type::RAW;
o.via.raw.ptr = v.ptr;
o.via.raw.size = v.size;
}
inline void operator<< (object::with_zone& o, const type::raw_ref& v)
{ static_cast<object&>(o) << v; }
} // namespace msgpack

View File

@@ -48,6 +48,27 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::set<T>& v)
return o;
}
template <typename T>
inline void operator<< (object::with_zone& o, const std::set<T>& v)
{
o.type = type::ARRAY;
if(v.empty()) {
o.via.array.ptr = NULL;
o.via.array.size = 0;
} else {
object* p = (object*)o.zone->malloc(sizeof(object)*v.size());
object* const pend = p + v.size();
o.via.array.ptr = p;
o.via.array.size = v.size();
typename std::set<T>::const_iterator it(v.begin());
do {
*p = object(*it, o.zone);
++p;
++it;
} while(p < pend);
}
}
template <typename T>
inline std::multiset<T>& operator>> (object o, std::multiset<T>& v)
@@ -73,6 +94,27 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::multiset<T>& v)
return o;
}
template <typename T>
inline void operator<< (object::with_zone& o, const std::multiset<T>& v)
{
o.type = type::ARRAY;
if(v.empty()) {
o.via.array.ptr = NULL;
o.via.array.size = 0;
} else {
object* p = (object*)o.zone->malloc(sizeof(object)*v.size());
object* const pend = p + v.size();
o.via.array.ptr = p;
o.via.array.size = v.size();
typename std::multiset<T>::const_iterator it(v.begin());
do {
*p = object(*it, o.zone);
++p;
++it;
} while(p < pend);
}
}
} // namespace msgpack

View File

@@ -39,6 +39,22 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::string& v)
return o;
}
inline void operator<< (object::with_zone& o, const std::string& v)
{
o.type = type::RAW;
char* ptr = (char*)o.zone->malloc(v.size());
o.via.raw.ptr = ptr;
o.via.raw.size = v.size();
memcpy(ptr, v.data(), v.size());
}
inline void operator<< (object& o, const std::string& v)
{
o.type = type::RAW;
o.via.raw.ptr = v.data();
o.via.raw.size = v.size();
}
} // namespace msgpack

View File

@@ -50,6 +50,28 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::tr1::unordered_
return o;
}
template <typename K, typename V>
inline void operator<< (object::with_zone& o, const std::tr1::unordered_map<K,V>& v)
{
o.type = type::MAP;
if(v.empty()) {
o.via.map.ptr = NULL;
o.via.map.size = 0;
} else {
object_kv* p = (object_kv*)o.zone->malloc(sizeof(object_kv)*v.size());
object_kv* const pend = p + v.size();
o.via.map.ptr = p;
o.via.map.size = v.size();
typename std::tr1::unordered_map<K,V>::const_iterator it(v.begin());
do {
p->key = object(it->first, o.zone);
p->val = object(it->second, o.zone);
++p;
++it;
} while(p < pend);
}
}
template <typename K, typename V>
inline std::tr1::unordered_multimap<K, V> operator>> (object o, std::tr1::unordered_multimap<K, V>& v)
@@ -78,6 +100,28 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::tr1::unordered_
return o;
}
template <typename K, typename V>
inline void operator<< (object::with_zone& o, const std::tr1::unordered_multimap<K,V>& v)
{
o.type = type::MAP;
if(v.empty()) {
o.via.map.ptr = NULL;
o.via.map.size = 0;
} else {
object_kv* p = (object_kv*)o.zone->malloc(sizeof(object_kv)*v.size());
object_kv* const pend = p + v.size();
o.via.map.ptr = p;
o.via.map.size = v.size();
typename std::tr1::unordered_multimap<K,V>::const_iterator it(v.begin());
do {
p->key = object(it->first, o.zone);
p->val = object(it->second, o.zone);
++p;
++it;
} while(p < pend);
}
}
} // namespace msgpack

View File

@@ -48,6 +48,27 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::tr1::unordered_
return o;
}
template <typename T>
inline void operator<< (object::with_zone& o, const std::tr1::unordered_set<T>& v)
{
o.type = type::ARRAY;
if(v.empty()) {
o.via.array.ptr = NULL;
o.via.array.size = 0;
} else {
object* p = (object*)o.zone->malloc(sizeof(object)*v.size());
object* const pend = p + v.size();
o.via.array.ptr = p;
o.via.array.size = v.size();
typename std::tr1::unordered_set<T>::const_iterator it(v.begin());
do {
*p = object(*it, o.zone);
++p;
++it;
} while(p < pend);
}
}
template <typename T>
inline std::tr1::unordered_multiset<T>& operator>> (object o, std::tr1::unordered_multiset<T>& v)
@@ -73,6 +94,27 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::tr1::unordered_
return o;
}
template <typename T>
inline void operator<< (object::with_zone& o, const std::tr1::unordered_multiset<T>& v)
{
o.type = type::ARRAY;
if(v.empty()) {
o.via.array.ptr = NULL;
o.via.array.size = 0;
} else {
object* p = (object*)o.zone->malloc(sizeof(object)*v.size());
object* const pend = p + v.size();
o.via.array.ptr = p;
o.via.array.size = v.size();
typename std::tr1::unordered_multiset<T>::const_iterator it(v.begin());
do {
*p = object(*it, o.zone);
++p;
++it;
} while(p < pend);
}
}
} // namespace msgpack

View File

@@ -141,7 +141,7 @@ type::tuple<A0<%1.upto(i) {|j|%>, A<%=j%><%}%>>& operator>> (
if(o.type != type::ARRAY) { throw type_error(); }
if(o.via.array.size < <%=i+1%>) { throw type_error(); }
<%0.upto(i) {|j|%>
o.via.array.ptr[<%=j%>].convert<A<%=j%>>(&v.template get<<%=j%>>());<%}%>
o.via.array.ptr[<%=j%>].convert<typename type::tuple_type<A<%=j%>>::type>(&v.template get<<%=j%>>());<%}%>
return v;
}
<%}%>
@@ -165,7 +165,42 @@ const packer<Stream>& operator<< (
}
<%}%>
inline void operator<< (
object::with_zone& o,
const type::tuple<>& v) {
o.type = type::ARRAY;
o.via.array.ptr = NULL;
o.via.array.size = 0;
}
<%0.upto(GENERATION_LIMIT) {|i|%>
template <typename A0<%1.upto(i) {|j|%>, typename A<%=j%><%}%>>
inline void operator<< (
object::with_zone& o,
const type::tuple<A0<%1.upto(i) {|j|%>, A<%=j%><%}%>>& v) {
o.type = type::ARRAY;
o.via.array.ptr = (object*)o.zone->malloc(sizeof(object)*<%=i+1%>);
o.via.array.size = <%=i+1%>;
<%0.upto(i) {|j|%>
o.via.array.ptr[<%=j%>] = object(v.template get<<%=j%>>(), o.zone);<%}%>
}
<%}%>
} // namespace msgpack
//inline std::ostream& operator<< (std::ostream& o, const msgpack::type::tuple<>& v) {
// return o << "[]";
//}
//<%0.upto(GENERATION_LIMIT) {|i|%>
//template <typename A0<%1.upto(i) {|j|%>, typename A<%=j%><%}%>>
//inline std::ostream& operator<< (std::ostream& o,
// const msgpack::type::tuple<A0<%1.upto(i) {|j|%>, A<%=j%><%}%>>& v) {
// return o << "["
// <%0.upto(i) {|j|%>
// <<<%if j != 0 then%> ", " <<<%end%> v.template get<<%=j%>>()<%}%>
// << "]";
//}
//<%}%>
#endif /* msgpack/type/tuple.hpp */

View File

@@ -53,6 +53,27 @@ inline packer<Stream>& operator<< (packer<Stream>& o, const std::vector<T>& v)
return o;
}
template <typename T>
inline void operator<< (object::with_zone& o, const std::vector<T>& v)
{
o.type = type::ARRAY;
if(v.empty()) {
o.via.array.ptr = NULL;
o.via.array.size = 0;
} else {
object* p = (object*)o.zone->malloc(sizeof(object)*v.size());
object* const pend = p + v.size();
o.via.array.ptr = p;
o.via.array.size = v.size();
typename std::vector<T>::const_iterator it(v.begin());
do {
*p = object(*it, o.zone);
++p;
++it;
} while(p < pend);
}
}
} // namespace msgpack

260
cpp/src/msgpack/unpack.h Normal file
View File

@@ -0,0 +1,260 @@
/*
* MessagePack for C unpacking routine
*
* Copyright (C) 2008-2009 FURUHASHI Sadayuki
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MSGPACK_UNPACKER_H__
#define MSGPACK_UNPACKER_H__
#include "msgpack/zone.h"
#include "msgpack/object.h"
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup msgpack_unpack Deserializer
* @ingroup msgpack
* @{
*/
typedef struct msgpack_unpacked {
msgpack_zone* zone;
msgpack_object data;
} msgpack_unpacked;
bool msgpack_unpack_next(msgpack_unpacked* result,
const char* data, size_t len, size_t* off);
/** @} */
/**
* @defgroup msgpack_unpacker Streaming deserializer
* @ingroup msgpack
* @{
*/
typedef struct msgpack_unpacker {
char* buffer;
size_t used;
size_t free;
size_t off;
size_t parsed;
msgpack_zone* z;
size_t initial_buffer_size;
void* ctx;
} msgpack_unpacker;
#ifndef MSGPACK_UNPACKER_INIT_BUFFER_SIZE
#define MSGPACK_UNPACKER_INIT_BUFFER_SIZE (64*1024)
#endif
/**
* Initializes a streaming deserializer.
* The initialized deserializer must be destroyed by msgpack_unpacker_destroy(msgpack_unpacker*).
*/
bool msgpack_unpacker_init(msgpack_unpacker* mpac, size_t initial_buffer_size);
/**
* Destroys a streaming deserializer initialized by msgpack_unpacker_init(msgpack_unpacker*, size_t).
*/
void msgpack_unpacker_destroy(msgpack_unpacker* mpac);
/**
* Creates a streaming deserializer.
* The created deserializer must be destroyed by msgpack_unpacker_free(msgpack_unpacker*).
*/
msgpack_unpacker* msgpack_unpacker_new(size_t initial_buffer_size);
/**
* Frees a streaming deserializer created by msgpack_unpacker_new(size_t).
*/
void msgpack_unpacker_free(msgpack_unpacker* mpac);
#ifndef MSGPACK_UNPACKER_RESERVE_SIZE
#define MSGPACK_UNPACKER_RESERVE_SIZE (32*1024)
#endif
/**
* Reserves free space of the internal buffer.
* Use this function to fill the internal buffer with
* msgpack_unpacker_buffer(msgpack_unpacker*),
* msgpack_unpacker_buffer_capacity(const msgpack_unpacker*) and
* msgpack_unpacker_buffer_consumed(msgpack_unpacker*).
*/
static inline bool msgpack_unpacker_reserve_buffer(msgpack_unpacker* mpac, size_t size);
/**
* Gets pointer to the free space of the internal buffer.
* Use this function to fill the internal buffer with
* msgpack_unpacker_reserve_buffer(msgpack_unpacker*, size_t),
* msgpack_unpacker_buffer_capacity(const msgpack_unpacker*) and
* msgpack_unpacker_buffer_consumed(msgpack_unpacker*).
*/
static inline char* msgpack_unpacker_buffer(msgpack_unpacker* mpac);
/**
* Gets size of the free space of the internal buffer.
* Use this function to fill the internal buffer with
* msgpack_unpacker_reserve_buffer(msgpack_unpacker*, size_t),
* msgpack_unpacker_buffer(const msgpack_unpacker*) and
* msgpack_unpacker_buffer_consumed(msgpack_unpacker*).
*/
static inline size_t msgpack_unpacker_buffer_capacity(const msgpack_unpacker* mpac);
/**
* Notifies the deserializer that the internal buffer filled.
* Use this function to fill the internal buffer with
* msgpack_unpacker_reserve_buffer(msgpack_unpacker*, size_t),
* msgpack_unpacker_buffer(msgpack_unpacker*) and
* msgpack_unpacker_buffer_capacity(const msgpack_unpacker*).
*/
static inline void msgpack_unpacker_buffer_consumed(msgpack_unpacker* mpac, size_t size);
/**
* Deserializes one object.
* Returns true if it successes. Otherwise false is returned.
* @param pac pointer to an initialized msgpack_unpacked object.
*/
bool msgpack_unpacker_next(msgpack_unpacker* mpac, msgpack_unpacked* pac);
/**
* Initializes a msgpack_unpacked object.
* The initialized object must be destroyed by msgpack_unpacked_destroy(msgpack_unpacker*).
* Use the object with msgpack_unpacker_next(msgpack_unpacker*, msgpack_unpacked*) or
* msgpack_unpack_next(msgpack_unpacked*, const char*, size_t, size_t*).
*/
static inline void msgpack_unpacked_init(msgpack_unpacked* result);
/**
* Destroys a streaming deserializer initialized by msgpack_unpacked().
*/
static inline void msgpack_unpacked_destroy(msgpack_unpacked* result);
/**
* Releases the memory zone from msgpack_unpacked object.
* The released zone must be freed by msgpack_zone_free(msgpack_zone*).
*/
static inline msgpack_zone* msgpack_unpacked_release_zone(msgpack_unpacked* result);
int msgpack_unpacker_execute(msgpack_unpacker* mpac);
msgpack_object msgpack_unpacker_data(msgpack_unpacker* mpac);
msgpack_zone* msgpack_unpacker_release_zone(msgpack_unpacker* mpac);
void msgpack_unpacker_reset_zone(msgpack_unpacker* mpac);
void msgpack_unpacker_reset(msgpack_unpacker* mpac);
static inline size_t msgpack_unpacker_message_size(const msgpack_unpacker* mpac);
/** @} */
// obsolete
typedef enum {
MSGPACK_UNPACK_SUCCESS = 2,
MSGPACK_UNPACK_EXTRA_BYTES = 1,
MSGPACK_UNPACK_CONTINUE = 0,
MSGPACK_UNPACK_PARSE_ERROR = -1,
} msgpack_unpack_return;
// obsolete
msgpack_unpack_return
msgpack_unpack(const char* data, size_t len, size_t* off,
msgpack_zone* result_zone, msgpack_object* result);
static inline size_t msgpack_unpacker_parsed_size(const msgpack_unpacker* mpac);
bool msgpack_unpacker_flush_zone(msgpack_unpacker* mpac);
bool msgpack_unpacker_expand_buffer(msgpack_unpacker* mpac, size_t size);
bool msgpack_unpacker_reserve_buffer(msgpack_unpacker* mpac, size_t size)
{
if(mpac->free >= size) { return true; }
return msgpack_unpacker_expand_buffer(mpac, size);
}
char* msgpack_unpacker_buffer(msgpack_unpacker* mpac)
{
return mpac->buffer + mpac->used;
}
size_t msgpack_unpacker_buffer_capacity(const msgpack_unpacker* mpac)
{
return mpac->free;
}
void msgpack_unpacker_buffer_consumed(msgpack_unpacker* mpac, size_t size)
{
mpac->used += size;
mpac->free -= size;
}
size_t msgpack_unpacker_message_size(const msgpack_unpacker* mpac)
{
return mpac->parsed - mpac->off + mpac->used;
}
size_t msgpack_unpacker_parsed_size(const msgpack_unpacker* mpac)
{
return mpac->parsed;
}
void msgpack_unpacked_init(msgpack_unpacked* result)
{
memset(result, 0, sizeof(msgpack_unpacked));
}
void msgpack_unpacked_destroy(msgpack_unpacked* result)
{
if(result->zone != NULL) {
msgpack_zone_free(result->zone);
result->zone = NULL;
memset(&result->data, 0, sizeof(msgpack_object));
}
}
msgpack_zone* msgpack_unpacked_release_zone(msgpack_unpacked* result)
{
if(result->zone != NULL) {
msgpack_zone* z = result->zone;
result->zone = NULL;
return z;
}
return NULL;
}
#ifdef __cplusplus
}
#endif
#endif /* msgpack/unpack.h */

View File

@@ -24,8 +24,9 @@
#include <memory>
#include <stdexcept>
// backward compatibility
#ifndef MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE
#define MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE (32*1024)
#define MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE MSGPACK_UNPACKER_INIT_BUFFER_SIZE
#endif
namespace msgpack {
@@ -37,14 +38,39 @@ struct unpack_error : public std::runtime_error {
};
class unpacked {
public:
unpacked() { }
unpacked(object obj, std::auto_ptr<msgpack::zone> z) :
m_obj(obj), m_zone(z) { }
object& get()
{ return m_obj; }
const object& get() const
{ return m_obj; }
std::auto_ptr<msgpack::zone>& zone()
{ return m_zone; }
const std::auto_ptr<msgpack::zone>& zone() const
{ return m_zone; }
private:
object m_obj;
std::auto_ptr<msgpack::zone> m_zone;
};
class unpacker : public msgpack_unpacker {
public:
unpacker(size_t init_buffer_size = MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE);
unpacker(size_t init_buffer_size = MSGPACK_UNPACKER_INIT_BUFFER_SIZE);
~unpacker();
public:
/*! 1. reserve buffer. at least `size' bytes of capacity will be ready */
void reserve_buffer(size_t size);
void reserve_buffer(size_t size = MSGPACK_UNPACKER_RESERVE_SIZE);
/*! 2. read data to the buffer() up to buffer_capacity() bytes */
char* buffer();
@@ -53,39 +79,22 @@ public:
/*! 3. specify the number of bytes actually copied */
void buffer_consumed(size_t size);
/*! 4. repeat execute() until it retunrs false */
bool execute();
/*! 4. repeat next() until it retunrs false */
bool next(unpacked* result);
/*! 5.1. if execute() returns true, take out the parsed object */
object data();
/*! 5.2. the object is valid until the zone is deleted */
// Note that once release_zone() from unpacker, you must delete it
// otherwise the memrory will leak.
zone* release_zone();
/*! 5.2. this method is equivalence to `delete release_zone()` */
void reset_zone();
/*! 5.3. after release_zone(), re-initialize unpacker */
void reset();
/*! 6. check if the size of message doesn't exceed assumption. */
/*! 5. check if the size of message doesn't exceed assumption. */
size_t message_size() const;
// Basic usage of the unpacker is as following:
//
// msgpack::unpacker pac;
//
// while( /* readable */ ) {
// while( /* input is readable */ ) {
//
// // 1.
// pac.reserve(1024);
// pac.reserve_buffer(32*1024);
//
// // 2.
// ssize_t bytes =
// read(the_source, pac.buffer(), pac.buffer_capacity());
// size_t bytes = input.readsome(pac.buffer(), pac.buffer_capacity());
//
// // error handling ...
//
@@ -93,25 +102,40 @@ public:
// pac.buffer_consumed(bytes);
//
// // 4.
// while(pac.execute()) {
// // 5.1
// object o = pac.data();
// msgpack::unpacked result;
// while(pac.next(&result)) {
// // do some with the object with the zone.
// msgpack::object obj = result.get();
// std::auto_ptr<msgpack:zone> z = result.zone();
// on_message(obj, z);
//
// // 5.2
// std::auto_ptr<msgpack::zone> olife( pac.release_zone() );
// //// boost::shared_ptr is also usable:
// // boost::shared_ptr<msgpack::zone> life(z.release());
// // on_message(result.get(), life);
// }
//
// // boost::shared_ptr is also usable:
// // boost::shared_ptr<msgpack::zone> olife( pac.release_zone() );
//
// // 5.3
// pac.reset();
//
// // do some with the object with the old zone.
// do_something(o, olife);
// // 5.
// if(pac.message_size() > 10*1024*1024) {
// throw std::runtime_error("message is too large");
// }
// }
//
/*! for backward compatibility */
bool execute();
/*! for backward compatibility */
object data();
/*! for backward compatibility */
zone* release_zone();
/*! for backward compatibility */
void reset_zone();
/*! for backward compatibility */
void reset();
public:
// These functions are usable when non-MessagePack message follows after
// MessagePack message.
@@ -137,6 +161,11 @@ private:
};
static void unpack(unpacked* result,
const char* data, size_t len, size_t* offset = NULL);
// obsolete
typedef enum {
UNPACK_SUCCESS = 2,
UNPACK_EXTRA_BYTES = 1,
@@ -144,6 +173,7 @@ typedef enum {
UNPACK_PARSE_ERROR = -1,
} unpack_return;
// obsolete
static unpack_return unpack(const char* data, size_t len, size_t* off,
zone* z, object* result);
@@ -187,6 +217,27 @@ inline void unpacker::buffer_consumed(size_t size)
return msgpack_unpacker_buffer_consumed(this, size);
}
inline bool unpacker::next(unpacked* result)
{
int ret = msgpack_unpacker_execute(this);
if(ret < 0) {
throw unpack_error("parse error");
}
if(ret == 0) {
result->zone().reset();
result->get() = object();
return false;
} else {
result->zone().reset( release_zone() );
result->get() = data();
reset();
return true;
}
}
inline bool unpacker::execute()
{
@@ -230,12 +281,12 @@ inline void unpacker::reset()
msgpack_unpacker_reset(this);
}
inline size_t unpacker::message_size() const
{
return msgpack_unpacker_message_size(this);
}
inline size_t unpacker::parsed_size() const
{
return msgpack_unpacker_parsed_size(this);
@@ -262,6 +313,38 @@ inline void unpacker::remove_nonparsed_buffer()
}
inline void unpack(unpacked* result,
const char* data, size_t len, size_t* offset)
{
msgpack::object obj;
std::auto_ptr<msgpack::zone> z(new zone());
unpack_return ret = (unpack_return)msgpack_unpack(
data, len, offset, z.get(),
reinterpret_cast<msgpack_object*>(&obj));
switch(ret) {
case UNPACK_SUCCESS:
result->get() = obj;
result->zone() = z;
return;
case UNPACK_EXTRA_BYTES:
result->get() = obj;
result->zone() = z;
return;
case UNPACK_CONTINUE:
throw unpack_error("insufficient bytes");
case UNPACK_PARSE_ERROR:
default:
throw unpack_error("parse error");
}
}
// obsolete
inline unpack_return unpack(const char* data, size_t len, size_t* off,
zone* z, object* result)
{

View File

@@ -0,0 +1,40 @@
/*
* MessagePack for C version information
*
* Copyright (C) 2008-2009 FURUHASHI Sadayuki
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MSGPACK_VERSION_H__
#define MSGPACK_VERSION_H__
#ifdef __cplusplus
extern "C" {
#endif
const char* msgpack_version(void);
int msgpack_version_major(void);
int msgpack_version_minor(void);
#define MSGPACK_VERSION "@VERSION@"
#define MSGPACK_VERSION_MAJOR @VERSION_MAJOR@
#define MSGPACK_VERSION_MINOR @VERSION_MINOR@
#ifdef __cplusplus
}
#endif
#endif /* msgpack/version.h */

View File

@@ -19,6 +19,7 @@
#define MSGPACK_VREFBUFFER_H__
#include "msgpack/zone.h"
#include <stdlib.h>
#ifndef _WIN32
#include <sys/uio.h>
@@ -29,19 +30,16 @@ struct iovec {
};
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MSGPACK_VREFBUFFER_REF_SIZE
#define MSGPACK_VREFBUFFER_REF_SIZE 32
#endif
#ifndef MSGPACK_VREFBUFFER_CHUNK_SIZE
#define MSGPACK_VREFBUFFER_CHUNK_SIZE 8192
#endif
/**
* @defgroup msgpack_vrefbuffer Vectored Referencing buffer
* @ingroup msgpack_buffer
* @{
*/
struct msgpack_vrefbuffer_chunk;
typedef struct msgpack_vrefbuffer_chunk msgpack_vrefbuffer_chunk;
@@ -64,10 +62,21 @@ typedef struct msgpack_vrefbuffer {
} msgpack_vrefbuffer;
#ifndef MSGPACK_VREFBUFFER_REF_SIZE
#define MSGPACK_VREFBUFFER_REF_SIZE 32
#endif
#ifndef MSGPACK_VREFBUFFER_CHUNK_SIZE
#define MSGPACK_VREFBUFFER_CHUNK_SIZE 8192
#endif
bool msgpack_vrefbuffer_init(msgpack_vrefbuffer* vbuf,
size_t ref_size, size_t chunk_size);
void msgpack_vrefbuffer_destroy(msgpack_vrefbuffer* vbuf);
static inline msgpack_vrefbuffer* msgpack_vrefbuffer_new(size_t ref_size, size_t chunk_size);
static inline void msgpack_vrefbuffer_free(msgpack_vrefbuffer* vbuf);
static inline int msgpack_vrefbuffer_write(void* data, const char* buf, unsigned int len);
static inline const struct iovec* msgpack_vrefbuffer_vec(const msgpack_vrefbuffer* vref);
@@ -81,6 +90,28 @@ int msgpack_vrefbuffer_append_ref(msgpack_vrefbuffer* vbuf,
int msgpack_vrefbuffer_migrate(msgpack_vrefbuffer* vbuf, msgpack_vrefbuffer* to);
void msgpack_vrefbuffer_clear(msgpack_vrefbuffer* vref);
/** @} */
msgpack_vrefbuffer* msgpack_vrefbuffer_new(size_t ref_size, size_t chunk_size)
{
msgpack_vrefbuffer* vbuf = (msgpack_vrefbuffer*)malloc(sizeof(msgpack_vrefbuffer));
if(!msgpack_vrefbuffer_init(vbuf, ref_size, chunk_size)) {
free(vbuf);
return NULL;
}
return vbuf;
}
void msgpack_vrefbuffer_free(msgpack_vrefbuffer* vbuf)
{
if(vbuf == NULL) { return; }
msgpack_vrefbuffer_destroy(vbuf);
free(vbuf);
}
int msgpack_vrefbuffer_write(void* data, const char* buf, unsigned int len)
{
msgpack_vrefbuffer* vbuf = (msgpack_vrefbuffer*)data;
@@ -102,6 +133,7 @@ size_t msgpack_vrefbuffer_veclen(const msgpack_vrefbuffer* vref)
return vref->tail - vref->array;
}
#ifdef __cplusplus
}
#endif

View File

@@ -78,6 +78,11 @@ public:
}
}
void clear()
{
msgpack_vrefbuffer_clear(this);
}
private:
typedef msgpack_vrefbuffer base;

207
cpp/src/msgpack/zbuffer.h Normal file
View File

@@ -0,0 +1,207 @@
/*
* MessagePack for C deflate buffer implementation
*
* Copyright (C) 2010 FURUHASHI Sadayuki
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MSGPACK_ZBUFFER_H__
#define MSGPACK_ZBUFFER_H__
#include "msgpack/sysdep.h"
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup msgpack_zbuffer Compressed buffer
* @ingroup msgpack_buffer
* @{
*/
typedef struct msgpack_zbuffer {
z_stream stream;
char* data;
size_t init_size;
} msgpack_zbuffer;
#ifndef MSGPACK_ZBUFFER_INIT_SIZE
#define MSGPACK_ZBUFFER_INIT_SIZE 8192
#endif
static inline bool msgpack_zbuffer_init(msgpack_zbuffer* zbuf,
int level, size_t init_size);
static inline void msgpack_zbuffer_destroy(msgpack_zbuffer* zbuf);
static inline msgpack_zbuffer* msgpack_zbuffer_new(int level, size_t init_size);
static inline void msgpack_zbuffer_free(msgpack_zbuffer* zbuf);
static inline char* msgpack_zbuffer_flush(msgpack_zbuffer* zbuf);
static inline const char* msgpack_zbuffer_data(const msgpack_zbuffer* zbuf);
static inline size_t msgpack_zbuffer_size(const msgpack_zbuffer* zbuf);
static inline bool msgpack_zbuffer_reset(msgpack_zbuffer* zbuf);
static inline void msgpack_zbuffer_reset_buffer(msgpack_zbuffer* zbuf);
static inline char* msgpack_zbuffer_release_buffer(msgpack_zbuffer* zbuf);
#ifndef MSGPACK_ZBUFFER_RESERVE_SIZE
#define MSGPACK_ZBUFFER_RESERVE_SIZE 512
#endif
static inline int msgpack_zbuffer_write(void* data, const char* buf, unsigned int len);
static inline bool msgpack_zbuffer_expand(msgpack_zbuffer* zbuf);
bool msgpack_zbuffer_init(msgpack_zbuffer* zbuf,
int level, size_t init_size)
{
memset(zbuf, 0, sizeof(msgpack_zbuffer));
zbuf->init_size = init_size;
if(deflateInit(&zbuf->stream, level) != Z_OK) {
free(zbuf->data);
return false;
}
return true;
}
void msgpack_zbuffer_destroy(msgpack_zbuffer* zbuf)
{
deflateEnd(&zbuf->stream);
free(zbuf->data);
}
msgpack_zbuffer* msgpack_zbuffer_new(int level, size_t init_size)
{
msgpack_zbuffer* zbuf = (msgpack_zbuffer*)malloc(sizeof(msgpack_zbuffer));
if(!msgpack_zbuffer_init(zbuf, level, init_size)) {
free(zbuf);
return NULL;
}
return zbuf;
}
void msgpack_zbuffer_free(msgpack_zbuffer* zbuf)
{
if(zbuf == NULL) { return; }
msgpack_zbuffer_destroy(zbuf);
free(zbuf);
}
bool msgpack_zbuffer_expand(msgpack_zbuffer* zbuf)
{
size_t used = (char*)zbuf->stream.next_out - zbuf->data;
size_t csize = used + zbuf->stream.avail_out;
size_t nsize = (csize == 0) ? zbuf->init_size : csize * 2;
char* tmp = (char*)realloc(zbuf->data, nsize);
if(tmp == NULL) {
return false;
}
zbuf->data = tmp;
zbuf->stream.next_out = (Bytef*)(tmp + used);
zbuf->stream.avail_out = nsize - used;
return true;
}
int msgpack_zbuffer_write(void* data, const char* buf, unsigned int len)
{
msgpack_zbuffer* zbuf = (msgpack_zbuffer*)data;
zbuf->stream.next_in = (Bytef*)buf;
zbuf->stream.avail_in = len;
do {
if(zbuf->stream.avail_out < MSGPACK_ZBUFFER_RESERVE_SIZE) {
if(!msgpack_zbuffer_expand(zbuf)) {
return -1;
}
}
if(deflate(&zbuf->stream, Z_NO_FLUSH) != Z_OK) {
return -1;
}
} while(zbuf->stream.avail_in > 0);
return 0;
}
char* msgpack_zbuffer_flush(msgpack_zbuffer* zbuf)
{
while(true) {
switch(deflate(&zbuf->stream, Z_FINISH)) {
case Z_STREAM_END:
return zbuf->data;
case Z_OK:
if(!msgpack_zbuffer_expand(zbuf)) {
return NULL;
}
break;
default:
return NULL;
}
}
}
const char* msgpack_zbuffer_data(const msgpack_zbuffer* zbuf)
{
return zbuf->data;
}
size_t msgpack_zbuffer_size(const msgpack_zbuffer* zbuf)
{
return (char*)zbuf->stream.next_out - zbuf->data;
}
void msgpack_zbuffer_reset_buffer(msgpack_zbuffer* zbuf)
{
zbuf->stream.avail_out += (char*)zbuf->stream.next_out - zbuf->data;
zbuf->stream.next_out = (Bytef*)zbuf->data;
}
bool msgpack_zbuffer_reset(msgpack_zbuffer* zbuf)
{
if(deflateReset(&zbuf->stream) != Z_OK) {
return false;
}
msgpack_zbuffer_reset_buffer(zbuf);
return true;
}
char* msgpack_zbuffer_release_buffer(msgpack_zbuffer* zbuf)
{
char* tmp = zbuf->data;
zbuf->data = NULL;
zbuf->stream.next_out = NULL;
zbuf->stream.avail_out = 0;
return tmp;
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* msgpack/zbuffer.h */

100
cpp/src/msgpack/zbuffer.hpp Normal file
View File

@@ -0,0 +1,100 @@
//
// MessagePack for C++ deflate buffer implementation
//
// Copyright (C) 2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef MSGPACK_ZBUFFER_HPP__
#define MSGPACK_ZBUFFER_HPP__
#include "msgpack/zbuffer.h"
#include <stdexcept>
namespace msgpack {
class zbuffer : public msgpack_zbuffer {
public:
zbuffer(int level = Z_DEFAULT_COMPRESSION,
size_t init_size = MSGPACK_ZBUFFER_INIT_SIZE)
{
msgpack_zbuffer_init(this, level, init_size);
}
~zbuffer()
{
msgpack_zbuffer_destroy(this);
}
public:
void write(const char* buf, unsigned int len)
{
if(msgpack_zbuffer_write(this, buf, len) < 0) {
throw std::bad_alloc();
}
}
char* flush()
{
char* buf = msgpack_zbuffer_flush(this);
if(!buf) {
throw std::bad_alloc();
}
return buf;
}
char* data()
{
return base::data;
}
const char* data() const
{
return base::data;
}
size_t size() const
{
return msgpack_zbuffer_size(this);
}
void reset()
{
if(!msgpack_zbuffer_reset(this)) {
throw std::bad_alloc();
}
}
void reset_buffer()
{
msgpack_zbuffer_reset_buffer(this);
}
char* release_buffer()
{
return msgpack_zbuffer_release_buffer(this);
}
private:
typedef msgpack_zbuffer base;
private:
zbuffer(const zbuffer&);
};
} // namespace msgpack
#endif /* msgpack/zbuffer.hpp */

View File

@@ -25,6 +25,12 @@ extern "C" {
#endif
/**
* @defgroup msgpack_zone Memory zone
* @ingroup msgpack
* @{
*/
typedef struct msgpack_zone_finalizer {
void (*func)(void* data);
void* data;
@@ -71,6 +77,7 @@ bool msgpack_zone_is_empty(msgpack_zone* zone);
void msgpack_zone_clear(msgpack_zone* zone);
/** @} */
#ifndef MSGPACK_ZONE_ALIGN

View File

@@ -18,7 +18,6 @@
#ifndef MSGPACK_ZONE_HPP__
#define MSGPACK_ZONE_HPP__
#include "msgpack/object.hpp"
#include "msgpack/zone.h"
#include <cstdlib>
#include <memory>

View File

@@ -16,7 +16,6 @@
// limitations under the License.
//
#include "msgpack/object.hpp"
#include <string.h>
namespace msgpack {
@@ -61,7 +60,6 @@ std::ostream& operator<< (std::ostream& s, const object o)
}
s << "]";
break;
// FIXME loop optimiziation
case type::MAP:
s << "{";
@@ -76,7 +74,6 @@ std::ostream& operator<< (std::ostream& s, const object o)
}
s << "}";
break;
// FIXME loop optimiziation
default:
// FIXME
@@ -86,53 +83,5 @@ std::ostream& operator<< (std::ostream& s, const object o)
}
bool operator==(const object x, const object y)
{
if(x.type != y.type) { return false; }
switch(x.type) {
case type::NIL:
return true;
case type::BOOLEAN:
return x.via.boolean == y.via.boolean;
case type::POSITIVE_INTEGER:
return x.via.u64 == y.via.u64;
case type::NEGATIVE_INTEGER:
return x.via.i64 == y.via.i64;
case type::RAW:
return x.via.raw.size == y.via.raw.size &&
memcmp(x.via.raw.ptr, y.via.raw.ptr, x.via.raw.size) == 0;
case type::ARRAY:
if(x.via.array.size != y.via.array.size) { return false; }
for(object* px(x.via.array.ptr),
* const pxend(x.via.array.ptr + x.via.array.size),
* py(y.via.array.ptr);
px < pxend; ++px, ++py) {
if(*px != *py) { return false; }
}
return true;
// FIXME loop optimiziation
case type::MAP:
if(x.via.map.size != y.via.map.size) { return false; }
for(object_kv* px(x.via.map.ptr),
* const pxend(x.via.map.ptr + x.via.map.size),
* py(y.via.map.ptr);
px < pxend; ++px, ++py) {
if(px->key != py->key || px->val != py->val) { return false; }
}
return true;
default:
return false;
}
}
} // namespace msgpack

View File

@@ -18,6 +18,7 @@
#include "msgpack/object.h"
#include "msgpack/pack.h"
#include <stdio.h>
#include <string.h>
#ifndef _MSC_VER
#include <inttypes.h>
@@ -141,7 +142,6 @@ void msgpack_object_print(FILE* out, msgpack_object o)
}
fprintf(out, "]");
break;
// FIXME loop optimiziation
case MSGPACK_OBJECT_MAP:
fprintf(out, "{");
@@ -161,7 +161,6 @@ void msgpack_object_print(FILE* out, msgpack_object o)
}
fprintf(out, "}");
break;
// FIXME loop optimiziation
default:
// FIXME
@@ -169,3 +168,70 @@ void msgpack_object_print(FILE* out, msgpack_object o)
}
}
bool msgpack_object_equal(const msgpack_object x, const msgpack_object y)
{
if(x.type != y.type) { return false; }
switch(x.type) {
case MSGPACK_OBJECT_NIL:
return true;
case MSGPACK_OBJECT_BOOLEAN:
return x.via.boolean == y.via.boolean;
case MSGPACK_OBJECT_POSITIVE_INTEGER:
return x.via.u64 == y.via.u64;
case MSGPACK_OBJECT_NEGATIVE_INTEGER:
return x.via.i64 == y.via.i64;
case MSGPACK_OBJECT_DOUBLE:
return x.via.dec == y.via.dec;
case MSGPACK_OBJECT_RAW:
return x.via.raw.size == y.via.raw.size &&
memcmp(x.via.raw.ptr, y.via.raw.ptr, x.via.raw.size) == 0;
case MSGPACK_OBJECT_ARRAY:
if(x.via.array.size != y.via.array.size) {
return false;
} else if(x.via.array.size == 0) {
return true;
} else {
msgpack_object* px = x.via.array.ptr;
msgpack_object* const pxend = x.via.array.ptr + x.via.array.size;
msgpack_object* py = y.via.array.ptr;
do {
if(!msgpack_object_equal(*px, *py)) {
return false;
}
++px;
++py;
} while(px < pxend);
return true;
}
case MSGPACK_OBJECT_MAP:
if(x.via.map.size != y.via.map.size) {
return false;
} else if(x.via.map.size == 0) {
return true;
} else {
msgpack_object_kv* px = x.via.map.ptr;
msgpack_object_kv* const pxend = x.via.map.ptr + x.via.map.size;
msgpack_object_kv* py = y.via.map.ptr;
do {
if(!msgpack_object_equal(px->key, py->key) || !msgpack_object_equal(px->val, py->val)) {
return false;
}
++px;
++py;
} while(px < pxend);
return true;
}
default:
return false;
}
}

View File

@@ -323,7 +323,7 @@ msgpack_object msgpack_unpacker_data(msgpack_unpacker* mpac)
msgpack_zone* msgpack_unpacker_release_zone(msgpack_unpacker* mpac)
{
if(!msgpack_unpacker_flush_zone(mpac)) {
return false;
return NULL;
}
msgpack_zone* r = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
@@ -363,28 +363,54 @@ void msgpack_unpacker_reset(msgpack_unpacker* mpac)
mpac->parsed = 0;
}
bool msgpack_unpacker_next(msgpack_unpacker* mpac, msgpack_unpacked* result)
{
if(result->zone != NULL) {
msgpack_zone_free(result->zone);
}
int ret = msgpack_unpacker_execute(mpac);
if(ret <= 0) {
result->zone = NULL;
memset(&result->data, 0, sizeof(msgpack_object));
return false;
}
result->zone = msgpack_unpacker_release_zone(mpac);
result->data = msgpack_unpacker_data(mpac);
msgpack_unpacker_reset(mpac);
return true;
}
msgpack_unpack_return
msgpack_unpack(const char* data, size_t len, size_t* off,
msgpack_zone* z, msgpack_object* result)
msgpack_zone* result_zone, msgpack_object* result)
{
template_context ctx;
template_init(&ctx);
ctx.user.z = z;
ctx.user.referenced = false;
size_t noff = 0;
if(off != NULL) { noff = *off; }
int ret = template_execute(&ctx, data, len, &noff);
if(ret < 0) {
if(len <= noff) {
// FIXME
return MSGPACK_UNPACK_CONTINUE;
}
template_context ctx;
template_init(&ctx);
ctx.user.z = result_zone;
ctx.user.referenced = false;
int e = template_execute(&ctx, data, len, &noff);
if(e < 0) {
return MSGPACK_UNPACK_PARSE_ERROR;
}
if(off != NULL) { *off = noff; }
if(ret == 0) {
if(e == 0) {
return MSGPACK_UNPACK_CONTINUE;
}
@@ -397,3 +423,37 @@ msgpack_unpack(const char* data, size_t len, size_t* off,
return MSGPACK_UNPACK_SUCCESS;
}
bool msgpack_unpack_next(msgpack_unpacked* result,
const char* data, size_t len, size_t* off)
{
msgpack_unpacked_destroy(result);
size_t noff = 0;
if(off != NULL) { noff = *off; }
if(len <= noff) {
return false;
}
msgpack_zone* z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
template_context ctx;
template_init(&ctx);
ctx.user.z = z;
ctx.user.referenced = false;
int e = template_execute(&ctx, data, len, &noff);
if(e <= 0) {
msgpack_zone_free(z);
return false;
}
if(off != NULL) { *off = noff; }
result->zone = z;
result->data = template_data(&ctx);
return true;
}

17
cpp/src/version.c Normal file
View File

@@ -0,0 +1,17 @@
#include "msgpack.h"
const char* msgpack_version(void)
{
return MSGPACK_VERSION;
}
int msgpack_version_major(void)
{
return MSGPACK_VERSION_MAJOR;
}
int msgpack_version_minor(void)
{
return MSGPACK_VERSION_MINOR;
}

View File

@@ -75,6 +75,25 @@ void msgpack_vrefbuffer_destroy(msgpack_vrefbuffer* vbuf)
free(vbuf->array);
}
void msgpack_vrefbuffer_clear(msgpack_vrefbuffer* vbuf)
{
msgpack_vrefbuffer_chunk* c = vbuf->inner_buffer.head->next;
msgpack_vrefbuffer_chunk* n;
while(c != NULL) {
n = c->next;
free(c);
c = n;
}
msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer;
msgpack_vrefbuffer_chunk* chunk = ib->head;
chunk->next = NULL;
ib->free = vbuf->chunk_size;
ib->ptr = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk);
vbuf->tail = vbuf->array;
}
int msgpack_vrefbuffer_append_ref(msgpack_vrefbuffer* vbuf,
const char* buf, unsigned int len)
{

View File

@@ -204,7 +204,7 @@ msgpack_zone* msgpack_zone_new(size_t chunk_size)
if(!init_chunk_list(&zone->chunk_list, chunk_size)) {
free(zone);
return false;
return NULL;
}
init_finalizer_array(&zone->finalizer_array);
@@ -214,6 +214,7 @@ msgpack_zone* msgpack_zone_new(size_t chunk_size)
void msgpack_zone_free(msgpack_zone* zone)
{
if(zone == NULL) { return; }
msgpack_zone_destroy(zone);
free(zone);
}

View File

@@ -1,9 +0,0 @@
CXXFLAGS += -Wall -g -I. -I.. -O4
LDFLAGS +=
all: test
test: test.o unpack.o zone.o object.o pack.hpp unpack.hpp zone.hpp object.hpp
$(CXX) test.o unpack.o zone.o object.o $(CXXFLAGS) $(LDFLAGS) -o $@

48
cpp/test/Makefile.am Normal file
View File

@@ -0,0 +1,48 @@
AM_CPPFLAGS = -I../src
AM_C_CPPFLAGS = -I../src
AM_LDFLAGS = ../src/libmsgpack.la -lgtest_main
check_PROGRAMS = \
zone \
pack_unpack \
pack_unpack_c \
streaming \
streaming_c \
object \
convert \
buffer \
cases \
version \
msgpackc_test \
msgpack_test
TESTS = $(check_PROGRAMS)
zone_SOURCES = zone.cc
pack_unpack_SOURCES = pack_unpack.cc
pack_unpack_c_SOURCES = pack_unpack_c.cc
streaming_SOURCES = streaming.cc
streaming_c_SOURCES = streaming_c.cc
object_SOURCES = object.cc
convert_SOURCES = convert.cc
buffer_SOURCES = buffer.cc
buffer_LDADD = -lz
cases_SOURCES = cases.cc
version_SOURCES = version.cc
msgpackc_test_SOURCES = msgpackc_test.cpp
msgpack_test_SOURCES = msgpack_test.cpp
EXTRA_DIST = cases.mpac cases_compact.mpac

75
cpp/test/buffer.cc Normal file
View File

@@ -0,0 +1,75 @@
#include <msgpack.hpp>
#include <msgpack/zbuffer.hpp>
#include <gtest/gtest.h>
#include <string.h>
TEST(buffer, sbuffer)
{
msgpack::sbuffer sbuf;
sbuf.write("a", 1);
sbuf.write("a", 1);
sbuf.write("a", 1);
EXPECT_EQ(3, sbuf.size());
EXPECT_TRUE( memcmp(sbuf.data(), "aaa", 3) == 0 );
sbuf.clear();
sbuf.write("a", 1);
sbuf.write("a", 1);
sbuf.write("a", 1);
EXPECT_EQ(3, sbuf.size());
EXPECT_TRUE( memcmp(sbuf.data(), "aaa", 3) == 0 );
}
TEST(buffer, vrefbuffer)
{
msgpack::vrefbuffer vbuf;
vbuf.write("a", 1);
vbuf.write("a", 1);
vbuf.write("a", 1);
const struct iovec* vec = vbuf.vector();
size_t veclen = vbuf.vector_size();
msgpack::sbuffer sbuf;
for(size_t i=0; i < veclen; ++i) {
sbuf.write((const char*)vec[i].iov_base, vec[i].iov_len);
}
EXPECT_EQ(3, sbuf.size());
EXPECT_TRUE( memcmp(sbuf.data(), "aaa", 3) == 0 );
vbuf.clear();
vbuf.write("a", 1);
vbuf.write("a", 1);
vbuf.write("a", 1);
vec = vbuf.vector();
veclen = vbuf.vector_size();
sbuf.clear();
for(size_t i=0; i < veclen; ++i) {
sbuf.write((const char*)vec[i].iov_base, vec[i].iov_len);
}
EXPECT_EQ(3, sbuf.size());
EXPECT_TRUE( memcmp(sbuf.data(), "aaa", 3) == 0 );
}
TEST(buffer, zbuffer)
{
msgpack::zbuffer zbuf;
zbuf.write("a", 1);
zbuf.write("a", 1);
zbuf.write("a", 1);
zbuf.flush();
char* data = zbuf.data();
size_t size = zbuf.size();
}

36
cpp/test/cases.cc Normal file
View File

@@ -0,0 +1,36 @@
#include <msgpack.hpp>
#include <fstream>
#include <gtest/gtest.h>
static void feed_file(msgpack::unpacker& pac, const char* path)
{
std::ifstream fin(path);
while(true) {
pac.reserve_buffer(32*1024);
fin.read(pac.buffer(), pac.buffer_capacity());
if(fin.bad()) {
throw std::runtime_error("read failed");
}
pac.buffer_consumed(fin.gcount());
if(fin.fail()) {
break;
}
}
}
TEST(cases, format)
{
msgpack::unpacker pac;
msgpack::unpacker pac_compact;
feed_file(pac, "cases.mpac");
feed_file(pac_compact, "cases_compact.mpac");
msgpack::unpacked result;
while(pac.next(&result)) {
msgpack::unpacked result_compact;
EXPECT_TRUE( pac_compact.next(&result_compact) );
EXPECT_EQ(result_compact.get(), result.get());
}
}

74
cpp/test/convert.cc Normal file
View File

@@ -0,0 +1,74 @@
#include <msgpack.hpp>
#include <gtest/gtest.h>
class compatibility {
public:
compatibility() : str1("default"), str2("default") { }
std::string str1;
std::string str2;
MSGPACK_DEFINE(str1, str2);
};
TEST(convert, compatibility_less)
{
std::vector<std::string> src(1);
src[0] = "kumofs";
msgpack::zone z;
msgpack::object obj(src, &z);
compatibility c;
EXPECT_NO_THROW( obj.convert(&c) );
EXPECT_EQ("kumofs", c.str1);
EXPECT_EQ("default", c.str2);
}
TEST(convert, compatibility_more)
{
std::vector<std::string> src(3);
src[0] = "kumofs";
src[1] = "mpio";
src[2] = "cloudy";
msgpack::zone z;
msgpack::object obj(src, &z);
compatibility to;
EXPECT_NO_THROW( obj.convert(&to) );
EXPECT_EQ("kumofs", to.str1);
EXPECT_EQ("mpio", to.str2);
}
class enum_member {
public:
enum_member() : flag(A) { }
enum flags_t {
A = 0,
B = 1,
};
flags_t flag;
MSGPACK_DEFINE((int&)flag);
};
TEST(convert, enum_member)
{
enum_member src;
src.flag = enum_member::B;
msgpack::zone z;
msgpack::object obj(src, &z);
enum_member to;
EXPECT_NO_THROW( obj.convert(&to) );
EXPECT_EQ(enum_member::B, to.flag);
}

View File

@@ -438,7 +438,7 @@ TEST(MSGPACK_STL, simple_buffer_multiset)
#ifdef HAVE_TR1_UNORDERED_MAP
#include <tr1/unordered_map>
#include "cpp/msgpack/type/tr1/unordered_map.hpp"
#include "msgpack/type/tr1/unordered_map.hpp"
TEST(MSGPACK_TR1, simple_buffer_unordered_map)
{
for (unsigned int k = 0; k < kLoop; k++) {
@@ -499,7 +499,7 @@ TEST(MSGPACK_TR1, simple_buffer_unordered_multimap)
#ifdef HAVE_TR1_UNORDERED_SET
#include <tr1/unordered_set>
#include "cpp/msgpack/type/tr1/unordered_set.hpp"
#include "msgpack/type/tr1/unordered_set.hpp"
TEST(MSGPACK_TR1, simple_buffer_unordered_set)
{
for (unsigned int k = 0; k < kLoop; k++) {

134
cpp/test/object.cc Normal file
View File

@@ -0,0 +1,134 @@
#include <msgpack.hpp>
#include <gtest/gtest.h>
struct myclass {
myclass() : num(0), str("default") { }
myclass(int num, const std::string& str) :
num(0), str("default") { }
~myclass() { }
int num;
std::string str;
MSGPACK_DEFINE(num, str);
bool operator==(const myclass& o) const
{
return num == o.num && str == o.str;
}
};
std::ostream& operator<<(std::ostream& o, const myclass& m)
{
return o << "myclass("<<m.num<<",\""<<m.str<<"\")";
}
TEST(object, convert)
{
myclass m1;
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, m1);
msgpack::zone z;
msgpack::object obj;
msgpack::unpack_return ret =
msgpack::unpack(sbuf.data(), sbuf.size(), NULL, &z, &obj);
EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS);
myclass m2;
obj.convert(&m2);
EXPECT_EQ(m1, m2);
}
TEST(object, as)
{
myclass m1;
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, m1);
msgpack::zone z;
msgpack::object obj;
msgpack::unpack_return ret =
msgpack::unpack(sbuf.data(), sbuf.size(), NULL, &z, &obj);
EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS);
EXPECT_EQ(m1, obj.as<myclass>());
}
TEST(object, print)
{
msgpack::object obj;
std::cout << obj << std::endl;
}
TEST(object, is_nil)
{
msgpack::object obj;
EXPECT_TRUE(obj.is_nil());
}
TEST(object, type_error)
{
msgpack::object obj(1);
EXPECT_THROW(obj.as<std::string>(), msgpack::type_error);
EXPECT_THROW(obj.as<std::vector<int> >(), msgpack::type_error);
EXPECT_EQ(1, obj.as<int>());
EXPECT_EQ(1, obj.as<short>());
EXPECT_EQ(1u, obj.as<unsigned int>());
EXPECT_EQ(1u, obj.as<unsigned long>());
}
TEST(object, equal_primitive)
{
msgpack::object obj_nil;
EXPECT_EQ(obj_nil, msgpack::object());
msgpack::object obj_int(1);
EXPECT_EQ(obj_int, msgpack::object(1));
EXPECT_EQ(obj_int, 1);
msgpack::object obj_double(1.2);
EXPECT_EQ(obj_double, msgpack::object(1.2));
EXPECT_EQ(obj_double, 1.2);
msgpack::object obj_bool(true);
EXPECT_EQ(obj_bool, msgpack::object(true));
EXPECT_EQ(obj_bool, true);
}
TEST(object, construct_primitive)
{
msgpack::object obj_nil;
EXPECT_EQ(msgpack::type::NIL, obj_nil.type);
msgpack::object obj_uint(1);
EXPECT_EQ(msgpack::type::POSITIVE_INTEGER, obj_uint.type);
EXPECT_EQ(1u, obj_uint.via.u64);
msgpack::object obj_int(-1);
EXPECT_EQ(msgpack::type::NEGATIVE_INTEGER, obj_int.type);
EXPECT_EQ(-1, obj_int.via.i64);
msgpack::object obj_double(1.2);
EXPECT_EQ(msgpack::type::DOUBLE, obj_double.type);
EXPECT_EQ(1.2, obj_double.via.dec);
msgpack::object obj_bool(true);
EXPECT_EQ(msgpack::type::BOOLEAN, obj_bool.type);
EXPECT_EQ(true, obj_bool.via.boolean);
}

123
cpp/test/pack_unpack.cc Normal file
View File

@@ -0,0 +1,123 @@
#include <msgpack.hpp>
#include <gtest/gtest.h>
#include <sstream>
TEST(pack, num)
{
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, 1);
}
TEST(pack, vector)
{
msgpack::sbuffer sbuf;
std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
msgpack::pack(sbuf, vec);
}
TEST(pack, to_ostream)
{
std::ostringstream stream;
msgpack::pack(stream, 1);
}
struct myclass {
myclass() : num(0), str("default") { }
myclass(int num, const std::string& str) :
num(0), str("default") { }
~myclass() { }
int num;
std::string str;
MSGPACK_DEFINE(num, str);
};
TEST(pack, myclass)
{
msgpack::sbuffer sbuf;
myclass m(1, "msgpack");
msgpack::pack(sbuf, m);
}
TEST(unpack, myclass)
{
msgpack::sbuffer sbuf;
myclass m1(1, "phraser");
msgpack::pack(sbuf, m1);
msgpack::zone z;
msgpack::object obj;
msgpack::unpack_return ret =
msgpack::unpack(sbuf.data(), sbuf.size(), NULL, &z, &obj);
EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS);
myclass m2 = obj.as<myclass>();
EXPECT_EQ(m1.num, m2.num);
EXPECT_EQ(m1.str, m2.str);
}
TEST(unpack, sequence)
{
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, 1);
msgpack::pack(sbuf, 2);
msgpack::pack(sbuf, 3);
size_t offset = 0;
msgpack::unpacked msg;
msgpack::unpack(&msg, sbuf.data(), sbuf.size(), &offset);
EXPECT_EQ(1, msg.get().as<int>());
msgpack::unpack(&msg, sbuf.data(), sbuf.size(), &offset);
EXPECT_EQ(2, msg.get().as<int>());
msgpack::unpack(&msg, sbuf.data(), sbuf.size(), &offset);
EXPECT_EQ(3, msg.get().as<int>());
}
TEST(unpack, sequence_compat)
{
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, 1);
msgpack::pack(sbuf, 2);
msgpack::pack(sbuf, 3);
size_t offset = 0;
msgpack::zone z;
msgpack::object obj;
msgpack::unpack_return ret;
ret = msgpack::unpack(sbuf.data(), sbuf.size(), &offset, &z, &obj);
EXPECT_TRUE(ret >= 0);
EXPECT_EQ(ret, msgpack::UNPACK_EXTRA_BYTES);
EXPECT_EQ(1, obj.as<int>());
ret = msgpack::unpack(sbuf.data(), sbuf.size(), &offset, &z, &obj);
EXPECT_TRUE(ret >= 0);
EXPECT_EQ(ret, msgpack::UNPACK_EXTRA_BYTES);
EXPECT_EQ(2, obj.as<int>());
ret = msgpack::unpack(sbuf.data(), sbuf.size(), &offset, &z, &obj);
EXPECT_TRUE(ret >= 0);
EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS);
EXPECT_EQ(3, obj.as<int>());
}

70
cpp/test/pack_unpack_c.cc Normal file
View File

@@ -0,0 +1,70 @@
#include <msgpack.h>
#include <gtest/gtest.h>
#include <stdio.h>
TEST(pack, num)
{
msgpack_sbuffer* sbuf = msgpack_sbuffer_new();
msgpack_packer* pk = msgpack_packer_new(sbuf, msgpack_sbuffer_write);
EXPECT_EQ(0, msgpack_pack_int(pk, 1));
msgpack_sbuffer_free(sbuf);
msgpack_packer_free(pk);
}
TEST(pack, array)
{
msgpack_sbuffer* sbuf = msgpack_sbuffer_new();
msgpack_packer* pk = msgpack_packer_new(sbuf, msgpack_sbuffer_write);
EXPECT_EQ(0, msgpack_pack_array(pk, 3));
EXPECT_EQ(0, msgpack_pack_int(pk, 1));
EXPECT_EQ(0, msgpack_pack_int(pk, 2));
EXPECT_EQ(0, msgpack_pack_int(pk, 3));
msgpack_sbuffer_free(sbuf);
msgpack_packer_free(pk);
}
TEST(unpack, sequence)
{
msgpack_sbuffer* sbuf = msgpack_sbuffer_new();
msgpack_packer* pk = msgpack_packer_new(sbuf, msgpack_sbuffer_write);
EXPECT_EQ(0, msgpack_pack_int(pk, 1));
EXPECT_EQ(0, msgpack_pack_int(pk, 2));
EXPECT_EQ(0, msgpack_pack_int(pk, 3));
msgpack_packer_free(pk);
bool success;
size_t offset = 0;
msgpack_unpacked msg;
msgpack_unpacked_init(&msg);
success = msgpack_unpack_next(&msg, sbuf->data, sbuf->size, &offset);
EXPECT_TRUE(success);
EXPECT_EQ(MSGPACK_OBJECT_POSITIVE_INTEGER, msg.data.type);
EXPECT_EQ(1, msg.data.via.u64);
success = msgpack_unpack_next(&msg, sbuf->data, sbuf->size, &offset);
EXPECT_TRUE(success);
EXPECT_EQ(MSGPACK_OBJECT_POSITIVE_INTEGER, msg.data.type);
EXPECT_EQ(2, msg.data.via.u64);
success = msgpack_unpack_next(&msg, sbuf->data, sbuf->size, &offset);
EXPECT_TRUE(success);
EXPECT_EQ(MSGPACK_OBJECT_POSITIVE_INTEGER, msg.data.type);
EXPECT_EQ(3, msg.data.via.u64);
success = msgpack_unpack_next(&msg, sbuf->data, sbuf->size, &offset);
EXPECT_FALSE(success);
msgpack_sbuffer_free(sbuf);
msgpack_unpacked_destroy(&msg);
}

220
cpp/test/streaming.cc Normal file
View File

@@ -0,0 +1,220 @@
#include <msgpack.hpp>
#include <gtest/gtest.h>
#include <sstream>
TEST(streaming, basic)
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack(1);
pk.pack(2);
pk.pack(3);
const char* input = buffer.data();
const char* const eof = input + buffer.size();
msgpack::unpacker pac;
msgpack::unpacked result;
int count = 0;
while(count < 3) {
pac.reserve_buffer(32*1024);
// read buffer into pac.buffer() upto
// pac.buffer_capacity() bytes.
size_t len = 1;
memcpy(pac.buffer(), input, len);
input += len;
pac.buffer_consumed(len);
while(pac.next(&result)) {
msgpack::object obj = result.get();
switch(count++) {
case 0:
EXPECT_EQ(1, obj.as<int>());
break;
case 1:
EXPECT_EQ(2, obj.as<int>());
break;
case 2:
EXPECT_EQ(3, obj.as<int>());
return;
}
}
EXPECT_TRUE(input < eof);
}
}
class event_handler {
public:
event_handler(std::istream& input) : input(input) { }
~event_handler() { }
void on_read()
{
while(true) {
pac.reserve_buffer(32*1024);
size_t len = input.readsome(pac.buffer(), pac.buffer_capacity());
if(len == 0) {
return;
}
pac.buffer_consumed(len);
msgpack::unpacked result;
while(pac.next(&result)) {
on_message(result.get(), result.zone());
}
if(pac.message_size() > 10*1024*1024) {
throw std::runtime_error("message is too large");
}
}
}
void on_message(msgpack::object obj, std::auto_ptr<msgpack::zone> z)
{
EXPECT_EQ(expect, obj.as<int>());
}
int expect;
private:
std::istream& input;
msgpack::unpacker pac;
};
TEST(streaming, event)
{
std::stringstream stream;
msgpack::packer<std::ostream> pk(&stream);
event_handler handler(stream);
pk.pack(1);
handler.expect = 1;
handler.on_read();
pk.pack(2);
handler.expect = 2;
handler.on_read();
pk.pack(3);
handler.expect = 3;
handler.on_read();
}
// backward compatibility
TEST(streaming, basic_compat)
{
std::ostringstream stream;
msgpack::packer<std::ostream> pk(&stream);
pk.pack(1);
pk.pack(2);
pk.pack(3);
std::istringstream input(stream.str());
msgpack::unpacker pac;
int count = 0;
while(count < 3) {
pac.reserve_buffer(32*1024);
size_t len = input.readsome(pac.buffer(), pac.buffer_capacity());
pac.buffer_consumed(len);
while(pac.execute()) {
std::auto_ptr<msgpack::zone> z(pac.release_zone());
msgpack::object obj = pac.data();
pac.reset();
switch(count++) {
case 0:
EXPECT_EQ(1, obj.as<int>());
break;
case 1:
EXPECT_EQ(2, obj.as<int>());
break;
case 2:
EXPECT_EQ(3, obj.as<int>());
return;
}
}
}
}
// backward compatibility
class event_handler_compat {
public:
event_handler_compat(std::istream& input) : input(input) { }
~event_handler_compat() { }
void on_read()
{
while(true) {
pac.reserve_buffer(32*1024);
size_t len = input.readsome(pac.buffer(), pac.buffer_capacity());
if(len == 0) {
return;
}
pac.buffer_consumed(len);
while(pac.execute()) {
std::auto_ptr<msgpack::zone> z(pac.release_zone());
msgpack::object obj = pac.data();
pac.reset();
on_message(obj, z);
}
if(pac.message_size() > 10*1024*1024) {
throw std::runtime_error("message is too large");
}
}
}
void on_message(msgpack::object obj, std::auto_ptr<msgpack::zone> z)
{
EXPECT_EQ(expect, obj.as<int>());
}
int expect;
private:
std::istream& input;
msgpack::unpacker pac;
};
TEST(streaming, event_compat)
{
std::stringstream stream;
msgpack::packer<std::ostream> pk(&stream);
event_handler_compat handler(stream);
pk.pack(1);
handler.expect = 1;
handler.on_read();
pk.pack(2);
handler.expect = 2;
handler.on_read();
pk.pack(3);
handler.expect = 3;
handler.on_read();
}

57
cpp/test/streaming_c.cc Normal file
View File

@@ -0,0 +1,57 @@
#include <msgpack.h>
#include <gtest/gtest.h>
#include <stdio.h>
TEST(streaming, basic)
{
msgpack_sbuffer* buffer = msgpack_sbuffer_new();
msgpack_packer* pk = msgpack_packer_new(buffer, msgpack_sbuffer_write);
EXPECT_EQ(0, msgpack_pack_int(pk, 1));
EXPECT_EQ(0, msgpack_pack_int(pk, 2));
EXPECT_EQ(0, msgpack_pack_int(pk, 3));
msgpack_packer_free(pk);
const char* input = buffer->data;
const char* const eof = input + buffer->size;
msgpack_unpacker pac;
msgpack_unpacker_init(&pac, MSGPACK_UNPACKER_INIT_BUFFER_SIZE);
msgpack_unpacked result;
msgpack_unpacked_init(&result);
int count = 0;
while(count < 3) {
msgpack_unpacker_reserve_buffer(&pac, 32*1024);
/* read buffer into msgpack_unapcker_buffer(&pac) upto
* msgpack_unpacker_buffer_capacity(&pac) bytes. */
size_t len = 1;
memcpy(msgpack_unpacker_buffer(&pac), input, len);
input += len;
msgpack_unpacker_buffer_consumed(&pac, len);
while(msgpack_unpacker_next(&pac, &result)) {
msgpack_object obj = result.data;
switch(count++) {
case 0:
EXPECT_EQ(MSGPACK_OBJECT_POSITIVE_INTEGER, result.data.type);
EXPECT_EQ(1, result.data.via.u64);
break;
case 1:
EXPECT_EQ(MSGPACK_OBJECT_POSITIVE_INTEGER, result.data.type);
EXPECT_EQ(2, result.data.via.u64);
break;
case 2:
EXPECT_EQ(MSGPACK_OBJECT_POSITIVE_INTEGER, result.data.type);
EXPECT_EQ(3, result.data.via.u64);
return;
}
}
EXPECT_TRUE(input < eof);
}
}

13
cpp/test/version.cc Normal file
View File

@@ -0,0 +1,13 @@
#include <msgpack.hpp>
#include <gtest/gtest.h>
TEST(version, print)
{
printf("MSGPACK_VERSION : %s\n", MSGPACK_VERSION);
printf("MSGPACK_VERSION_MAJOR : %d\n", MSGPACK_VERSION_MAJOR);
printf("MSGPACK_VERSION_MINOR : %d\n", MSGPACK_VERSION_MINOR);
printf("msgpack_version() : %s\n", msgpack_version());
printf("msgpack_version_major() : %d\n", msgpack_version_major());
printf("msgpack_version_minor() : %d\n", msgpack_version_minor());
}

78
cpp/test/zone.cc Normal file
View File

@@ -0,0 +1,78 @@
#include <msgpack.hpp>
#include <gtest/gtest.h>
TEST(zone, malloc)
{
msgpack::zone z;
char* buf1 = (char*)z.malloc(4);
memcpy(buf1, "test", 4);
char* buf2 = (char*)z.malloc(4);
memcpy(buf2, "test", 4);
}
class myclass {
public:
myclass() : num(0), str("default") { }
myclass(int num, const std::string& str) :
num(num), str(str) { }
~myclass() { }
int num;
std::string str;
private:
myclass(const myclass&);
};
TEST(zone, allocate)
{
msgpack::zone z;
myclass* m = z.allocate<myclass>();
EXPECT_EQ(m->num, 0);
EXPECT_EQ(m->str, "default");
}
TEST(zone, allocate_constructor)
{
msgpack::zone z;
myclass* m = z.allocate<myclass>(7, "msgpack");
EXPECT_EQ(m->num, 7);
EXPECT_EQ(m->str, "msgpack");
}
static void custom_finalizer_func(void* user)
{
myclass* m = (myclass*)user;
delete m;
}
TEST(zone, push_finalizer)
{
msgpack::zone z;
myclass* m = new myclass();
z.push_finalizer(custom_finalizer_func, (void*)m);
}
TEST(zone, push_finalizer_auto_ptr)
{
msgpack::zone z;
std::auto_ptr<myclass> am(new myclass());
z.push_finalizer(am);
}
TEST(zone, malloc_no_align)
{
msgpack::zone z;
char* buf1 = (char*)z.malloc_no_align(4);
char* buf2 = (char*)z.malloc_no_align(4);
EXPECT_EQ(buf1+4, buf2);
}

4
erlang/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
MANIFEST
*.beam
.omakedb*
*.omc

42
erlang/OMakefile Normal file
View File

@@ -0,0 +1,42 @@
########################################################################
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this file, to deal in the File without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the File, and to permit persons to whom the
# File is furnished to do so, subject to the following condition:
#
# THE FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE FILE OR
# THE USE OR OTHER DEALINGS IN THE FILE.
########################################################################
# The standard OMakefile.
# You will usually need to modify this file for your project.
########################################################################
# Phony targets are scoped, so you probably want to declare them first.
#
.PHONY: all clean test #install
########################################################################
# Subdirectories.
# You may want to include some subdirectories in this project.
# If so, define the subdirectory targets and uncomment this section.
#
.DEFAULT: msgpack.beam
msgpack.beam: msgpack.erl
erlc $<
test: msgpack.beam
erl -noshell -s msgpack test -s init stop
clean:
-rm *.beam

45
erlang/OMakeroot Normal file
View File

@@ -0,0 +1,45 @@
########################################################################
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this file, to deal in the File without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the File, and to permit persons to whom the
# File is furnished to do so, subject to the following condition:
#
# THE FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE FILE OR
# THE USE OR OTHER DEALINGS IN THE FILE.
########################################################################
# The standard OMakeroot file.
# You will not normally need to modify this file.
# By default, your changes should be placed in the
# OMakefile in this directory.
#
# If you decide to modify this file, note that it uses exactly
# the same syntax as the OMakefile.
#
#
# Include the standard installed configuration files.
# Any of these can be deleted if you are not using them,
# but you probably want to keep the Common file.
#
open build/C
open build/OCaml
open build/LaTeX
#
# The command-line variables are defined *after* the
# standard configuration has been loaded.
#
DefineCommandVars()
#
# Include the OMakefile in this directory.
#
.SUBDIRS: .

9
erlang/README.md Normal file
View File

@@ -0,0 +1,9 @@
MessagePack for Erlang
======================
Binary-based efficient object serialization library.
see wiki ( http://redmine.msgpack.org/projects/msgpack/wiki/QuickStartErlang ) for details
# Status
0.1.0 released.

362
erlang/msgpack.erl Normal file
View File

@@ -0,0 +1,362 @@
%%
%% MessagePack for Erlang
%%
%% Copyright (C) 2009-2010 UENISHI Kota
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
-module(msgpack).
-author('kuenishi+msgpack@gmail.com').
%% tuples, atoms are not supported. lists, integers, double, and so on.
%% see http://msgpack.sourceforge.jp/spec for
%% supported formats. APIs are almost compatible
%% for C API (http://msgpack.sourceforge.jp/c:doc)
%% except buffering functions (both copying and zero-copying).
-export([pack/1, unpack/1, unpack_all/1]).
-export([pack_map/1]).
% compile:
% erl> c(msgpack).
% erl> S = <some term>.
% erl> {S, <<>>} = msgpack:unpack( msgpack:pack(S) ).
-type reason() :: enomem | badarg | no_code_matches.
-type msgpack_term() :: [msgpack_term()]
| {[{msgpack_term(),msgpack_term()}]}
| integer() | float() | binary().
% ===== external APIs ===== %
-spec pack(Term::msgpack_term()) -> binary().
pack(I) when is_integer(I) andalso I < 0 ->
pack_int_(I);
pack(I) when is_integer(I) ->
pack_uint_(I);
pack(F) when is_float(F) ->
pack_double(F);
pack(nil) ->
<< 16#C0:8 >>;
pack(true) ->
<< 16#C3:8 >>;
pack(false) ->
<< 16#C2:8 >>;
pack(Bin) when is_binary(Bin) ->
pack_raw(Bin);
pack(List) when is_list(List) ->
pack_array(List);
pack({Map}) when is_list(Map) ->
pack_map(Map);
pack(Map) when is_tuple(Map), element(1,Map)=:=dict ->
pack_map(dict:to_list(Map));
pack(_Other) ->
{error, undefined}.
% unpacking.
% if failed in decoding and not end, get more data
% and feed more Bin into this function.
% TODO: error case for imcomplete format when short for any type formats.
-spec unpack( Bin::binary() )-> {msgpack_term(), binary()} |
{more, non_neg_integer()} | {more, undefined} |
{error, reason()}.
unpack(Bin) when not is_binary(Bin)->
{error, badarg};
unpack(Bin) when bit_size(Bin) >= 8 ->
unpack_(Bin);
unpack(<<>>)->
{more, 1};
unpack(_) ->
{more, undefined}.
-spec unpack_all( binary() ) -> [msgpack_term()].
unpack_all(Data)->
case unpack(Data) of
{ Term, Binary } when bit_size(Binary) =:= 0 ->
[Term];
{ Term, Binary } when is_binary(Binary) ->
[Term|unpack_all(Binary)]
end.
-spec pack_map(M::[{msgpack_term(),msgpack_term()}])-> binary().
pack_map(M)->
case length(M) of
Len when Len < 16 ->
<< 2#1000:4, Len:4/integer-unit:1, (pack_map_(M, <<>>))/binary >>;
Len when Len < 16#10000 -> % 65536
<< 16#DE:8, Len:16/big-unsigned-integer-unit:1, (pack_map_(M, <<>>))/binary >>;
Len ->
<< 16#DF:8, Len:32/big-unsigned-integer-unit:1, (pack_map_(M, <<>>))/binary >>
end.
% ===== internal APIs ===== %
% positive fixnum
pack_uint_(N) when N < 128 ->
<< 2#0:1, N:7 >>;
% uint 8
pack_uint_(N) when N < 256 ->
<< 16#CC:8, N:8 >>;
% uint 16
pack_uint_(N) when N < 65536 ->
<< 16#CD:8, N:16/big-unsigned-integer-unit:1 >>;
% uint 32
pack_uint_(N) when N < 16#FFFFFFFF->
<< 16#CE:8, N:32/big-unsigned-integer-unit:1 >>;
% uint 64
pack_uint_(N) ->
<< 16#CF:8, N:64/big-unsigned-integer-unit:1 >>.
% negative fixnum
pack_int_(N) when is_integer(N) , N >= -32->
<< 2#111:3, N:5 >>;
% int 8
pack_int_(N) when N > -128 ->
<< 16#D0:8, N:8/big-signed-integer-unit:1 >>;
% int 16
pack_int_(N) when N > -32768 ->
<< 16#D1:8, N:16/big-signed-integer-unit:1 >>;
% int 32
pack_int_(N) when N > -16#FFFFFFFF ->
<< 16#D2:8, N:32/big-signed-integer-unit:1 >>;
% int 64
pack_int_(N) ->
<< 16#D3:8, N:64/big-signed-integer-unit:1 >>.
% float : erlang's float is always IEEE 754 64bit format.
%pack_float(F) when is_float(F)->
% << 16#CA:8, F:32/big-float-unit:1 >>.
% pack_double(F).
% double
pack_double(F) ->
<< 16#CB:8, F:64/big-float-unit:1 >>.
% raw bytes
pack_raw(Bin) ->
case byte_size(Bin) of
Len when Len < 6->
<< 2#101:3, Len:5, Bin/binary >>;
Len when Len < 16#10000 -> % 65536
<< 16#DA:8, Len:16/big-unsigned-integer-unit:1, Bin/binary >>;
Len ->
<< 16#DB:8, Len:32/big-unsigned-integer-unit:1, Bin/binary >>
end.
% list / tuple
pack_array(L) ->
case length(L) of
Len when Len < 16 ->
<< 2#1001:4, Len:4/integer-unit:1, (pack_array_(L, <<>>))/binary >>;
Len when Len < 16#10000 -> % 65536
<< 16#DC:8, Len:16/big-unsigned-integer-unit:1,(pack_array_(L, <<>>))/binary >>;
Len ->
<< 16#DD:8, Len:32/big-unsigned-integer-unit:1,(pack_array_(L, <<>>))/binary >>
end.
pack_array_([], Acc) -> Acc;
pack_array_([Head|Tail], Acc) ->
pack_array_(Tail, <<Acc/binary, (pack(Head))/binary>>).
% FIXME! this should be without lists:reverse/1
unpack_array_(<<>>, 0, RetList) -> {lists:reverse(RetList), <<>>};
unpack_array_(Remain, 0, RetList) when is_binary(Remain)-> {lists:reverse(RetList), Remain};
unpack_array_(<<>>, RestLen, _RetList) when RestLen > 0 -> {more, undefined};
unpack_array_(Bin, RestLen, RetList) when is_binary(Bin)->
case unpack(Bin) of
{more, _} -> {more, undefined};
{Term, Rest}-> unpack_array_(Rest, RestLen-1, [Term|RetList])
end.
pack_map_([], Acc) -> Acc;
pack_map_([{Key,Value}|Tail], Acc) ->
pack_map_(Tail, << Acc/binary, (pack(Key))/binary, (pack(Value))/binary>>).
% FIXME! this should be without lists:reverse/1
-spec unpack_map_(binary(), non_neg_integer(), [{term(), msgpack_term()}])->
{more, non_neg_integer()} | { any(), binary()}.
unpack_map_(Bin, 0, Acc) -> {{lists:reverse(Acc)}, Bin};
unpack_map_(Bin, Len, Acc) ->
case unpack(Bin) of
{more, _} -> {more, undefined};
{Key, Rest} ->
case unpack(Rest) of
{more, _} -> {more, undefined};
{Value, Rest2} ->
unpack_map_(Rest2,Len-1,[{Key,Value}|Acc])
end
end.
-spec unpack_(Payload::binary()) ->
{more, pos_integer()} | {msgpack_term(), binary()} | {error, reason()}.
unpack_(Binary)->
case Binary of
% ATOMS
<<16#C0, Rest/binary>> -> {nil, Rest};
<<16#C2, Rest/binary>> -> {false, Rest};
<<16#C3, Rest/binary>> -> {true, Rest};
% Floats
<<16#CA, V:32/float-unit:1, Rest/binary>> -> {V, Rest};
<<16#CB, V:64/float-unit:1, Rest/binary>> -> {V, Rest};
% Unsigned integers
<<16#CC, V:8/unsigned-integer, Rest/binary>> -> {V, Rest};
<<16#CD, V:16/big-unsigned-integer-unit:1, Rest/binary>> -> {V, Rest};
<<16#CE, V:32/big-unsigned-integer-unit:1, Rest/binary>> -> {V, Rest};
<<16#CF, V:64/big-unsigned-integer-unit:1, Rest/binary>> -> {V, Rest};
% Signed integers
<<16#D0, V:8/signed-integer, Rest/binary>> -> {V, Rest};
<<16#D1, V:16/big-signed-integer-unit:1, Rest/binary>> -> {V, Rest};
<<16#D2, V:32/big-signed-integer-unit:1, Rest/binary>> -> {V, Rest};
<<16#D3, V:64/big-signed-integer-unit:1, Rest/binary>> -> {V, Rest};
% Raw bytes
<<16#DA, L:16/unsigned-integer-unit:1, V:L/binary, Rest/binary>> -> {V, Rest};
<<16#DB, L:32/unsigned-integer-unit:1, V:L/binary, Rest/binary>> -> {V, Rest};
% Arrays
<<16#DC, L:16/big-unsigned-integer-unit:1, Rest/binary>> -> unpack_array_(Rest, L, []);
<<16#DD, L:32/big-unsigned-integer-unit:1, Rest/binary>> -> unpack_array_(Rest, L, []);
% Maps
<<16#DE, L:16/big-unsigned-integer-unit:1, Rest/binary>> -> unpack_map_(Rest, L, []);
<<16#DF, L:32/big-unsigned-integer-unit:1, Rest/binary>> -> unpack_map_(Rest, L, []);
% Tag-encoded lengths (kept last, for speed)
<<0:1, V:7, Rest/binary>> -> {V, Rest}; % positive int
<<2#111:3, V:5, Rest/binary>> -> {V - 2#100000, Rest}; % negative int
<<2#101:3, L:5, V:L/binary, Rest/binary>> -> {V, Rest}; % raw bytes
<<2#1001:4, L:4, Rest/binary>> -> unpack_array_(Rest, L, []); % array
<<2#1000:4, L:4, Rest/binary>> -> unpack_map_(Rest, L, []); % map
% Incomplete / invalid data
<<16#CA, Rest/binary>> -> {more, 4-byte_size(Rest)};
<<16#CB, Rest/binary>> -> {more, 8-byte_size(Rest)};
<<16#CC>> -> {more, 1};
<<16#CD, Rest/binary>> -> {more, 2-byte_size(Rest)};
<<16#CE, Rest/binary>> -> {more, 4-byte_size(Rest)};
<<16#CF, Rest/binary>> -> {more, 8-byte_size(Rest)};
<<16#D0>> -> {more, 1};
<<16#D1, Rest/binary>> -> {more, 2-byte_size(Rest)};
<<16#D2, Rest/binary>> -> {more, 4-byte_size(Rest)};
<<16#D3, Rest/binary>> -> {more, 8-byte_size(Rest)};
<<16#DA, Rest/binary>> -> {more, 16-byte_size(Rest)};
<<16#DB, Rest/binary>> -> {more, 32-byte_size(Rest)};
<<16#DC, Rest/binary>> -> {more, 2-byte_size(Rest)};
<<16#DD, Rest/binary>> -> {more, 4-byte_size(Rest)};
<<16#DE, Rest/binary>> -> {more, 2-byte_size(Rest)};
<<16#DF, Rest/binary>> -> {more, 4-byte_size(Rest)};
<<2#101:3, L:5, Rest/binary>> -> {more, L-byte_size(Rest)};
<<>> -> {more, 1};
<<2#101:3, _/binary>> -> {more, undefined};
<<F:8, Rest/binary>> when F==16#C1;
F==16#C7; F==16#C8; F==16#C9; F==16#D5;
F==16#D6; F==16#D7; F==16#D8; F==16#D9->
{error, {badarg, <<F, Rest/binary>>}};
Other ->
{error, {badarg, Other}}
end.
% ===== test codes ===== %
-include_lib("eunit/include/eunit.hrl").
-ifdef(EUNIT).
compare_all([], [])-> ok;
compare_all([], R)-> {toomuchrhs, R};
compare_all(L, [])-> {toomuchlhs, L};
compare_all([LH|LTL], [RH|RTL]) ->
LH=RH,
compare_all(LTL, RTL).
test_data()->
[true, false, nil,
0, 1, 2, 123, 512, 1230, 678908, 16#FFFFFFFFFF,
-1, -23, -512, -1230, -567898, -16#FFFFFFFFFF,
123.123, -234.4355, 1.0e-34, 1.0e64,
[23, 234, 0.23],
<<"hogehoge">>, <<"243546rf7g68h798j", 0, 23, 255>>,
<<"hoasfdafdas][">>,
[0,42, <<"sum">>, [1,2]], [1,42, nil, [3]],
-234, -40000, -16#10000000, -16#100000000,
42
].
basic_test()->
Tests = test_data(),
Passed = test_(Tests),
Passed = length(Tests).
port_test()->
Tests = test_data(),
{[Tests],<<>>} = msgpack:unpack(msgpack:pack([Tests])),
Port = open_port({spawn, "ruby ../test/crosslang.rb"}, [binary]),
true = port_command(Port, msgpack:pack(Tests) ),
receive
{Port, {data, Data}}-> {Tests, <<>>}=msgpack:unpack(Data)
after 1024-> ?assert(false) end,
port_close(Port).
test_p(Len,Term,OrigBin,Len) ->
{Term, <<>>}=msgpack:unpack(OrigBin);
test_p(I,_,OrigBin,Len) when I < Len->
<<Bin:I/binary, _/binary>> = OrigBin,
case msgpack:unpack(Bin) of
{more, N} when not is_integer(N) ->
?assertEqual(undefined, N);
{more, N} ->
?assert( N < Len )
end.
partial_test()-> % error handling test.
Term = lists:seq(0, 45),
Bin=msgpack:pack(Term),
BinLen = byte_size(Bin),
[test_p(X, Term, Bin, BinLen) || X <- lists:seq(0,BinLen)].
long_test()->
Longer = lists:seq(0, 655),
% Longest = lists:seq(0,12345),
{Longer, <<>>} = msgpack:unpack(msgpack:pack(Longer)),
% {Longest, <<>>} = msgpack:unpack(msgpack:pack(Longest)).
ok.
map_test()->
Ints = lists:seq(0, 65),
Map = {[ {X, X*2} || X <- Ints ] ++ [{<<"hage">>, 324}, {43542, [nil, true, false]}]},
{Map2, <<>>} = msgpack:unpack(msgpack:pack(Map)),
?assertEqual(Map, Map2),
ok.
unknown_test()->
Tests = [0, 1, 2, 123, 512, 1230, 678908,
-1, -23, -512, -1230, -567898,
<<"hogehoge">>, <<"243546rf7g68h798j">>,
123.123,
-234.4355, 1.0e-34, 1.0e64,
[23, 234, 0.23],
[0,42,<<"sum">>, [1,2]], [1,42, nil, [3]],
{[{1,2},{<<"hoge">>,nil}]},
-234, -50000,
42
],
Port = open_port({spawn, "ruby testcase_generator.rb"}, [binary]),
receive
{Port, {data, Data}}->
compare_all(Tests, msgpack:unpack_all(Data))
after 1024-> ?assert(false) end,
port_close(Port).
test_([]) -> 0;
test_([Before|Rest])->
Pack = msgpack:pack(Before),
{After, <<>>} = msgpack:unpack( Pack ),
?assertEqual(Before, After),
1+test_(Rest).
other_test()->
{more,1}=msgpack:unpack(<<>>).
-endif.

View File

@@ -0,0 +1,65 @@
begin
require 'rubygems'
rescue LoadError
end
require 'msgpack'
def usage
puts <<EOF
Usage: #{$0} [out-file]
This tool is for testing of accepting MessagePack random-term.
This does following behavior:
1. serializes the objects in this file, using Ruby implementation
of MessagePack (Note that Ruby implementation is considered valid)
2. Writes the serialized binaries into <out-file> (default: stdout)
EOF
exit 1
end
code = 1
outio = $stdout
if ARGV.length > 2
usage
end
if fname = ARGV[0]
unless fname == "-"
begin
outio = File.open(fname, "w")
rescue
puts "can't open output file: #{$!}"
exit 1
end
end
end
objs = [0, 1, 2, 123, 512, 1230, 678908,
-1, -23, -512, -1230, -567898,
"hogehoge", "243546rf7g68h798j",
123.123,
-234.4355, 1.0e-34, 1.0e64,
[23, 234, 0.23],
[0,42,"sum", [1,2]], [1,42, nil, [3]],
{ 1 => 2, "hoge" => nil },
-234, -50000,
42
]
begin
objs.each do |obj|
outio.write MessagePack.pack(obj)
outio.flush
end
rescue EOFError
code=0
rescue
$stderr.puts $!
code=1
end
outio.close
exit code

24
haskell/LICENSE Normal file
View File

@@ -0,0 +1,24 @@
Copyright (c) 2009, Hideyuki Tanaka
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Hideyuki Tanaka nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY Hideyuki Tanaka ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

3
haskell/Setup.lhs Normal file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env runhaskell
> import Distribution.Simple
> main = defaultMain

137
haskell/cbits/msgpack.c Normal file
View File

@@ -0,0 +1,137 @@
#include <msgpack.h>
void msgpack_sbuffer_init_wrap(msgpack_sbuffer* sbuf)
{
msgpack_sbuffer_init(sbuf);
}
void msgpack_sbuffer_destroy_wrap(msgpack_sbuffer* sbuf)
{
msgpack_sbuffer_destroy(sbuf);
}
int msgpack_sbuffer_write_wrap(void* data, const char* buf, unsigned int len)
{
return msgpack_sbuffer_write(data, buf, len);
}
msgpack_packer* msgpack_packer_new_wrap(void *data, msgpack_packer_write callback)
{
return msgpack_packer_new(data, callback);
}
void msgpack_packer_free_wrap(msgpack_packer* pk)
{
msgpack_packer_free(pk);
}
int msgpack_pack_uint8_wrap(msgpack_packer* pk, uint8_t d)
{
return msgpack_pack_uint8(pk, d);
}
int msgpack_pack_uint16_wrap(msgpack_packer* pk, uint16_t d)
{
return msgpack_pack_uint16(pk, d);
}
int msgpack_pack_uint32_wrap(msgpack_packer* pk, uint32_t d)
{
return msgpack_pack_uint32(pk, d);
}
int msgpack_pack_uint64_wrap(msgpack_packer* pk, uint64_t d)
{
return msgpack_pack_uint64(pk, d);
}
int msgpack_pack_int8_wrap(msgpack_packer* pk, int8_t d)
{
return msgpack_pack_int8(pk, d);
}
int msgpack_pack_int16_wrap(msgpack_packer* pk, int16_t d)
{
return msgpack_pack_int16(pk, d);
}
int msgpack_pack_int32_wrap(msgpack_packer* pk, int32_t d)
{
return msgpack_pack_int32(pk, d);
}
int msgpack_pack_int64_wrap(msgpack_packer* pk, int64_t d)
{
return msgpack_pack_int64(pk, d);
}
int msgpack_pack_double_wrap(msgpack_packer* pk, double d)
{
return msgpack_pack_double(pk, d);
}
int msgpack_pack_nil_wrap(msgpack_packer* pk)
{
return msgpack_pack_nil(pk);
}
int msgpack_pack_true_wrap(msgpack_packer* pk)
{
return msgpack_pack_true(pk);
}
int msgpack_pack_false_wrap(msgpack_packer* pk)
{
return msgpack_pack_false(pk);
}
int msgpack_pack_array_wrap(msgpack_packer* pk, unsigned int n)
{
return msgpack_pack_array(pk, n);
}
int msgpack_pack_map_wrap(msgpack_packer* pk, unsigned int n)
{
return msgpack_pack_map(pk, n);
}
int msgpack_pack_raw_wrap(msgpack_packer* pk, size_t l)
{
return msgpack_pack_raw(pk, l);
}
int msgpack_pack_raw_body_wrap(msgpack_packer* pk, const void *b, size_t l)
{
return msgpack_pack_raw_body(pk, b, l);
}
bool msgpack_unpacker_reserve_buffer_wrap(msgpack_unpacker *mpac, size_t size)
{
return msgpack_unpacker_reserve_buffer(mpac, size);
}
char *msgpack_unpacker_buffer_wrap(msgpack_unpacker *mpac)
{
return msgpack_unpacker_buffer(mpac);
}
size_t msgpack_unpacker_buffer_capacity_wrap(const msgpack_unpacker *mpac)
{
return msgpack_unpacker_buffer_capacity(mpac);
}
void msgpack_unpacker_buffer_consumed_wrap(msgpack_unpacker *mpac, size_t size)
{
msgpack_unpacker_buffer_consumed(mpac, size);
}
void msgpack_unpacker_data_wrap(msgpack_unpacker *mpac, msgpack_object *obj)
{
*obj=msgpack_unpacker_data(mpac);
}
size_t msgpack_unpacker_message_size_wrap(const msgpack_unpacker *mpac)
{
return msgpack_unpacker_message_size(mpac);
}

32
haskell/msgpack.cabal Normal file
View File

@@ -0,0 +1,32 @@
Name: msgpack
Version: 0.2.2
License: BSD3
License-File: LICENSE
Author: Hideyuki Tanaka
Maintainer: Hideyuki Tanaka <tanaka.hideyuki@gmail.com>
Category: Data
Synopsis: A Haskell binding to MessagePack
Description:
A Haskell binding to MessagePack <http://msgpack.sourceforge.jp/>
Homepage: http://github.com/tanakh/hsmsgpack
Stability: Experimental
Tested-with: GHC==6.10.4
Cabal-Version: >=1.2
Build-Type: Simple
library
build-depends: base>=4 && <5, mtl, bytestring
ghc-options: -O2 -Wall
hs-source-dirs: src
extra-libraries: msgpackc
Exposed-modules:
Data.MessagePack
Data.MessagePack.Base
Data.MessagePack.Class
Data.MessagePack.Feed
Data.MessagePack.Monad
Data.MessagePack.Stream
C-Sources:
cbits/msgpack.c

View File

@@ -0,0 +1,63 @@
--------------------------------------------------------------------
-- |
-- Module : Data.MessagePack
-- Copyright : (c) Hideyuki Tanaka, 2009
-- License : BSD3
--
-- Maintainer: tanaka.hideyuki@gmail.com
-- Stability : experimental
-- Portability: portable
--
-- Simple interface to pack and unpack MessagePack data.
--
--------------------------------------------------------------------
module Data.MessagePack(
module Data.MessagePack.Base,
module Data.MessagePack.Class,
module Data.MessagePack.Feed,
module Data.MessagePack.Monad,
module Data.MessagePack.Stream,
-- * Pack and Unpack
packb,
unpackb,
-- * Pure version of Pack and Unpack
packb',
unpackb',
) where
import Data.ByteString (ByteString)
import System.IO.Unsafe
import Data.MessagePack.Base
import Data.MessagePack.Class
import Data.MessagePack.Feed
import Data.MessagePack.Monad
import Data.MessagePack.Stream
-- | Pack Haskell data to MessagePack string.
packb :: OBJECT a => a -> IO ByteString
packb dat = do
sb <- newSimpleBuffer
pc <- newPacker sb
pack pc dat
simpleBufferData sb
-- | Unpack MessagePack string to Haskell data.
unpackb :: OBJECT a => ByteString -> IO (Result a)
unpackb bs = do
withZone $ \z -> do
r <- unpackObject z bs
return $ case r of
Left err -> Left (show err)
Right (_, dat) -> fromObject dat
-- | Pure version of 'packb'.
packb' :: OBJECT a => a -> ByteString
packb' dat = unsafePerformIO $ packb dat
-- | Pure version of 'unpackb'.
unpackb' :: OBJECT a => ByteString -> Result a
unpackb' bs = unsafePerformIO $ unpackb bs

View File

@@ -0,0 +1,584 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE ForeignFunctionInterface #-}
--------------------------------------------------------------------
-- |
-- Module : Data.MessagePack.Base
-- Copyright : (c) Hideyuki Tanaka, 2009
-- License : BSD3
--
-- Maintainer: tanaka.hideyuki@gmail.com
-- Stability : experimental
-- Portability: portable
--
-- Low Level Interface to MessagePack C API
--
--------------------------------------------------------------------
module Data.MessagePack.Base(
-- * Simple Buffer
SimpleBuffer,
newSimpleBuffer,
simpleBufferData,
-- * Serializer
Packer,
newPacker,
packU8,
packU16,
packU32,
packU64,
packS8,
packS16,
packS32,
packS64,
packTrue,
packFalse,
packInt,
packDouble,
packNil,
packBool,
packArray,
packMap,
packRAW,
packRAWBody,
packRAW',
-- * Stream Deserializer
Unpacker,
defaultInitialBufferSize,
newUnpacker,
unpackerReserveBuffer,
unpackerBuffer,
unpackerBufferCapacity,
unpackerBufferConsumed,
unpackerFeed,
unpackerExecute,
unpackerData,
unpackerReleaseZone,
unpackerResetZone,
unpackerReset,
unpackerMessageSize,
-- * MessagePack Object
Object(..),
packObject,
UnpackReturn(..),
unpackObject,
-- * Memory Zone
Zone,
newZone,
freeZone,
withZone,
) where
import Control.Exception
import Control.Monad
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS hiding (pack, unpack)
import Data.Int
import Data.Word
import Foreign.C
import Foreign.Concurrent
import Foreign.ForeignPtr hiding (newForeignPtr)
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import Foreign.Ptr
import Foreign.Storable
#include <msgpack.h>
type SimpleBuffer = ForeignPtr ()
type WriteCallback = Ptr () -> CString -> CUInt -> IO CInt
-- | Create a new Simple Buffer. It will be deleted automatically.
newSimpleBuffer :: IO SimpleBuffer
newSimpleBuffer = do
ptr <- mallocBytes (#size msgpack_sbuffer)
fptr <- newForeignPtr ptr $ do
msgpack_sbuffer_destroy ptr
free ptr
withForeignPtr fptr $ \p ->
msgpack_sbuffer_init p
return fptr
-- | Get data of Simple Buffer.
simpleBufferData :: SimpleBuffer -> IO ByteString
simpleBufferData sb =
withForeignPtr sb $ \ptr -> do
size <- (#peek msgpack_sbuffer, size) ptr
dat <- (#peek msgpack_sbuffer, data) ptr
BS.packCStringLen (dat, fromIntegral (size :: CSize))
foreign import ccall "msgpack_sbuffer_init_wrap" msgpack_sbuffer_init ::
Ptr () -> IO ()
foreign import ccall "msgpack_sbuffer_destroy_wrap" msgpack_sbuffer_destroy ::
Ptr () -> IO ()
foreign import ccall "msgpack_sbuffer_write_wrap" msgpack_sbuffer_write ::
WriteCallback
type Packer = ForeignPtr ()
-- | Create new Packer. It will be deleted automatically.
newPacker :: SimpleBuffer -> IO Packer
newPacker sbuf = do
cb <- wrap_callback msgpack_sbuffer_write
ptr <- withForeignPtr sbuf $ \ptr ->
msgpack_packer_new ptr cb
fptr <- newForeignPtr ptr $ do
msgpack_packer_free ptr
return fptr
foreign import ccall "msgpack_packer_new_wrap" msgpack_packer_new ::
Ptr () -> FunPtr WriteCallback -> IO (Ptr ())
foreign import ccall "msgpack_packer_free_wrap" msgpack_packer_free ::
Ptr () -> IO ()
foreign import ccall "wrapper" wrap_callback ::
WriteCallback -> IO (FunPtr WriteCallback)
packU8 :: Packer -> Word8 -> IO Int
packU8 pc n =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_uint8 ptr n
foreign import ccall "msgpack_pack_uint8_wrap" msgpack_pack_uint8 ::
Ptr () -> Word8 -> IO CInt
packU16 :: Packer -> Word16 -> IO Int
packU16 pc n =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_uint16 ptr n
foreign import ccall "msgpack_pack_uint16_wrap" msgpack_pack_uint16 ::
Ptr () -> Word16 -> IO CInt
packU32 :: Packer -> Word32 -> IO Int
packU32 pc n =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_uint32 ptr n
foreign import ccall "msgpack_pack_uint32_wrap" msgpack_pack_uint32 ::
Ptr () -> Word32 -> IO CInt
packU64 :: Packer -> Word64 -> IO Int
packU64 pc n =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_uint64 ptr n
foreign import ccall "msgpack_pack_uint64_wrap" msgpack_pack_uint64 ::
Ptr () -> Word64 -> IO CInt
packS8 :: Packer -> Int8 -> IO Int
packS8 pc n =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_int8 ptr n
foreign import ccall "msgpack_pack_int8_wrap" msgpack_pack_int8 ::
Ptr () -> Int8 -> IO CInt
packS16 :: Packer -> Int16 -> IO Int
packS16 pc n =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_int16 ptr n
foreign import ccall "msgpack_pack_int16_wrap" msgpack_pack_int16 ::
Ptr () -> Int16 -> IO CInt
packS32 :: Packer -> Int32 -> IO Int
packS32 pc n =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_int32 ptr n
foreign import ccall "msgpack_pack_int32_wrap" msgpack_pack_int32 ::
Ptr () -> Int32 -> IO CInt
packS64 :: Packer -> Int64 -> IO Int
packS64 pc n =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_int64 ptr n
foreign import ccall "msgpack_pack_int64_wrap" msgpack_pack_int64 ::
Ptr () -> Int64 -> IO CInt
-- | Pack an integral data.
packInt :: Integral a => Packer -> a -> IO Int
packInt pc n = packS64 pc $ fromIntegral n
-- | Pack a double data.
packDouble :: Packer -> Double -> IO Int
packDouble pc d =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_double ptr (realToFrac d)
foreign import ccall "msgpack_pack_double_wrap" msgpack_pack_double ::
Ptr () -> CDouble -> IO CInt
-- | Pack a nil.
packNil :: Packer -> IO Int
packNil pc =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_nil ptr
foreign import ccall "msgpack_pack_nil_wrap" msgpack_pack_nil ::
Ptr () -> IO CInt
packTrue :: Packer -> IO Int
packTrue pc =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_true ptr
foreign import ccall "msgpack_pack_true_wrap" msgpack_pack_true ::
Ptr () -> IO CInt
packFalse :: Packer -> IO Int
packFalse pc =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_false ptr
foreign import ccall "msgpack_pack_false_wrap" msgpack_pack_false ::
Ptr () -> IO CInt
-- | Pack a bool data.
packBool :: Packer -> Bool -> IO Int
packBool pc True = packTrue pc
packBool pc False = packFalse pc
-- | 'packArray' @p n@ starts packing an array.
-- Next @n@ data will consist this array.
packArray :: Packer -> Int -> IO Int
packArray pc n =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_array ptr (fromIntegral n)
foreign import ccall "msgpack_pack_array_wrap" msgpack_pack_array ::
Ptr () -> CUInt -> IO CInt
-- | 'packMap' @p n@ starts packing a map.
-- Next @n@ pairs of data (2*n data) will consist this map.
packMap :: Packer -> Int -> IO Int
packMap pc n =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_map ptr (fromIntegral n)
foreign import ccall "msgpack_pack_map_wrap" msgpack_pack_map ::
Ptr () -> CUInt -> IO CInt
-- | 'packRAW' @p n@ starts packing a byte sequence.
-- Next total @n@ bytes of 'packRAWBody' call will consist this sequence.
packRAW :: Packer -> Int -> IO Int
packRAW pc n =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
msgpack_pack_raw ptr (fromIntegral n)
foreign import ccall "msgpack_pack_raw_wrap" msgpack_pack_raw ::
Ptr () -> CSize -> IO CInt
-- | Pack a byte sequence.
packRAWBody :: Packer -> ByteString -> IO Int
packRAWBody pc bs =
liftM fromIntegral $ withForeignPtr pc $ \ptr ->
BS.useAsCStringLen bs $ \(str, len) ->
msgpack_pack_raw_body ptr (castPtr str) (fromIntegral len)
foreign import ccall "msgpack_pack_raw_body_wrap" msgpack_pack_raw_body ::
Ptr () -> Ptr () -> CSize -> IO CInt
-- | Pack a single byte stream. It calls 'packRAW' and 'packRAWBody'.
packRAW' :: Packer -> ByteString -> IO Int
packRAW' pc bs = do
_ <- packRAW pc (BS.length bs)
packRAWBody pc bs
type Unpacker = ForeignPtr ()
defaultInitialBufferSize :: Int
defaultInitialBufferSize = 32 * 1024 -- #const MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE
-- | 'newUnpacker' @initialBufferSize@ creates a new Unpacker. It will be deleted automatically.
newUnpacker :: Int -> IO Unpacker
newUnpacker initialBufferSize = do
ptr <- msgpack_unpacker_new (fromIntegral initialBufferSize)
fptr <- newForeignPtr ptr $ do
msgpack_unpacker_free ptr
return fptr
foreign import ccall "msgpack_unpacker_new" msgpack_unpacker_new ::
CSize -> IO (Ptr ())
foreign import ccall "msgpack_unpacker_free" msgpack_unpacker_free ::
Ptr() -> IO ()
-- | 'unpackerReserveBuffer' @up size@ reserves at least @size@ bytes of buffer.
unpackerReserveBuffer :: Unpacker -> Int -> IO Bool
unpackerReserveBuffer up size =
withForeignPtr up $ \ptr ->
liftM (/=0) $ msgpack_unpacker_reserve_buffer ptr (fromIntegral size)
foreign import ccall "msgpack_unpacker_reserve_buffer_wrap" msgpack_unpacker_reserve_buffer ::
Ptr () -> CSize -> IO CChar
-- | Get a pointer of unpacker buffer.
unpackerBuffer :: Unpacker -> IO (Ptr CChar)
unpackerBuffer up =
withForeignPtr up $ \ptr ->
msgpack_unpacker_buffer ptr
foreign import ccall "msgpack_unpacker_buffer_wrap" msgpack_unpacker_buffer ::
Ptr () -> IO (Ptr CChar)
-- | Get size of allocated buffer.
unpackerBufferCapacity :: Unpacker -> IO Int
unpackerBufferCapacity up =
withForeignPtr up $ \ptr ->
liftM fromIntegral $ msgpack_unpacker_buffer_capacity ptr
foreign import ccall "msgpack_unpacker_buffer_capacity_wrap" msgpack_unpacker_buffer_capacity ::
Ptr () -> IO CSize
-- | 'unpackerBufferConsumed' @up size@ notices that writed @size@ bytes to buffer.
unpackerBufferConsumed :: Unpacker -> Int -> IO ()
unpackerBufferConsumed up size =
withForeignPtr up $ \ptr ->
msgpack_unpacker_buffer_consumed ptr (fromIntegral size)
foreign import ccall "msgpack_unpacker_buffer_consumed_wrap" msgpack_unpacker_buffer_consumed ::
Ptr () -> CSize -> IO ()
-- | Write byte sequence to Unpacker. It is utility funciton, calls 'unpackerReserveBuffer', 'unpackerBuffer' and 'unpackerBufferConsumed'.
unpackerFeed :: Unpacker -> ByteString -> IO ()
unpackerFeed up bs =
BS.useAsCStringLen bs $ \(str, len) -> do
True <- unpackerReserveBuffer up len
ptr <- unpackerBuffer up
copyArray ptr str len
unpackerBufferConsumed up len
-- | Execute deserializing. It returns 0 when buffer contains not enough bytes, returns 1 when succeeded, returns negative value when it failed.
unpackerExecute :: Unpacker -> IO Int
unpackerExecute up =
withForeignPtr up $ \ptr ->
liftM fromIntegral $ msgpack_unpacker_execute ptr
foreign import ccall "msgpack_unpacker_execute" msgpack_unpacker_execute ::
Ptr () -> IO CInt
-- | Returns a deserialized object when 'unpackerExecute' returned 1.
unpackerData :: Unpacker -> IO Object
unpackerData up =
withForeignPtr up $ \ptr ->
allocaBytes (#size msgpack_object) $ \pobj -> do
msgpack_unpacker_data ptr pobj
peekObject pobj
foreign import ccall "msgpack_unpacker_data_wrap" msgpack_unpacker_data ::
Ptr () -> Ptr () -> IO ()
-- | Release memory zone. The returned zone must be freed by calling 'freeZone'.
unpackerReleaseZone :: Unpacker -> IO Zone
unpackerReleaseZone up =
withForeignPtr up $ \ptr ->
msgpack_unpacker_release_zone ptr
foreign import ccall "msgpack_unpacker_release_zone" msgpack_unpacker_release_zone ::
Ptr () -> IO (Ptr ())
-- | Free memory zone used by Unapcker.
unpackerResetZone :: Unpacker -> IO ()
unpackerResetZone up =
withForeignPtr up $ \ptr ->
msgpack_unpacker_reset_zone ptr
foreign import ccall "msgpack_unpacker_reset_zone" msgpack_unpacker_reset_zone ::
Ptr () -> IO ()
-- | Reset Unpacker state except memory zone.
unpackerReset :: Unpacker -> IO ()
unpackerReset up =
withForeignPtr up $ \ptr ->
msgpack_unpacker_reset ptr
foreign import ccall "msgpack_unpacker_reset" msgpack_unpacker_reset ::
Ptr () -> IO ()
-- | Returns number of bytes of sequence of deserializing object.
unpackerMessageSize :: Unpacker -> IO Int
unpackerMessageSize up =
withForeignPtr up $ \ptr ->
liftM fromIntegral $ msgpack_unpacker_message_size ptr
foreign import ccall "msgpack_unpacker_message_size_wrap" msgpack_unpacker_message_size ::
Ptr () -> IO CSize
type Zone = Ptr ()
-- | Create a new memory zone. It must be freed manually.
newZone :: IO Zone
newZone =
msgpack_zone_new (#const MSGPACK_ZONE_CHUNK_SIZE)
-- | Free a memory zone.
freeZone :: Zone -> IO ()
freeZone z =
msgpack_zone_free z
-- | Create a memory zone, then execute argument, then free memory zone.
withZone :: (Zone -> IO a) -> IO a
withZone z =
bracket newZone freeZone z
foreign import ccall "msgpack_zone_new" msgpack_zone_new ::
CSize -> IO Zone
foreign import ccall "msgpack_zone_free" msgpack_zone_free ::
Zone -> IO ()
-- | Object Representation of MessagePack data.
data Object =
ObjectNil
| ObjectBool Bool
| ObjectInteger Int
| ObjectDouble Double
| ObjectRAW ByteString
| ObjectArray [Object]
| ObjectMap [(Object, Object)]
deriving (Show)
peekObject :: Ptr a -> IO Object
peekObject ptr = do
typ <- (#peek msgpack_object, type) ptr
case (typ :: CInt) of
(#const MSGPACK_OBJECT_NIL) ->
return ObjectNil
(#const MSGPACK_OBJECT_BOOLEAN) ->
peekObjectBool ptr
(#const MSGPACK_OBJECT_POSITIVE_INTEGER) ->
peekObjectPositiveInteger ptr
(#const MSGPACK_OBJECT_NEGATIVE_INTEGER) ->
peekObjectNegativeInteger ptr
(#const MSGPACK_OBJECT_DOUBLE) ->
peekObjectDouble ptr
(#const MSGPACK_OBJECT_RAW) ->
peekObjectRAW ptr
(#const MSGPACK_OBJECT_ARRAY) ->
peekObjectArray ptr
(#const MSGPACK_OBJECT_MAP) ->
peekObjectMap ptr
_ ->
fail $ "peekObject: unknown object type (" ++ show typ ++ ")"
peekObjectBool :: Ptr a -> IO Object
peekObjectBool ptr = do
b <- (#peek msgpack_object, via.boolean) ptr
return $ ObjectBool $ (b :: CUChar) /= 0
peekObjectPositiveInteger :: Ptr a -> IO Object
peekObjectPositiveInteger ptr = do
n <- (#peek msgpack_object, via.u64) ptr
return $ ObjectInteger $ fromIntegral (n :: Word64)
peekObjectNegativeInteger :: Ptr a -> IO Object
peekObjectNegativeInteger ptr = do
n <- (#peek msgpack_object, via.i64) ptr
return $ ObjectInteger $ fromIntegral (n :: Int64)
peekObjectDouble :: Ptr a -> IO Object
peekObjectDouble ptr = do
d <- (#peek msgpack_object, via.dec) ptr
return $ ObjectDouble $ realToFrac (d :: CDouble)
peekObjectRAW :: Ptr a -> IO Object
peekObjectRAW ptr = do
size <- (#peek msgpack_object, via.raw.size) ptr
p <- (#peek msgpack_object, via.raw.ptr) ptr
bs <- BS.packCStringLen (p, fromIntegral (size :: Word32))
return $ ObjectRAW bs
peekObjectArray :: Ptr a -> IO Object
peekObjectArray ptr = do
csize <- (#peek msgpack_object, via.array.size) ptr
let size = fromIntegral (csize :: Word32)
p <- (#peek msgpack_object, via.array.ptr) ptr
objs <- mapM (\i -> peekObject $ p `plusPtr`
((#size msgpack_object) * i))
[0..size-1]
return $ ObjectArray objs
peekObjectMap :: Ptr a -> IO Object
peekObjectMap ptr = do
csize <- (#peek msgpack_object, via.map.size) ptr
let size = fromIntegral (csize :: Word32)
p <- (#peek msgpack_object, via.map.ptr) ptr
dat <- mapM (\i -> peekObjectKV $ p `plusPtr`
((#size msgpack_object_kv) * i))
[0..size-1]
return $ ObjectMap dat
peekObjectKV :: Ptr a -> IO (Object, Object)
peekObjectKV ptr = do
k <- peekObject $ ptr `plusPtr` (#offset msgpack_object_kv, key)
v <- peekObject $ ptr `plusPtr` (#offset msgpack_object_kv, val)
return (k, v)
-- | Pack a Object.
packObject :: Packer -> Object -> IO ()
packObject pc ObjectNil = packNil pc >> return ()
packObject pc (ObjectBool b) = packBool pc b >> return ()
packObject pc (ObjectInteger n) = packInt pc n >> return ()
packObject pc (ObjectDouble d) = packDouble pc d >> return ()
packObject pc (ObjectRAW bs) = packRAW' pc bs >> return ()
packObject pc (ObjectArray ls) = do
_ <- packArray pc (length ls)
mapM_ (packObject pc) ls
packObject pc (ObjectMap ls) = do
_ <- packMap pc (length ls)
mapM_ (\(a, b) -> packObject pc a >> packObject pc b) ls
data UnpackReturn =
UnpackContinue -- ^ not enough bytes to unpack object
| UnpackParseError -- ^ got invalid bytes
| UnpackError -- ^ other error
deriving (Eq, Show)
-- | Unpack a single MessagePack object from byte sequence.
unpackObject :: Zone -> ByteString -> IO (Either UnpackReturn (Int, Object))
unpackObject z dat =
allocaBytes (#size msgpack_object) $ \ptr ->
BS.useAsCStringLen dat $ \(str, len) ->
alloca $ \poff -> do
poke poff 0
ret <- msgpack_unpack str (fromIntegral len) poff z ptr
case ret of
(#const MSGPACK_UNPACK_SUCCESS) -> do
off <- peek poff
obj <- peekObject ptr
return $ Right (fromIntegral off, obj)
(#const MSGPACK_UNPACK_EXTRA_BYTES) -> do
off <- peek poff
obj <- peekObject ptr
return $ Right (fromIntegral off, obj)
(#const MSGPACK_UNPACK_CONTINUE) ->
return $ Left UnpackContinue
(#const MSGPACK_UNPACK_PARSE_ERROR) ->
return $ Left UnpackParseError
_ ->
return $ Left UnpackError
foreign import ccall "msgpack_unpack" msgpack_unpack ::
Ptr CChar -> CSize -> Ptr CSize -> Zone -> Ptr () -> IO CInt

View File

@@ -0,0 +1,101 @@
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances #-}
{-# LANGUAGE IncoherentInstances #-}
--------------------------------------------------------------------
-- |
-- Module : Data.MessagePack.Class
-- Copyright : (c) Hideyuki Tanaka, 2009
-- License : BSD3
--
-- Maintainer: tanaka.hideyuki@gmail.com
-- Stability : experimental
-- Portability: portable
--
-- Serializing Haskell values to and from MessagePack Objects.
--
--------------------------------------------------------------------
module Data.MessagePack.Class(
-- * Serialization to and from Object
OBJECT(..),
Result,
pack,
) where
import Control.Monad.Error
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as C8
import Data.MessagePack.Base
-- | The class of types serializable to and from MessagePack object
class OBJECT a where
toObject :: a -> Object
fromObject :: Object -> Result a
-- | A type for parser results
type Result a = Either String a
instance OBJECT Object where
toObject = id
fromObject = Right
fromObjectError :: String
fromObjectError = "fromObject: cannot cast"
instance OBJECT () where
toObject = const ObjectNil
fromObject ObjectNil = Right ()
fromObject _ = Left fromObjectError
instance OBJECT Int where
toObject = ObjectInteger
fromObject (ObjectInteger n) = Right n
fromObject _ = Left fromObjectError
instance OBJECT Bool where
toObject = ObjectBool
fromObject (ObjectBool b) = Right b
fromObject _ = Left fromObjectError
instance OBJECT Double where
toObject = ObjectDouble
fromObject (ObjectDouble d) = Right d
fromObject _ = Left fromObjectError
instance OBJECT ByteString where
toObject = ObjectRAW
fromObject (ObjectRAW bs) = Right bs
fromObject _ = Left fromObjectError
instance OBJECT String where
toObject = toObject . C8.pack
fromObject obj = liftM C8.unpack $ fromObject obj
instance OBJECT a => OBJECT [a] where
toObject = ObjectArray . map toObject
fromObject (ObjectArray arr) =
mapM fromObject arr
fromObject _ =
Left fromObjectError
instance (OBJECT a, OBJECT b) => OBJECT [(a, b)] where
toObject =
ObjectMap . map (\(a, b) -> (toObject a, toObject b))
fromObject (ObjectMap mem) = do
mapM (\(a, b) -> liftM2 (,) (fromObject a) (fromObject b)) mem
fromObject _ =
Left fromObjectError
instance OBJECT a => OBJECT (Maybe a) where
toObject (Just a) = toObject a
toObject Nothing = ObjectNil
fromObject ObjectNil = return Nothing
fromObject obj = liftM Just $ fromObject obj
-- | Pack a serializable Haskell value.
pack :: OBJECT a => Packer -> a -> IO ()
pack pc = packObject pc . toObject

View File

@@ -0,0 +1,62 @@
--------------------------------------------------------------------
-- |
-- Module : Data.MessagePack.Feed
-- Copyright : (c) Hideyuki Tanaka, 2009
-- License : BSD3
--
-- Maintainer: tanaka.hideyuki@gmail.com
-- Stability : experimental
-- Portability: portable
--
-- Feeders for Stream Deserializers
--
--------------------------------------------------------------------
module Data.MessagePack.Feed(
-- * Feeder type
Feeder,
-- * Feeders
feederFromHandle,
feederFromFile,
feederFromString,
) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.IORef
import System.IO
-- | Feeder returns Just ByteString when bytes remains, otherwise Nothing.
type Feeder = IO (Maybe ByteString)
-- | Feeder from Handle
feederFromHandle :: Handle -> IO Feeder
feederFromHandle h = return $ do
bs <- BS.hGetNonBlocking h bufSize
if BS.length bs > 0
then do return $ Just bs
else do
c <- BS.hGet h 1
if BS.length c > 0
then do return $ Just c
else do
hClose h
return Nothing
where
bufSize = 4096
-- | Feeder from File
feederFromFile :: FilePath -> IO Feeder
feederFromFile path =
openFile path ReadMode >>= feederFromHandle
-- | Feeder from ByteString
feederFromString :: ByteString -> IO Feeder
feederFromString bs = do
r <- newIORef (Just bs)
return $ f r
where
f r = do
mb <- readIORef r
writeIORef r Nothing
return mb

View File

@@ -0,0 +1,156 @@
--------------------------------------------------------------------
-- |
-- Module : Data.MessagePack.Monad
-- Copyright : (c) Hideyuki Tanaka, 2009
-- License : BSD3
--
-- Maintainer: tanaka.hideyuki@gmail.com
-- Stability : experimental
-- Portability: portable
--
-- Monadic Stream Serializers and Deserializers
--
--------------------------------------------------------------------
module Data.MessagePack.Monad(
-- * Classes
MonadPacker(..),
MonadUnpacker(..),
-- * Packer and Unpacker type
PackerT(..),
UnpackerT(..),
-- * Packers
packToString,
packToHandle,
packToFile,
-- * Unpackers
unpackFrom,
unpackFromString,
unpackFromHandle,
unpackFromFile,
) where
import Control.Monad
import Control.Monad.Trans
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import System.IO
import Data.MessagePack.Base hiding (Unpacker)
import qualified Data.MessagePack.Base as Base
import Data.MessagePack.Class
import Data.MessagePack.Feed
class Monad m => MonadPacker m where
-- | Serialize a object
put :: OBJECT a => a -> m ()
class Monad m => MonadUnpacker m where
-- | Deserialize a object
get :: OBJECT a => m a
-- | Serializer Type
newtype PackerT m r = PackerT { runPackerT :: Base.Packer -> m r }
instance Monad m => Monad (PackerT m) where
a >>= b =
PackerT $ \pc -> do
r <- runPackerT a pc
runPackerT (b r) pc
return r =
PackerT $ \_ -> return r
instance MonadTrans PackerT where
lift m = PackerT $ \_ -> m
instance MonadIO m => MonadIO (PackerT m) where
liftIO = lift . liftIO
instance MonadIO m => MonadPacker (PackerT m) where
put v = PackerT $ \pc -> liftIO $ do
pack pc v
-- | Execute given serializer and returns byte sequence.
packToString :: MonadIO m => PackerT m r -> m ByteString
packToString m = do
sb <- liftIO $ newSimpleBuffer
pc <- liftIO $ newPacker sb
_ <- runPackerT m pc
liftIO $ simpleBufferData sb
-- | Execute given serializer and write byte sequence to Handle.
packToHandle :: MonadIO m => Handle -> PackerT m r -> m ()
packToHandle h m = do
sb <- packToString m
liftIO $ BS.hPut h sb
liftIO $ hFlush h
-- | Execute given serializer and write byte sequence to file.
packToFile :: MonadIO m => FilePath -> PackerT m r -> m ()
packToFile p m = do
sb <- packToString m
liftIO $ BS.writeFile p sb
-- | Deserializer type
newtype UnpackerT m r = UnpackerT { runUnpackerT :: Base.Unpacker -> Feeder -> m r }
instance Monad m => Monad (UnpackerT m) where
a >>= b =
UnpackerT $ \up feed -> do
r <- runUnpackerT a up feed
runUnpackerT (b r) up feed
return r =
UnpackerT $ \_ _ -> return r
instance MonadTrans UnpackerT where
lift m = UnpackerT $ \_ _ -> m
instance MonadIO m => MonadIO (UnpackerT m) where
liftIO = lift . liftIO
instance MonadIO m => MonadUnpacker (UnpackerT m) where
get = UnpackerT $ \up feed -> liftIO $ do
executeOne up feed
obj <- unpackerData up
freeZone =<< unpackerReleaseZone up
unpackerReset up
let Right r = fromObject obj
return r
where
executeOne up feed = do
resp <- unpackerExecute up
guard $ resp>=0
when (resp==0) $ do
Just bs <- feed
unpackerFeed up bs
executeOne up feed
-- | Execute deserializer using given feeder.
unpackFrom :: MonadIO m => Feeder -> UnpackerT m r -> m r
unpackFrom f m = do
up <- liftIO $ newUnpacker defaultInitialBufferSize
runUnpackerT m up f
-- | Execute deserializer using given handle.
unpackFromHandle :: MonadIO m => Handle -> UnpackerT m r -> m r
unpackFromHandle h m =
flip unpackFrom m =<< liftIO (feederFromHandle h)
-- | Execute deserializer using given file content.
unpackFromFile :: MonadIO m => FilePath -> UnpackerT m r -> m r
unpackFromFile p m = do
h <- liftIO $ openFile p ReadMode
r <- flip unpackFrom m =<< liftIO (feederFromHandle h)
liftIO $ hClose h
return r
-- | Execute deserializer from given byte sequence.
unpackFromString :: MonadIO m => ByteString -> UnpackerT m r -> m r
unpackFromString bs m = do
flip unpackFrom m =<< liftIO (feederFromString bs)

View File

@@ -0,0 +1,82 @@
--------------------------------------------------------------------
-- |
-- Module : Data.MessagePack.Stream
-- Copyright : (c) Hideyuki Tanaka, 2009
-- License : BSD3
--
-- Maintainer: tanaka.hideyuki@gmail.com
-- Stability : experimental
-- Portability: portable
--
-- Lazy Stream Serializers and Deserializers
--
--------------------------------------------------------------------
module Data.MessagePack.Stream(
unpackObjects,
unpackObjectsFromFile,
unpackObjectsFromHandle,
unpackObjectsFromString,
) where
import Data.ByteString (ByteString)
import System.IO
import System.IO.Unsafe
import Data.MessagePack.Base
import Data.MessagePack.Feed
-- | Unpack objects using given feeder.
unpackObjects :: Feeder -> IO [Object]
unpackObjects feeder = do
up <- newUnpacker defaultInitialBufferSize
f up
where
f up = unsafeInterleaveIO $ do
mbo <- unpackOnce up
case mbo of
Just o -> do
os <- f up
return $ o:os
Nothing ->
return []
unpackOnce up = do
resp <- unpackerExecute up
case resp of
0 -> do
r <- feedOnce up
if r
then unpackOnce up
else return Nothing
1 -> do
obj <- unpackerData up
freeZone =<< unpackerReleaseZone up
unpackerReset up
return $ Just obj
_ ->
error $ "unpackerExecute fails: " ++ show resp
feedOnce up = do
dat <- feeder
case dat of
Nothing ->
return False
Just bs -> do
unpackerFeed up bs
return True
-- | Unpack objects from file.
unpackObjectsFromFile :: FilePath -> IO [Object]
unpackObjectsFromFile fname =
unpackObjects =<< feederFromFile fname
-- | Unpack objects from handle.
unpackObjectsFromHandle :: Handle -> IO [Object]
unpackObjectsFromHandle h =
unpackObjects =<< feederFromHandle h
-- | Unpack oobjects from given byte sequence.
unpackObjectsFromString :: ByteString -> IO [Object]
unpackObjectsFromString bs =
unpackObjects =<< feederFromString bs

16
haskell/test/Monad.hs Normal file
View File

@@ -0,0 +1,16 @@
import Control.Monad.Trans
import Data.MessagePack
main = do
sb <- packToString $ do
put [1,2,3::Int]
put (3.14 :: Double)
put "Hoge"
print sb
unpackFromString sb $ do
arr <- get
dbl <- get
str <- get
liftIO $ print (arr :: [Int], dbl :: Double, str :: String)

14
haskell/test/Stream.hs Normal file
View File

@@ -0,0 +1,14 @@
import Control.Applicative
import qualified Data.ByteString as BS
import Data.MessagePack
main = do
sb <- newSimpleBuffer
pc <- newPacker sb
pack pc [1,2,3::Int]
pack pc True
pack pc "hoge"
bs <- simpleBufferData sb
os <- unpackObjectsFromString bs
mapM_ print os

36
haskell/test/Test.hs Normal file
View File

@@ -0,0 +1,36 @@
import Control.Monad
import Data.MessagePack
{-
main = do
sb <- newSimpleBuffer
pc <- newPacker sb
pack pc [(1,2),(2,3),(3::Int,4::Int)]
pack pc [4,5,6::Int]
pack pc "hoge"
bs <- simpleBufferData sb
print bs
up <- newUnpacker defaultInitialBufferSize
unpackerFeed up bs
let f = do
res <- unpackerExecute up
when (res==1) $ do
obj <- unpackerData up
print obj
f
f
return ()
-}
main = do
bs <- packb [(1,2),(2,3),(3::Int,4::Int)]
print bs
dat <- unpackb bs
print (dat :: Result [(Int, Int)])

Some files were not shown because too many files have changed in this diff Show More