簡體   English   中英

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++ 中解碼它? 或我將擁有的變量的確切數量; 在這些情況下是否可以迭代結構?

我設法處理定義結構的“固定”數據結構(始終具有相同數量的變量),例如:

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++ 中迭代一個未知的數據結構嗎?,如何?

提前致謝!

問候, 埃內斯托

有兩種處理未知數據結構的方法。

第一種方法是使用解析/訪問者機制。 這是一個例子:

#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 ,無需訪客或提升。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM