C/C++のMessagePackライブラリMPackを使う

はじめに

MessagePackはオブジェクトシリアライズ用の軽量なバイナリフォーマットです。
テキストフォーマットであるJSONの代わりに用いられることが多く、ソケット通信やファイル記録など使用することができます。

C/C++向けのMessagePackライブラリはいくつか存在しますが、今回はMPackを紹介したいと思います。

github.com

Mpackは次の特徴があります。

使い方

使い方については基本的にはGitHubのREADME.mdに書かれていますが、ゼロアロケーションで使う方法を備忘録的に書き残します。

サンプルコード

#include <stdio.h>
#include <memory>
#include <array>
#include <string_view>
#include <iostream>
#include <iomanip>
#include "mpack/mpack.h"

int main()
{
    std::array<uint8_t, 1024> buffer;

    {
        printf("Writing MsgPack.\n");

        // ライター初期化
        mpack_writer_t writer;
        mpack_writer_init(&writer, (char*)buffer.data(), buffer.size());

        // 整数書き出し
        mpack_write_uint(&writer, 123);

        // 実数書き出し
        mpack_write_float(&writer, 1.23f);

        // ブール値書き出し
        mpack_write_bool(&writer, true);

        // 文字列書き出し
        mpack_write_cstr(&writer, "hogehoge");

        // 配列書き出し
        mpack_start_array(&writer, 3);
        for (size_t i = 0; i < 3; i++) {
            mpack_write_uint(&writer, i);
        }
        mpack_finish_array(&writer);

        // 連想配列書き出し
        mpack_start_map(&writer, 3);
        for (size_t i = 0; i < 3; i++) {
            static const char* names[] = {"foo", "bar", "baz"};
            mpack_write_cstr(&writer, names[i]);
            mpack_write_uint(&writer, i);
        }
        mpack_finish_map(&writer);

        // 出力データサイズ
        size_t outputSize = mpack_writer_buffer_used(&writer);

        // 書き出し終了
        mpack_writer_destroy(&writer);

        // バイナリ表示
        std::cout << std::hex;
        for (size_t i = 0; i < outputSize; i++) {
            std::cout << std::setfill('0') << std::setw(2) << (int)buffer[i] << " ";
        }
        std::cout << std::dec << std::endl;
    }

    {
        printf("Reading MsgPack.\n");

        // リーダー初期化
        mpack_reader_t reader;
        mpack_reader_init_data(&reader, (const char*)buffer.data(), buffer.size());

        // 整数読み出し
        mpack_tag_t intTag = mpack_read_tag(&reader);
        std::cout << mpack_tag_uint_value(&intTag) << std::endl;

        // 実数読み出し
        mpack_tag_t floatTag = mpack_read_tag(&reader);
        std::cout << mpack_tag_float_value(&floatTag) << std::endl;

        // ブール値読み出し
        mpack_tag_t boolTag = mpack_read_tag(&reader);
        std::cout << std::boolalpha << mpack_tag_bool_value(&boolTag) << std::endl;

        // 文字列読み出し
        mpack_tag_t strTag = mpack_read_tag(&reader);
        size_t strSize =  mpack_tag_str_length(&strTag);
        std::string_view str(mpack_read_bytes_inplace(&reader, strSize), strSize);
        std::cout << str << std::endl;
        mpack_done_str(&reader);

        // 配列読み出し
        mpack_tag_t arrayTag = mpack_read_tag(&reader);
        size_t arraySize = mpack_tag_array_count(&arrayTag);
        std::cout << "[";
        for (size_t i = 0; i < arraySize; i++) {
            if (i > 0) std::cout << ", ";

            mpack_tag_t intTag = mpack_read_tag(&reader);
            std::cout << mpack_tag_uint_value(&intTag);
        }
        std::cout << "]" << std::endl;
        mpack_done_array(&reader);

        // 連想配列読み出し
        mpack_tag_t mapTag = mpack_read_tag(&reader);
        size_t mapSize = mpack_tag_map_count(&mapTag);
        std::cout << "{";
        for (size_t i = 0; i < mapSize; i++) {
            if (i > 0) std::cout << ", ";

            mpack_tag_t strTag = mpack_read_tag(&reader);
            size_t strSize =  mpack_tag_str_length(&strTag);
            std::string_view str(mpack_read_bytes_inplace(&reader, strSize), strSize);
            std::cout << str << ":";
            mpack_done_str(&reader);

            mpack_tag_t intTag = mpack_read_tag(&reader);
            std::cout << mpack_tag_uint_value(&intTag);
        }
        std::cout << "}" << std::endl;
        mpack_done_map(&reader);

        // 読み出し終了
        mpack_reader_destroy(&reader);
    }

    return 0;
}

出力

Writing MsgPack.
7b ca 3f 9d 70 a4 c3 a8 68 6f 67 65 68 6f 67 65 93 00 01 02 83 a3 66 6f 6f 00 a3 62 61 72 01 a3 62 61 7a 02
Reading MsgPack.
123
1.23
true
hogehoge
[0, 1, 2]
{foo:0, bar:1, baz:2}