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。