【messagePack官网】:序列化

【GitHub】:msgpack for C/C++

1、msgpack 静态库编译

TIMESTAMP序列化问题 msgpack序列化_TIMESTAMP序列化问题

1、msgpack 项目源码下载 github地址2、cmake 编译配置工具下载 官网地址3、cmake 构建工程【configer—>generate】
4、VS 打开 msgpack.sln,编译生成静态库【msgpackc.lib、msgpackc_import.lib】

2、调用 msgpack 静态库

C++ 样例代码:

#include <msgpack.hpp>
#include <string>
#include <iostream>
#include <sstream>

int main(void)
{
    msgpack::type::tuple<int, bool, std::string> src(1, true, "example");

    // serialize the object into the buffer.
    // any classes that implements write(const char*,size_t) can be a buffer.
    std::stringstream buffer;	   // 已实现write(const char*,size_t)
    msgpack::pack(buffer, src);    // src不受限制的联合

    // send the buffer ...
    buffer.seekg(0);

    // deserialize the buffer into msgpack::object instance.
    std::string str(buffer.str());

    msgpack::object_handle oh =    // 反序列化成实例
        msgpack::unpack(str.data(), str.size());

    // deserialized object is valid during the msgpack::object_handle instance is alive.
    msgpack::object deserialized = oh.get();

    // msgpack::object supports ostream.
    std::cout << deserialized << std::endl;

    // convert msgpack::object instance into the original type.
    // if the type is mismatched, it throws msgpack::type_error exception.
    msgpack::type::tuple<int, bool, std::string> dst;
    deserialized.convert(dst);		// 将msgpack :: object实例转成原始类型, 失败报msgpack :: type_error异常

    // or create the new instance
    msgpack::type::tuple<int, bool, std::string> dst2 =		// 创建新实例
        deserialized.as<msgpack::type::tuple<int, bool, std::string> >();

    return 0;
}

3、msgpack 基础教程

msgpack 查版本:【GitHub】:v2_0_cpp_tutorial

#include <iostream>
#include <msgpack.hpp>

int main() {
    std::cout << MSGPACK_VERSION << std::endl;
}

打包字符串"compact":【在线编译】

#include <iostream>
#include <sstream>
#include <msgpack.hpp>

// hex_dump is not a part of msgpack-c. 
inline std::ostream& hex_dump(std::ostream& o, std::string const& v) {
    std::ios::fmtflags f(o.flags());
    o << std::hex;
    for (auto c : v) {
        o << "0x" << std::setw(2) << std::setfill('0') << (static_cast<int>(c) & 0xff) << ' ';
    }
    o.flags(f);
    return o;
}

int main() {
    std::stringstream ss;
    msgpack::pack(ss, "compact");
    hex_dump(std::cout, ss.str()) << std::endl;
}

// --------------------------------------------------
0xa7 0x63 0x6f 0x6d 0x70 0x61 0x63 0x74 
  |   'c'  'o'  'm'  'p'  'a'  'c'  't'
  |
  7 bytes string

打包数组,如std::vector:【在线编译】

int main() {
    std::stringstream ss;
    std::vector<int> v { 1, 5, 8, 2, 6 };
    msgpack::pack(ss, v);
    hex_dump(std::cout, ss.str()) << std::endl;
}

// --------------------------------------------------
0x95 0x01 0x05 0x08 0x02 0x06 
  |     1    5    8    2    6
  |
  5 length array

打包映射,如std::map:【在线编译】

nt main() {
    std::stringstream ss;
    std::map<std::string, int> v { { "ABC", 5 }, { "DEFG", 2 } };
    msgpack::pack(ss, v);
    hex_dump(std::cout, ss.str()) << std::endl;
}

// --------------------------------------------------
0x82 0xa3 0x41 0x42 0x43 0x05 0xa4 0x44 0x45 0x46 0x47 0x02 
  |    |   'A'  'B'  'C'    5   |   'D'  'E'  'F'  'G'    2  
  |    |                        |
  |    |                        |
  |    3 bytes string           4 bytes string
  |
  |    [    key        ] [val]  [     key            ] [val]
  |    [    element 1        ]  [     element 2            ]
2 length map

4、msgpack打包:pack、packer

支持类型:msgpack wiki序列化:应用对象 --> msgpack类型系统 --> msgpack格式【字节数组】,反序列化则反序
可添加适配器类模板 以特殊支持 打包自定义类型对象:

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

缓冲:只要实现write(const char*, std::size_t) 成员函数,即可作缓冲用

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

msgpack四种缓冲区:
  1、zbuffer:内容用zlib压缩
  2、fbuffer:内容用c风格文件指针存到文件中
  3、sbuffer:普通缓冲区,调malloc、free和realloc,调msgpack::pack复制src
  4、vrefbuffer:引用缓冲区,调msgpack::pack可能复制src,因src超阈值则引用而非拷贝,故应注意保留src

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)),    // 最小10
        m_chunk_size(chunk_size)
    {
        ...
    }
};

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()
}

打包:调pack,传缓冲区和打包对象

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

手动打包:

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

当通过operator <<(packer&o,const T&v) 实现自定义类型时,通常会用这些函数手动打包

class packer {
public:
    packer<Stream>& pack_uint8(uint8_t d);
    packer<Stream>& pack_uint16(uint16_t d);
    // ...uint32、uint64、int8、int16、int32、int64

    packer<Stream>& pack_fix_uint8(uint8_t d);
    packer<Stream>& pack_fix_uint16(uint16_t d);
    // ...uint32、uint64、int8、int16、int32、int64

    packer<Stream>& pack_char(char d);
    packer<Stream>& pack_signed_char(signed char d);
    // ...short、int、long、long long
    // unsigned char、unsigned short、unsigned int、unsigned long、unsigned long long

    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);
	// ...bin、ext
};

类设置成可被打包【MSGPACK_DEFINE 侵入式设置】

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

枚举变量设置成可被打包

#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

5、msgpack解包:unpack、unpacker

msgpack提供两种解压缩:1、在客户端控制缓冲区时使用 2、在客户端不想控制缓冲区时使用
访问解压缩的数据:msgpack wiki

// 解包时,传msgpack :: object_handle作参数
class object_handle 
{
public:
    object_handle();
    const object& get() const;	// msgpack::object 构造和拷贝都是浅拷贝
    msgpack::unique_ptr<msgpack::zone>& zone();	// msgpack :: zone 内部缓冲区构造了 msgpack::object
};

void some_function(const char* data, std::size_t len) 
{
    // Default construct msgpack::object_handle
    msgpack::object_handle result;

    // Pass the msgpack::object_handle
    unpack(result, data, len);
    // Get msgpack::object from msgpack::object_handle (shallow copy)
    msgpack::object obj(result.get());
    // Get msgpack::zone from msgpack::object_handle (move)
    msgpack::unique_ptr<msgpack::zone> z(result.zone());
    ...
}

msgpack::object_handle管理msgpack::object的生存期,需注意前者销毁则后者成悬空引用

msgpack::object_handle some_function(const char* data, std::size_t len) 
{
    // Default construct msgpack::object_handle
    msgpack::object_handle result;

    // Pass the msgpack::object_handle
    unpack(result, data, len);	// 可控制data缓冲区, 而调unpacker::next()时, 缓冲区是unpacker的内部缓冲区
    return result;		// 函数外调msgpack::object, 需确保 msgpack::object_handle 存在
}

void foo() 
{
    ...
    msgpack::object_handle handle = some_function(data, len);	
    // Use object
    msgpack::object obj = handle.get();

客户端控制一缓冲区:若客户端已准备 含msgpack格式数据 的缓冲区,则使用:

// simple (since C++11)
object_handle unpack(
	const char* data, 
	std::size_t len,
    unpack_reference_func f = nullptr,
    void* user_data = nullptr,
    unpack_limit const& limit = unpack_limit());

// get referenced information (since C++11)
object_handle unpack(..., bool& referenced, ...);    // 前二参数和后三参数同上

// set and get offset information (since C++11)
object_handle unpack(..., std::size_t& off, ...);    // 前二参数和后三参数同上

// get referenced information
// set and get offset information
//  (since C++11)
object_handle unpack(..., std::size_t& off, bool& referenced, ...);    // 前二参数和后三参数同上

// --------------------------------------------------

// simple
void unpack(
	object_handle& result, 
	const char* data, 
	std::size_t len,
    unpack_reference_func f = nullptr,
    void* user_data = nullptr,
    unpack_limit const& limit = unpack_limit());

// get referenced information
void unpack(..., bool& referenced, ...);    // 前三数和后三参数同上

// set and get offset information
void unpack(..., std::size_t& off, ...);    // 前三数和后三参数同上

// get referenced information
// set and get offset information
void unpack(..., std::size_t& off, bool& referenced, ...);    // 前三数和后三参数同上

若缓冲区只含一个msgpack数据:

object_handle result;
const char* data = ...
std::size_t len = ...

unpack(result, data, len);
result = unpack(data, len); // since C++11

若缓冲区含多个msgpack数据,按偏移取一数据:

object_handle result;
const char* data = ...
std::size_t len = ...
std::size_t off = ...
unpack(result, data, len, off);
result = unpack(data, len, off); // since C++11

若缓冲区含msgpack数据数量确定:

void some_function(const char* buffer, std::size_t len)
{
    msgpack::object_handle result1;
    msgpack::object_handle result2;
    msgpack::object_handle result3;
    std::size_t off = 0;

    // Unpack the first msgpack data.
    // off is updated when function is returned.
    unpack(result1, buffer, len, off);
    // Unpack the second msgpack data.
    // off is updated when function is returned.
    unpack(result2, buffer, len, off);
    // Unpack the third msgpack data.
    // off is updated when function is returned.
    unpack(result3, buffer, len, off);
    assert(len == off);
    ...
}

若缓冲区含msgpack数据数量不确定,但数据已完成:

void some_function(const char* buffer, std::size_t len) 
{
    std::size_t off = 0;

    while (off != len) 
    {
        msgpack::object_handle result;
        unpack(result, buffer, len, off);
        msgpack::object obj(result.get());
        // Use obj
    }
}

调msgpack::unpack抛异常情况:
  1、缓冲区msgpack数据格式无效
  2、从off开始的缓冲区含不完整的msgpack数据
若客户端可能会获取 不完整 的msgpack数据,则可调 msgpack::unpacker


限制解压元素数量【传给unpack】:

class unpack_limit {
public:
    unpack_limit(
        std::size_t array = 0xffffffff,
        std::size_t map = 0xffffffff,
        //  ...str、bin、ext、depth
    );
    std::size_t array() const;
    std::size_t map() const;
    // ...str、bin、ext、depth
};

默认为0xffffffff,是msgpack格式最大值【实际深度限制非格式定义】,若元素数超,则引发异常:

struct size_overflow : public unpack_error {
};

struct array_size_overflow : public size_overflow {
};
struct map_size_overflow : public size_overflow {
};
//  ...str、bin、ext、depth

内存管理: 在缓冲区中msgpack数据,默认情况下,均将拷到msgpack::zone中, 故可在解压后释放缓冲区

TIMESTAMP序列化问题 msgpack序列化_TIMESTAMP序列化问题_02

可自定义unpack_reference_func,当STR、BIN和EXT解压时,将调该函数

// 返true,则对应msgpack::object指向缓冲区, 需确保缓冲区在对象销毁前均有效
// 返false,则msgpack::object指向从缓冲区复制的msgpack :: zone上的STR、BIN和EXT有效负载
typedef bool (*unpack_reference_func)(type::object_type type, std::size_t length, void* user_data);

namespace type {
    enum object_type {
        NIL = MSGPACK_OBJECT_NIL,
        BOOLEAN = MSGPACK_OBJECT_BOOLEAN,
        POSITIVE_INTEGER = MSGPACK_OBJECT_POSITIVE_INTEGER,
        NEGATIVE_INTEGER = MSGPACK_OBJECT_NEGATIVE_INTEGER,
        DOUBLE = MSGPACK_OBJECT_DOUBLE,
        STR = MSGPACK_OBJECT_STR,
        BIN = MSGPACK_OBJECT_BIN,
        ARRAY = MSGPACK_OBJECT_ARRAY,
        MAP = MSGPACK_OBJECT_MAP,
        EXT = MSGPACK_OBJECT_EXT
    };
}

可将STR,BIN和EXT作类型参数,但 其他类型永不会出现,因具有其他类型的msgpack :: object是通过转换创建
有效负载大小:STR或BIN,=实际数据大小;EXT,=EXT的类型+数据大小

// unpack_reference_func示例实现
// 自定义目的:在可以预期接收到msgpack数据模式时控制内存消耗的峰值
bool my_reference_func(type::object_type type, std::size_t length, void* user_data)
{
    switch (type)
    {
    case: type::STR :	// Small strings are copied.
        if (length < 32) return false;
        break;
    case: type::BIN :	// BIN is always copied.
        return false;
    case: type::EXT :	// fixext's are copied.
        switch (length)
        {
        case  1 + 1:
        case  2 + 1:
        case  4 + 1:
        case  8 + 1:
        case 16 + 1:
            return false;
        }
        break;
    default:
        assert(false);
    }
    // otherwise referenced.
    return true;
}

当字符串等于或大于32bytes时,则内存布局:

TIMESTAMP序列化问题 msgpack序列化_#include_03


可获知解压后的msgpack :: object是否引用缓冲区:

// get referenced information
void unpack(
    object_handle& result,
    const char* data,
    std::size_t len,
    bool& referenced,	// 判断是否引用
    unpack_reference_func f = nullptr,
    void* user_data = nullptr,
    unpack_limit const& limit = unpack_limit());

// get referenced information
// set and get offset information
void unpack(
    object_handle& result,
    const char* data,
    std::size_t len,
    std::size_t& off,
    bool& referenced,	// 判断是否引用
    unpack_reference_func f = nullptr,
    void* user_data = nullptr,
    unpack_limit const& limit = unpack_limit());

控制缓冲区:msgpack提供msgpack::unpacker管理缓冲区
msgpack::unpacker适用情况:
  1、msgpack数据被切碎,客户端不知道何时完成【开发流应用程序】
  2、需要在不进行仔细内存管理的情况下,最大程度地减少复制操作

// msgpack::unpacker的基本【非全部】接口: 
#ifndef MSGPACK_UNPACKER_INIT_BUFFER_SIZE
#define MSGPACK_UNPACKER_INIT_BUFFER_SIZE (64*1024)
#endif

#ifndef MSGPACK_UNPACKER_RESERVE_SIZE
#define MSGPACK_UNPACKER_RESERVE_SIZE (32*1024)
#endif

class unpacker 
{
public:
    unpacker(unpack_reference_func f = &unpacker::default_reference_func,
        void* user_data = nullptr,
        std::size_t init_buffer_size = MSGPACK_UNPACKER_INIT_BUFFER_SIZE,
        unpack_limit const& limit = unpack_limit());
    void reserve_buffer(std::size_t size = MSGPACK_UNPACKER_RESERVE_SIZE);
    char* buffer();
    void buffer_consumed(std::size_t size);
    bool next(object_handle& result);
};

msgpack::unpacker基本模式:

// The size may decided by receive performance, transmit layer's protocol and so on.
std::size_t const try_read_size = 100;	// 可由接收性能和传输层协议等决定

msgpack::unpacker unp;

// Message receive loop
while (/* block until input becomes readable */) 
{
    unp.reserve_buffer(try_read_size);
    // unp has at least try_read_size buffer on this point.

    // input is a kind of I/O library object.
    // read message to msgpack::unpacker's internal buffer directly.
    std::size_t actual_read_size = input.readsome(unp.buffer(), try_read_size);

    // tell msgpack::unpacker actual consumed size.
    unp.buffer_consumed(actual_read_size);

    msgpack::object_handle result;
    // Message pack data loop
    while (unp.next(result)) 	// 处理消息正确且完整, 返true
    {
        msgpack::object obj(result.get());
        // Use obj
    }
    // All complete msgpack message is proccessed at this point,
    // then continue to read addtional message.
}

当消息含STR,BIN或EXT数据时,默认不复制:

inline bool unpacker::default_reference_func(type::object_type type, uint64_t len, void*)
{
    return true;
}

缓冲区生存期由 zone的finalizer_array 和 msgpack::unpacker的引用计数机制 控制【使用引用无需特地控制缓冲区生存期】

// 大多数情况下,不需要使用next()的该版本,因引用的内存是由拆包器管理
bool next(object_handle& result, bool& referenced);

TIMESTAMP序列化问题 msgpack序列化_ios_04

6、msgpack访问:visitor

visitor可更直接地访问msgpack格式的字节【似用于XML的SAX API】
可自定义visitor传给 parse(),迭代解析时,遇msgpack元素,则调visitor相应函数:msgpack wiki

struct visitor {
    bool visit_nil();
    bool visit_boolean(bool v);
    bool visit_positive_integer(uint64_t v);
    bool visit_negative_integer(int64_t v);
    bool visit_float32(float v);
    bool visit_float64(double v);
    bool visit_str(const char* v, uint32_t size);
    bool visit_bin(const char* v, uint32_t size);
    bool visit_ext(const char* v, uint32_t size);
    
    bool start_array(uint32_t num_elements);	//数组、数组项, 开始/结束解析
    bool start_array_item();
    bool end_array_item();
    bool end_array();
    
    bool start_map(uint32_t num_kv_pairs);		//映射、映射关键字、映射值, 开始/结束解析
    bool start_map_key();
    bool end_map_key();
    bool start_map_value();
    bool end_map_value();
    bool end_map();
    
    // 当发生解析错误时调用时被调
    void parse_error(size_t parsed_offset, size_t error_offset);	
    // 当缓冲区包含的字节不足以构建完整的msgpack
    void insufficient_bytes(size_t parsed_offset, size_t error_offset);
    bool referenced() const; // Only when you want to use the visitor with a parser
};

visitor须实现所有函数,若只想实现几个,则可继承msgpack :: null_visitor【返true意味着继续解包】

struct null_visitor {
    bool visit_nil() {
        return true;
    }
    bool visit_boolean(bool /*v*/) {
        return true;
    }
    // ...其余函数返回类型为 bool的均返true, void的均为空
};

将msgpack格式化的字节转换为类似JSON的结构的示例:

// 忽略字符串转义,非想证明重点
struct json_like_visitor : msgpack::v2::null_visitor {
    json_like_visitor(std::string& s):m_s(s) {}

    bool visit_nil() {
        m_s += "null";
        return true;
    }
    bool visit_boolean(bool v) {
        if (v) m_s += "true";
        else m_s += "false";
        return true;
    }
    bool visit_positive_integer(uint64_t v) {
        std::stringstream ss;
        ss << v;
        m_s += ss.str();
        return true;
    }
    bool visit_negative_integer(int64_t v) {
        std::stringstream ss;
        ss << v;
        m_s += ss.str();
        return true;
    }
    bool visit_str(const char* v, uint32_t size) {
        m_s += '"' + std::string(v, size) + '"';
        return true;
    }
    bool start_array(uint32_t /*num_elements*/) {
        m_s += "[";
        return true;
    }
    bool end_array_item() {
        m_s += ",";
        return true;
    }
    bool end_array() {
        m_s.erase(m_s.size() - 1, 1); // remove the last ','
        m_s += "]";
        return true;
    }
    bool start_map(uint32_t /*num_kv_pairs*/) {
        m_s += "{";
        return true;
    }
    bool end_map_key() {
        m_s += ":";
        return true;
    }
    bool end_map_value() {
        m_s += ",";
        return true;
    }
    bool end_map() {
        m_s.erase(m_s.size() - 1, 1); // remove the last ','
        m_s += "}";
        return true;
    }
    void parse_error(size_t /*parsed_offset*/, size_t /*error_offset*/) {
        // report error.
    }
    void insufficient_bytes(size_t /*parsed_offset*/, size_t /*error_offset*/) {
        // report error.
    }
    std::string& m_s;
};

int main()
{
    std::stringstream ss;
    msgpack::packer<std::stringstream> p(ss);
    p.pack_map(1);
    p.pack("key");
    p.pack_array(3);
    p.pack(42);
    p.pack_nil();
    p.pack(true);

    std::string json_like;
    json_like_visitor v(json_like);
    std::size_t off = 0;
    std::string const& str = ss.str();
    bool ret = msgpack::v2::parse(str.data(), str.size(), off, v);
    assert(ret);
    assert("{\"key\":[42,null,true]}" == json_like);
}

parse api,传visitor引用:

// unpacker类似,其中visit返false,则parse返false
template <typename Visitor>
bool parse(const char* data, size_t len, size_t& off, Visitor& v);
template <typename Visitor>
bool parse(const char* data, size_t len, Visitor& v);

可将visitor与流接口一起使用:

template <typename VisitorHolder, typename ReferencedBufferHook>
class parser

VisitorHolder需实现visitor(),返回访问者对象引用;
ReferencedBufferHook需实现operator()(char *),仅当满足以下所有条件时,当前缓冲区指针才可调operator():
  1、parser::reserve_buffer(std :: size_t)已经调用
  2、当前缓冲区空间不足,需要分配新的缓冲区
  3、当前缓冲区已被visitor引用,在此情况下,visitor::referenced()应返true

若visitor::referenced()返true,则parser不会释放当前缓冲区,而是调ReferencedBufferHook【有机会设置清理功能】

parser较unpacker特殊处 bool next():

// unpacker
bool next(msgpack::object_handle& result, bool& referenced);	
bool next(msgpack::object_handle& result);
// parser
bool next();	// 调next解析MessagePack格式化的数据时, 便调了visitor

6、msgpack对象:object

msgpack::object的内部类型与msgpack格式相对应,其属复合结构: msgpack wiki

TIMESTAMP序列化问题 msgpack序列化_TIMESTAMP序列化问题_05


当msgpack :: object的类型为str、bin或ext时,可能有对外部的引用

TIMESTAMP序列化问题 msgpack序列化_API_06


msgpack::object_handle【可视为智能指针】将管理所有内存:

  1、使用msgpack::unpacker

  2、使用不带unpack_referenc_func的msgpack::unpack() 【若带且返true,则须确保传递引用的生存期长于object_handle】


解压转换类型【自定义转换类型 链接1链接2】:

TIMESTAMP序列化问题 msgpack序列化_ios_07

template <typename T>
object(const T& v, zone& z);

// 构建时需传zone,数据会拷贝至其中,但调msgpack::type::raw_ref将传引用,不拷贝
msgpack::object obj(msgpack::type::raw_ref(data, size), zone);

7、msgpack适配器:adaptor

将各类型对象压缩到msgpack::object,或相反操作,均需适配器:msgpack wiki当适配器用于boost容器时,需定义MSGPACK_USE_BOOST

自定义适配器【类】:
侵入式:类中定义MSGPACK_DEFINE

macro

msgpack::object type

note

MSGPACK_DEFINE

array or map *3

MSGPACK_DEFINE_ARRAY

array

since 1.2.0

MSGPACK_DEFINE_MAP

map since

since 1.2.0

// 定义MSGPACK_USE_DEFINE_MAP时, MSGPACK_DEFINE适用于数组, 否则适用于映射
#include <msgpack.hpp>

struct your_class 
{
	int a;
	std::string b;
    MSGPACK_DEFINE(a, b);	// MSGPACK_DEFINE使类可打包, 与msgpack::object互转
};

// ...

// 假设a=42,b=“ ABC”,序列化如下:
// array
[42,"ABC"]
// map (MSGPACK_USE_DEFINE_MAP is defined)
{"a":42,"b":"ABC"}		// 使用json理解,实际情况是msgpack格式

当使用基类调整类时,用MSGPACK_BASE宏:

macro

msgpack::object type

MSGPACK_BASE

array or map *4

MSGPACK_BASE_ARRAY

array

MSGPACK_BASE_MAP

map

#include <msgpack.hpp>
struct base1 
{
	int a;
	MSGPACK_DEFINE(a);	
};

struct base2 
{
	int a;
	MSGPACK_DEFINE(a);
};

// 定义MSGPACK_USE_DEFINE_MAP时, MSGPACK_BASE适用于数组, 否则适用于映射
struct your_class : base1, base2 
{
	int a;
    std::string b;
    // You can choose any order. It is represented to the msgpack array elements order.
    MSGPACK_DEFINE(b, MSGPACK_BASE(base2), a, MSGPACK_BASE(base1));	
};

// ...

// 当用MSGPACK_BASE_MAP时, 键是基类名称的STR
// MSGPACK_DEFINE_ARRAY, key顺序依据加入顺序; MSGPACK_DEFINE_MAP, key顺序依据名称顺序

// array
["ABC",[2],42,[1]]
// map (MSGPACK_USE_DEFINE_MAP is defined)
{"b":"ABC","base2":{"a":2},"a":42,"base1":{"a":1}}

可用MSGPACK_NVP自定义映射键的名称:

#include <msgpack.hpp>

struct your_class 
{
    int a;
    std::string b;
    MSGPACK_DEFINE_MAP(a, MSGPACK_NVP("#b", b));
};

{"a":42,"#b":"ABC"}

非侵入式:特例化模板

// convert: msgpack::object 转至 T.
template <typename T>
struct convert {
    msgpack::object const& operator()(msgpack::object const&, T&) const;
};

// pack: T 打包进 msgpack::packer.
template <typename T>
struct pack {
    template <typename Stream>
    msgpack::packer<Stream>& operator()(msgpack::packer<Stream>&, T const&) const;
};

// object: 用T 设置 msgpack::object
template <typename T>
struct object {
    void operator()(msgpack::object&, T const&) const;
};

// object_with_zone: 用T 设置 msgpack::object::with_zone
template <typename T>
struct object_with_zone {
    void operator()(msgpack::object::with_zone&, T const&) const;
};

专门针对your_type模板:

template <>
struct convert<your_type> {
    msgpack::object const& operator()(msgpack::object const&, your_type&) const {
        // your implementation
    }
};

template <>
struct pack<your_type> {
    template <typename Stream>
    msgpack::packer<Stream>& operator()(msgpack::packer<Stream>&, your_type const&) const {
        // your implementation
    }
};

template <>
struct object<your_type> {
    void operator()(msgpack::object&, your_type const&) const {
        // your implementation
    }
};

template <>
struct object_with_zone<your_type> {
    void operator()(msgpack::object::with_zone&, your_type const&) const {
        // your implementation
    }
};

无需特例化所有模板,若只想支持打包,则可仅对打包模板处理:

#include <msgpack.hpp>

class my_class {
public:
    my_class() {} // When you want to convert from msgpack::object to my_class
                  // using msgpack::object::as fucntion template,
                  // my_class should be default constructible.
    my_class(std::string const& name, int age):name_(name), age_(age) {}

    // my_class should provide getters for the data members you want to pack.
    std::string const& get_name() const { return name_; }
    int get_age() const { return age_; }
private:
    std::string name_;
    int age_;
};

namespace msgpack {
MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) {
namespace adaptor {

// Place class template specialization here
template<>
struct convert<my_class> {
    msgpack::object const& operator()(msgpack::object const& o, my_class& v) const {
        if (o.type != msgpack::type::ARRAY) throw msgpack::type_error();
        if (o.via.array.size != 2) throw msgpack::type_error();
        v = my_class(
            o.via.array.ptr[0].as<std::string>(),
            o.via.array.ptr[1].as<int>());
        return o;
    }
};

template<>
struct pack<my_class> {
    template <typename Stream>
    packer<Stream>& operator()(msgpack::packer<Stream>& o, my_class const& v) const {
        // packing member variables as an array.
        o.pack_array(2);
        o.pack(v.get_name());
        o.pack(v.get_age());
        return o;
    }
};

template <>
struct object_with_zone<my_class> {
    void operator()(msgpack::object::with_zone& o, my_class const& v) const {
        o.type = type::ARRAY;
        o.via.array.size = 2;
        o.via.array.ptr = static_cast<msgpack::object*>(
            o.zone.allocate_align(sizeof(msgpack::object) * o.via.array.size));
        o.via.array.ptr[0] = msgpack::object(v.get_name(), o.zone);
        o.via.array.ptr[1] = msgpack::object(v.get_age(), o.zone);
    }
};

} // namespace adaptor
} // MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS)
} // namespace msgpack

然后可将msgpack :: object转换为类形式:

// MSVC2015不完全支持C++11功能, 由于缺Expression SFINAE, MSVC2015不支持此功能
msgpack::object o = /*...*/
no_def_con ndc = o.as<no_def_con>();

自定义适配器【枚举】

#include <msgpack.hpp>

enum your_enum {
    elem1,
    elem2
};

MSGPACK_ADD_ENUM(your_enum);	// MSGPACK_ADD_ENUM使枚举或枚举类可打包, 与msgpack::object互转

enum class your_enum_class {
    elem1,
    elem2
};

MSGPACK_ADD_ENUM(your_enum_class);		// 在全局命名空间中使用

// ...