MPACK是MessagePack序列化格式的编码器和解码器的C实现。这是:
MPACK的核心包含一个缓冲的读取器和作家,以及一个解析动态键入节点树的树型解析器。可以启用辅助功能,可以读取预期类型的值,与文件一起工作,生长缓冲区或自动分配字符串,检查UTF-8编码等等。
MPACK代码足够小,可以直接嵌入您的代码库中。只需下载合并软件包,然后将mpack.h和mpack.c添加到您的项目中即可。
MPACK支持所有现代编译器,所有台式机和智能手机OS,WebAssembly,Linux内核内部,甚至是8位微控制器,例如Arduino。可以在编译时自定义MPACK功能集,以设置哪些功能,组件和调试检查已编译,以及可用的依赖项。
节点API将大量MessagePack数据解析为动态类型的节点的不变树。一系列的辅助功能可用于从每个节点中提取特定类型的数据。
// parse a file into a node tree
mpack_tree_t tree ;
mpack_tree_init_filename ( & tree , "homepage-example.mp" , 0 );
mpack_tree_parse ( & tree );
mpack_node_t root = mpack_tree_root ( & tree );
// extract the example data on the msgpack homepage
bool compact = mpack_node_bool ( mpack_node_map_cstr ( root , "compact" ));
int schema = mpack_node_i32 ( mpack_node_map_cstr ( root , "schema" ));
// clean up and check for errors
if ( mpack_tree_destroy ( & tree ) != mpack_ok ) {
fprintf ( stderr , "An error occurred decoding the data!n" );
return ;
}请注意,上述代码中不需要其他错误处理。如果文件丢失或损坏,则MAP键丢失了或不在预期类型中的节点,则返回特殊的“ nil”节点和false/Zero值,然后将树放置在错误状态中。仅在使用数据之前需要进行错误检查。
上面的示例自动分配节点。可以在存储器约束环境中提供固定节点池,而不是将其提供给解析器。为了获得最大的性能和最少的内存使用情况,预期API可用于解析预定义模式的数据。
写API将结构化数据编码到MessagePack。
// encode to memory buffer
char * data ;
size_t size ;
mpack_writer_t writer ;
mpack_writer_init_growable ( & writer , & data , & size );
// write the example on the msgpack homepage
mpack_build_map ( & writer );
mpack_write_cstr ( & writer , "compact" );
mpack_write_bool ( & writer , true);
mpack_write_cstr ( & writer , "schema" );
mpack_write_uint ( & writer , 0 );
mpack_complete_map ( & writer );
// finish writing
if ( mpack_writer_destroy ( & writer ) != mpack_ok ) {
fprintf ( stderr , "An error occurred encoding the data!n" );
return ;
}
// use the data
do_something_with_data ( data , size );
free ( data );在上面的示例中,我们编码为可生长的内存缓冲区。相反,作者可以写入预先分配的或堆栈分配的缓冲区(对于化合物类型具有前期尺寸),从而避免了对内存分配的需求。当缓冲区已满或完成写入时,还可以为作者提供刷新功能(例如文件或套接字写入功能)。
如果发生任何错误,作者将处于错误状态。如果编写过多的数据,编写错误的元素数量,如果发生分配失败,如果无法冲洗数据,则作者将标记错误。当作者处于错误状态时,任何后续写入都将被忽略,因此您无需检查每个写入错误。
上面的示例使用mpack_build_map()自动确定包含的键值对数。如果您可以预先知道所需的元素数量,则可以将其传递给mpack_start_map() 。在这种情况下,相应的mpack_finish_map()将在调试模式下断言实际编写了预期的元素数,这是其他MessagePack C/C ++库可能无法做到的。
MPACK具有丰富的功能,同时保持了非常高的性能和小型代码足迹。这是一个简短的功能表,将其与其他C解析器进行比较:
| mpack (v1.1) | msgpack-c (v3.3.0) | CMP (v19) | CWPACK (v1.3.1) | |
|---|---|---|---|---|
| 没有LIBC要求 | ✓ | ✓ | ✓ | |
| 可长大的记忆作者 | ✓ | ✓ | ✓* | |
| 文件I/O帮助者 | ✓ | ✓ | ✓* | |
| 状态错误处理 | ✓ | ✓ | ||
| 增量解析器 | ✓ | ✓ | ✓ | |
| 树流解析器 | ✓ | ✓ | ||
| 复合尺寸跟踪 | ✓ | |||
| 自动化合物大小 | ✓ |
这里有一个较大的功能比较表,其中包括表中各种条目的描述。
这个基准测试套件将MPACK的性能与其他示意性序列化格式的实现进行了比较。 MPACK的表现优于所有JSON和MessagePack库(CWPACK除外),在某些测试中,MPACK比Rapidjson快几倍。
从概念上讲,MessagePack与JSON类似的数据存储:它们既由简单值(例如数字和字符串)组成,并在地图和数组中层次存储。那么,为什么不改用JSON呢?主要原因是JSON被设计为可读,因此它不像二元序列化格式那样有效:
划定字符串,地图和阵列之类的复合类型,因此不能预先分配适当的存储。必须对整个对象进行解析以确定其大小。
字符串没有存储在其本地编码中。当阅读时,必须逃脱引号和后斜切之类的特殊字符。
数字特别低效率(尤其是在解析浮子时),这使JSON不合适作为包含大量数字的结构化数据的基本格式。
JSON根本不支持二进制数据。小型二进制斑点(例如图标和缩略图)必须是基础64或传递的基础。
以上问题大大增加了解码器的复杂性。功能全面的JSON解码器非常大,最小的解码器往往会忽略诸如启动和浮动解析之类的功能,而是将这些功能放在用户或平台上。这可能会导致难以找到的平台特异性和特定地点的错误,并具有更大的安全性漏洞的潜力。这也大大降低了性能,使JSON在移动游戏等应用程序中没有吸引力。
尽管可以通过减小和压缩来部分缓解JSON的空间效率低下,但性能效率低下不能。更重要的是,如果您要缩小和压缩数据,那么为什么首先使用人类可读格式呢?
MPACK构建过程不会在库中构建MPACK;它用于构建和运行单元测试。您无需构建MPACK或单元测试套件即可使用MPACK。
有关如何测试MPACK的信息,请参见test/readme.md。