【messagePack官网】:序列化
【GitHub】:msgpack for C/C++

1、msgpack 静态库编译

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 instancemsgpack::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
#endifnamespace detail {// int64, uint64, doublestd::size_t const packer_max_buffer_size = 9;
} // detailclass vrefbuffer {public:// ref_size is stored to m_ref_sizevrefbuffer(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)),    // 最小10m_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、int64packer<Stream>& pack_fix_uint8(uint8_t d);packer<Stream>& pack_fix_uint16(uint16_t d);// ...uint32、uint64、int8、int16、int32、int64packer<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 longpacker<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_handlemsgpack::object_handle result;// Pass the msgpack::object_handleunpack(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_handlemsgpack::object_handle result;// Pass the msgpack::object_handleunpack(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 objectmsgpack::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中, 故可在解压后释放缓冲区

可自定义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时,则内存布局:

可获知解压后的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)
#endifclass 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 loopwhile (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);

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);  // 当缓冲区包含的字节不足以构建完整的msgpackvoid 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

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

msgpack::object_handle【可视为智能指针】将管理所有内存:
  1、使用msgpack::unpacker
  2、使用不带unpack_referenc_func的msgpack::unpack() 【若带且返true,则须确保传递引用的生存期长于object_handle】


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

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);        // 在全局命名空间中使用// ...

【C/C++类库】:msgpack 序列化相关推荐

  1. python msgpack_菜鸟世界 -python序列化第2篇---msgpack

    1.It's like JSON,but fast and small msgpack用起来像json,但是却比json快,并且序列化以后的数据长度更小,言外之意,使用msgpack不仅序列化和反序列 ...

  2. [序列化]MsgPack、Hessian对比

    两者的区别: hessian序列化的时候,会写入字段名称,然后字段值,你可以想象为一个map. msgpack序列化的时候,不写入字段名字,会按字段顺序写入值,你可以想象为一个数组. 对比 hessi ...

  3. K:java中的序列化与反序列化

    Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?以下内容将围绕这些问题进行展开讨论. Java序列化与反序列化 简单来说Java序列化是指把Java对象转 ...

  4. java-Java可以对方法进行序列化?

    Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?本文围绕这些问题进行了探讨. 1.Java序列化与反序列化 Java序列化是指把Java对象转换为字节序列 ...

  5. Java 中序列化与反序列化

    一. 序列化和反序列化概念 Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是一种将这些字节重建成一个对象的过程.将程序中的对象,放入文 ...

  6. java 序列化概念和作用_结合代码详细解读Java序列化与反序列化概念理解

    Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?本文围绕这些问题进行了探讨. 1.Java序列化与反序列化 Java序列化是指把Java对象转换为字节序列 ...

  7. java序列化与反序列化(转)

    Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?本文围绕这些问题进行了探讨. 1.Java序列化与反序列化 Java序列化是指把Java对象转换为字节序列 ...

  8. Java基础—序列化底层原理

    原文地址:https://blog.csdn.net/xlgen157387/article/details/79840134 目录 一.基本概念 二.Java如何实现序列化和反序列化 三.相关注意事 ...

  9. java序列化_今天聊聊 Java 序列化

    点击上方 Java后端,选择 设为星标 优质文章,及时送达在开发过程中经常会对实体进行序列化,但其实我们只是在"只知其然,不知其所以然"的状态,很多时候会有这些问题: 什么是序列化 ...

最新文章

  1. javascript 随机点名
  2. python语法基础题输出倒三角图案,【趣味shellamp;amp;python】倒三角控制台输出图形...
  3. centos 7 yum 安装 python3
  4. Arduino可穿戴开发入门教程(大学霸内部资料)
  5. Servlet+MySQL使用DBCP数据库连接池实现用户登录
  6. PMP 英文术语缩写
  7. 转:使用curl来调试你的应用
  8. Java学习笔记一和前言
  9. 本地启动 Hybris 服务器调试模式后,监听在 8000 端口
  10. 从源文件和JAR文件构建Java代码模型
  11. 算法(10)-leetcode-explore-learn-数据结构-链表双指针技巧
  12. 上海交大张拳石:神经网络的变量交互可解释性研究
  13. java appender_log4j的Appenders配置方法
  14. 为什么选择使用 OKR 进行项目过程管理
  15. 【ArcGis for javascript从零开始】之一 ArcGis加载天地图
  16. 【目标检测】|RFB ECCV2018
  17. 通达信指标-MACD+均线交叉
  18. 某客服热线呼叫中心话务分析
  19. 【数据结构】初识数据结构,十分钟带你玩转算法复杂度
  20. Latex使用本地字体

热门文章

  1. 什么是授权码,它又是如何设置?
  2. Hive多维统计分析案例实战
  3. JAVA FTPClient文件操作
  4. 基于最小优先级队列构造哈夫曼树 Java
  5. 冰蝎各个版本的更新日志
  6. php opencv 数字水印,OpenCV之简单数字水印
  7. c语言feof函数_使用示例的C语言中的feof()函数
  8. python星座转换程序代码_0009 如何编写程序计算所属星座,一看就懂
  9. 让人眼前一亮的三维可视化平台
  10. 【BEV】BEVDet