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 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中, 故可在解压后释放缓冲区
可自定义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)
#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);
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
当msgpack :: object的类型为str、bin或ext时,可能有对外部的引用
msgpack::object_handle【可视为智能指针】将管理所有内存:
1、使用msgpack::unpacker
2、使用不带unpack_referenc_func的msgpack::unpack() 【若带且返true,则须确保传递引用的生存期长于object_handle】
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); // 在全局命名空间中使用
// ...