msgpack::packer

Supported types

msgpack::packer 将任何数据打包成 msgpack 格式。目前支持以下格式:

https://github.com/msgpack/msgpack-c/tree/cpp_master/include/msgpack/adaptor

此外,您可以打包 msgpack::object。

您可以添加您的适配器类模板特化来支持打包那些包含您想要打包的类型的对象。

重载声明:

#include <msgpack.hpp>

namespace msgpack {
MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) {
namespace adaptor {

template <>
struct pack<the_type_you_want_to_pack> {
    template <typename Stream>
    msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, the_type_you_want_to_pack const& v) const {
        // packing implementation.
        // o.pack_???(v.???);
        return o;
    }
};
} // namespace adaptor
} // MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS)
} // namespace msgpack

您可以在pack实现中调用packer的打包成员函数。请参阅手动打包

另请参阅适配器(adaptor)

Buffer

您可以使用任何具有以下成员函数的类:

write(const char*, std::size_t);

在 C++ 标准库中,std::stringstream 有它。

std::tuple<int, bool, std::string> src(1, true, "example");
std::stringstream buffer;
msgpack::pack(buffer, src); // calls std::stringstream::write internally.

msgpack 提供了多种类型的缓冲区:

sbuffer

sbuffer 是简单的缓冲区。它在内部使用 malloc、free 和 realloc。当调用 msgpack::pack 时,src 被复制到缓冲区。 realloc 比新建、复制和删除操作更快。

vrefbuffer

vrefbuffer 是一种参考缓冲区。当调用 msgpack::pack 时,缓冲区可能会引用 src。所以你可以避免复制,但你需要保留 src 对象,直到缓冲区的提升时间结束。

vrefbuffer 有一个名为 m_ref_size 的阈值。如果序列化的 src 对象的大小大于或等于阈值,则引用该对象。

vrefbuffer.hpp

    void write(const char* buf, size_t len)
    {
        if(len < m_ref_size) {
            append_copy(buf, len);
        } else {
            append_ref(buf, len);
        }
    }
#ifndef MSGPACK_VREFBUFFER_REF_SIZE
#define MSGPACK_VREFBUFFER_REF_SIZE 32
#endif

#ifndef MSGPACK_VREFBUFFER_CHUNK_SIZE
#define MSGPACK_VREFBUFFER_CHUNK_SIZE 8192
#endif

namespace detail {
    // int64, uint64, double
    std::size_t const packer_max_buffer_size = 9;
} // detail

class vrefbuffer {
public:
    // ref_size is stored to m_ref_size
    vrefbuffer(size_t ref_size = MSGPACK_VREFBUFFER_REF_SIZE,
               size_t chunk_size = MSGPACK_VREFBUFFER_CHUNK_SIZE)
        :m_ref_size(std::max(ref_size, detail::packer_max_buffer_size + 1)),
         m_chunk_size(chunk_size)
    {
        ...
    }
};

你可以在构造函数上传递阈值大小,但是如果你给的 ref_size 小于 10,vrefbuffer::ref_size,实际的阈值应该是 10。因为 msgpack 格式固定对象的最大大小是 9,它们的缓冲区是在栈上分配如下:

pack.hpp

template <typename Stream>
inline packer<Stream>& packer<Stream>::pack_fix_int64(int64_t d)
{
    char buf[9];
    buf[0] = static_cast<char>(0xd3); _msgpack_store64(&buf[1], d);
    append_buffer(buf, 9);
    return *this;
    // buf's lifetime is finished, so can't use vrefbuffer::append_ref()
}

zbuffer

zbuffer的内容是使用 zlib 压缩的。

fbuffer

fbuffer 的内容使用 c 风格的 FILE*存储到文件中。

pack

如果要打包数据,请调用 pack()。第一个参数是缓冲区,第二个参数是要打包的值。您可以传递任何支持的类型

template <typename Stream, typename T>
inline void pack(Stream& s, const T& v);

pack manually(手动)

您也可以手动打包。请参见以下示例:

msgpack::sbuffer sbuf;
msgpack::packer<msgpack::sbuffer> packer(sbuf);
char c[] = { 1, 2, 3, 4, 5, 6 };
packer.pack_bin(sizeof(c));         // pack header and size
packer.pack_bin_body(c, sizeof(c)); // pack payload

msgpack::packer 提供以下手动打包功能。当您通过 operator<< (packer& o, const the_type_you_want_to_pack& v) 实现自定义类型支持时,通常会使用这些函数。当然,您可以直接在应用程序中使用解包功能。

class packer {
public:
    packer<Stream>& pack_uint8(uint8_t d);
    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(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_fix_uint8(uint8_t d);
    packer<Stream>& pack_fix_uint16(uint16_t d);
    packer<Stream>& pack_fix_uint32(uint32_t d);
    packer<Stream>& pack_fix_uint64(uint64_t d);
    packer<Stream>& pack_fix_int8(int8_t d);
    packer<Stream>& pack_fix_int16(int16_t d);
    packer<Stream>& pack_fix_int32(int32_t d);
    packer<Stream>& pack_fix_int64(int64_t d);

    packer<Stream>& pack_char(char d);
    packer<Stream>& pack_signed_char(signed char 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);
    packer<Stream>& pack_unsigned_char(unsigned char d);
    packer<Stream>& pack_unsigned_short(unsigned short d);
    packer<Stream>& pack_unsigned_int(unsigned int d);
    packer<Stream>& pack_unsigned_long(unsigned long d);
    packer<Stream>& pack_unsigned_long_long(unsigned long long d);

    packer<Stream>& pack_float(float d);
    packer<Stream>& pack_double(double d);

    packer<Stream>& pack_nil();
    packer<Stream>& pack_true();
    packer<Stream>& pack_false();

    packer<Stream>& pack_array(size_t n);

    packer<Stream>& pack_map(size_t n);

    packer<Stream>& pack_str(size_t l);
    packer<Stream>& pack_str_body(const char* b, size_t l);

    packer<Stream>& pack_bin(size_t l);
    packer<Stream>& pack_bin_body(const char* b, size_t l);

    packer<Stream>& pack_ext(size_t l, int8_t type);
    packer<Stream>& pack_ext_body(const char* b, size_t l);
};

packing classes

msgpack 提供了一个方便的宏来让你的类适应pack函数。

class my_class {
public:
    std::string value;
    int i;
    MSGPACK_DEFINE(value, i); // write the member variables that you want to pack
};

如果类有 MSGPACK_DEFINE() 宏,则可以打包类,可以将类转换为 msgpack::object,也可以将 msgpack::object 转换为类。

packing enums

msgpack 提供了一个方便的宏来使枚举变量适应pack函数。当你要打包的类有枚举成员变量时,你需要告诉msgpack你要打包的是哪个枚举类型。

#include <msgpack.hpp>

class TestEnumMemberClass
{
public:
  TestEnumMemberClass()
    : t1(STATE_A), t2(STATE_B), t3(STATE_C) {}

  enum TestEnumType {
    STATE_INVALID = 0,
    STATE_A = 1,
    STATE_B = 2,
    STATE_C = 3
  };
  TestEnumType t1;
  TestEnumType t2;
  TestEnumType t3;

  MSGPACK_DEFINE(t1, t2, t3);
};

// This macro should be written in the global namespace
MSGPACK_ADD_ENUM(TestEnumMemberClass::TestEnumType);

// ...
// pack enums

在 MSGPACK_ADD_ENUM() 定义之后,就可以pack枚举类型了。

请参阅示例

另请参阅 适配器

Q.E.D.