MessagePack C++ - 如何遍历未知数据结构?
MessagePack C++ - How to iterate through an unknown data structure?
我想像这样使用 MessagePack 在 C++ 和 Python 语言之间共享结构化数据:
{
"t" : [ [t00,...,t0N], ... , [tM0,...,tMN] ],
"x" : [ x0,..,xN],
"P" : [ [P00, ..., P0N], ..., [PM0,...,PMN] ]
}
变量的数量是可选的,所以在某些情况下我只会有例如:
{
"t" : [ [t00,...,t0N], ... , [tM0,...,tMN] ]
}
在Python中解码这个很简单,我的问题是弄清楚
如果我事先不知道的结构,如何在 C++ 中对此进行解码
数据 ?或我将拥有的确切变量数;是吗
在这些情况下可以迭代结构吗?
我设法处理了一个 "fixed" 数据结构(总是使用相同的
变量数)定义一个结构,例如:
struct variables
{
std::vector< std::vector<double> > t;
std::vector< double > x;
std::vector< std::vector<double> > P;
MSPACK_DEFINE_MAP( t, x, P );
};
std::stringstream inBuffer;
.... (read data )
std::string str( inBuffer.str() );
msgpack::object_handle oh = msgpack::unpack( str.data(), str.size() );
msgpack::object deserialized = oh.get();
variables var;
deserialized.convert( var );
有没有更好的方法来完成这个?,如何管理可选的
不能出现在结构中的变量?;我重复
上一个问题:我可以在 C++ 中迭代一个未知的数据结构吗?
怎么样?
提前致谢!
此致,埃内斯托
有两种处理未知数据结构的方法。
第一种方式是使用parse/visitor机制。
这是一个例子:
#include <msgpack.hpp>
#include <sstream>
#include <iostream>
// This is a simple print example visitor.
// You can do any processing in your visitor.
struct my_visitor : msgpack::null_visitor {
bool start_map_key() {
processing_map_key = true;
return true;
}
bool end_map_key() {
processing_map_key = false;
return true;
}
bool start_array(uint32_t size) {
std::cout << "array (size:" << size << ")[" << std::endl;
return true;
}
bool end_array() {
std::cout << "]" << std::endl;
return true;
}
bool visit_str(const char* v, uint32_t size) {
if (processing_map_key) {
std::cout << "map key:" << std::string(v, size) << std::endl;
}
return true;
}
bool visit_positive_integer(uint64_t v) {
std::cout << "found value:" << v << std::endl;
return true;
}
bool processing_map_key = false;
std::string indent;
};
int main() {
// create test data
std::stringstream ss;
msgpack::packer<std::stringstream> pk(ss);
pk.pack_map(1);
pk.pack("t");
pk.pack_array(2);
pk.pack_array(3);
pk.pack(1);
pk.pack(2);
pk.pack(3);
pk.pack_array(3);
pk.pack(4);
pk.pack(5);
pk.pack(6);
// print data (for debug)
{
auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
std::cout << oh.get() << std::endl;
}
// apply visitor
{
my_visitor mv;
msgpack::parse(ss.str().data(), ss.str().size(), mv);
}
}
运行 演示:https://wandbox.org/permlink/3NrR4IMDIuLTk9e9
见https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_visitor。
另一种方法是使用 msgpack::type::variant
或 `msgpack::type::variant_ref。
前者复制数据,你可以更新它。后者不复制数据。你不能更新它。
这种方法需要提升。所以你需要定义MSGPACK_USE_BOOST。我建议定义为编译器选项。
// Boost is required
#define MSGPACK_USE_BOOST
#include <msgpack.hpp>
#include <sstream>
#include <iostream>
struct my_visitor:boost::static_visitor<void> {
void operator()(uint64_t v) const {
std::cout << "positive insteger:" << v << std::endl;
}
// const is required for map key because std::multimap's key (first) is const.
void operator()(std::string const& v) const {
std::cout << "string:" << v << std::endl;
}
void operator()(std::vector<msgpack::type::variant>& v) const {
std::cout << "array found" << std::endl;
for (auto& e : v) {
boost::apply_visitor(*this, e);
}
}
void operator()(std::multimap<msgpack::type::variant, msgpack::type::variant>& v) const {
std::cout << "map found" << std::endl;
for (auto& e : v) {
std::cout << "key:" << std::endl;
boost::apply_visitor(*this, e.first);
std::cout << "value:" << std::endl;
boost::apply_visitor(*this, e.second);
}
}
template <typename T>
void operator()(T const&) const {
std::cout << " match others" << std::endl;
}
};
int main() {
// create test data
std::stringstream ss;
msgpack::packer<std::stringstream> pk(ss);
pk.pack_map(1);
pk.pack("t");
pk.pack_array(2);
pk.pack_array(3);
pk.pack(1);
pk.pack(2);
pk.pack(3);
pk.pack_array(3);
pk.pack(4);
pk.pack(5);
pk.pack(6);
auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
std::cout << oh.get() << std::endl;
msgpack::type::variant v = oh.get().as<msgpack::type::variant>();
boost::apply_visitor(my_visitor(), v);
}
运行 演示:https://wandbox.org/permlink/HQwJjfwW8rLEMi0d
见https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_variant
示例如下:
https://github.com/msgpack/msgpack-c/blob/master/example/boost/msgpack_variant_capitalize.cpp
https://github.com/msgpack/msgpack-c/blob/master/example/boost/msgpack_variant_mapbased.cpp
两种方式都可以处理不可预测的数据结构。你需要做一些访客处理。如果数据结构在某种程度上是可预测的,你原来的方法也是好的。
实际上有一个更简单的方法,如果你处理的是映射(如问题中所述),而不是数组。
msgpack::object_handle oh = msgpack::unpack(/* some data */);
std::map<std::string,msgpack::type::variant> map = obj.convert();
这样您将获得包含所有数据的 map
,无需访问者或提升。
我想像这样使用 MessagePack 在 C++ 和 Python 语言之间共享结构化数据:
{
"t" : [ [t00,...,t0N], ... , [tM0,...,tMN] ],
"x" : [ x0,..,xN],
"P" : [ [P00, ..., P0N], ..., [PM0,...,PMN] ]
}
变量的数量是可选的,所以在某些情况下我只会有例如:
{
"t" : [ [t00,...,t0N], ... , [tM0,...,tMN] ]
}
在Python中解码这个很简单,我的问题是弄清楚 如果我事先不知道的结构,如何在 C++ 中对此进行解码 数据 ?或我将拥有的确切变量数;是吗 在这些情况下可以迭代结构吗?
我设法处理了一个 "fixed" 数据结构(总是使用相同的 变量数)定义一个结构,例如:
struct variables
{
std::vector< std::vector<double> > t;
std::vector< double > x;
std::vector< std::vector<double> > P;
MSPACK_DEFINE_MAP( t, x, P );
};
std::stringstream inBuffer;
.... (read data )
std::string str( inBuffer.str() );
msgpack::object_handle oh = msgpack::unpack( str.data(), str.size() );
msgpack::object deserialized = oh.get();
variables var;
deserialized.convert( var );
有没有更好的方法来完成这个?,如何管理可选的 不能出现在结构中的变量?;我重复 上一个问题:我可以在 C++ 中迭代一个未知的数据结构吗? 怎么样?
提前致谢!
此致,埃内斯托
有两种处理未知数据结构的方法。
第一种方式是使用parse/visitor机制。 这是一个例子:
#include <msgpack.hpp>
#include <sstream>
#include <iostream>
// This is a simple print example visitor.
// You can do any processing in your visitor.
struct my_visitor : msgpack::null_visitor {
bool start_map_key() {
processing_map_key = true;
return true;
}
bool end_map_key() {
processing_map_key = false;
return true;
}
bool start_array(uint32_t size) {
std::cout << "array (size:" << size << ")[" << std::endl;
return true;
}
bool end_array() {
std::cout << "]" << std::endl;
return true;
}
bool visit_str(const char* v, uint32_t size) {
if (processing_map_key) {
std::cout << "map key:" << std::string(v, size) << std::endl;
}
return true;
}
bool visit_positive_integer(uint64_t v) {
std::cout << "found value:" << v << std::endl;
return true;
}
bool processing_map_key = false;
std::string indent;
};
int main() {
// create test data
std::stringstream ss;
msgpack::packer<std::stringstream> pk(ss);
pk.pack_map(1);
pk.pack("t");
pk.pack_array(2);
pk.pack_array(3);
pk.pack(1);
pk.pack(2);
pk.pack(3);
pk.pack_array(3);
pk.pack(4);
pk.pack(5);
pk.pack(6);
// print data (for debug)
{
auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
std::cout << oh.get() << std::endl;
}
// apply visitor
{
my_visitor mv;
msgpack::parse(ss.str().data(), ss.str().size(), mv);
}
}
运行 演示:https://wandbox.org/permlink/3NrR4IMDIuLTk9e9
见https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_visitor。
另一种方法是使用 msgpack::type::variant
或 `msgpack::type::variant_ref。
前者复制数据,你可以更新它。后者不复制数据。你不能更新它。
这种方法需要提升。所以你需要定义MSGPACK_USE_BOOST。我建议定义为编译器选项。
// Boost is required
#define MSGPACK_USE_BOOST
#include <msgpack.hpp>
#include <sstream>
#include <iostream>
struct my_visitor:boost::static_visitor<void> {
void operator()(uint64_t v) const {
std::cout << "positive insteger:" << v << std::endl;
}
// const is required for map key because std::multimap's key (first) is const.
void operator()(std::string const& v) const {
std::cout << "string:" << v << std::endl;
}
void operator()(std::vector<msgpack::type::variant>& v) const {
std::cout << "array found" << std::endl;
for (auto& e : v) {
boost::apply_visitor(*this, e);
}
}
void operator()(std::multimap<msgpack::type::variant, msgpack::type::variant>& v) const {
std::cout << "map found" << std::endl;
for (auto& e : v) {
std::cout << "key:" << std::endl;
boost::apply_visitor(*this, e.first);
std::cout << "value:" << std::endl;
boost::apply_visitor(*this, e.second);
}
}
template <typename T>
void operator()(T const&) const {
std::cout << " match others" << std::endl;
}
};
int main() {
// create test data
std::stringstream ss;
msgpack::packer<std::stringstream> pk(ss);
pk.pack_map(1);
pk.pack("t");
pk.pack_array(2);
pk.pack_array(3);
pk.pack(1);
pk.pack(2);
pk.pack(3);
pk.pack_array(3);
pk.pack(4);
pk.pack(5);
pk.pack(6);
auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
std::cout << oh.get() << std::endl;
msgpack::type::variant v = oh.get().as<msgpack::type::variant>();
boost::apply_visitor(my_visitor(), v);
}
运行 演示:https://wandbox.org/permlink/HQwJjfwW8rLEMi0d
见https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_variant
示例如下: https://github.com/msgpack/msgpack-c/blob/master/example/boost/msgpack_variant_capitalize.cpp https://github.com/msgpack/msgpack-c/blob/master/example/boost/msgpack_variant_mapbased.cpp
两种方式都可以处理不可预测的数据结构。你需要做一些访客处理。如果数据结构在某种程度上是可预测的,你原来的方法也是好的。
实际上有一个更简单的方法,如果你处理的是映射(如问题中所述),而不是数组。
msgpack::object_handle oh = msgpack::unpack(/* some data */);
std::map<std::string,msgpack::type::variant> map = obj.convert();
这样您将获得包含所有数据的 map
,无需访问者或提升。