从C / C ++获取指向msgpack数组中元素的指针和长度

时间:2015-10-22 02:38:25

标签: c++ msgpack

我有一些使用C / C ++ api用msgpack打包的数据如下:

msgpack::sbuffer sbuf;
msgpack::packer<msgpack::sbuffer> pk(&sbuf);

int var1 = 10;
std::string var2 = "test";
double var3 = 3.14159; // could be any type

pk.pack_array(3);
pk.pack(var1);
pk.pack(var2);
pk.pack(var3);

稍后我需要解压缩该数组,但需要直接访问第三个元素,这样我就可以持久保存到文件/ db / redis / memcached / etc.虽然数组的前两个元素是固定类型,但第三个元素可以是msgpack(int,string,vector,map等)可接受的任何类型。

size_t off = 0;
msgpack::unpacked result = msgpack::unpack(sbuf.data(), sbuf.len(), off);
msgpack::object obj = result.get();

int var1;
obj.via.array.ptr[0].convert(&var1);

std::string var2;
obj.via.array.ptr[1].convert(&var2);

// now here I want to get a pointer & len to the 3rd item so I can persist
// this value that is already msgpack'd.

const char* dataptr = reinterpret_cast<const char*>(&obj.via.array.ptr[2]);
// now what is the length of the data pointed to by dataptr?

如上所示,我可以在obj.via.array.ptr [2]上做一个reinterpret_cast,但是对于二进制数据或者msgpack结构,一个简单的strlen()就不会这样做。得到我的长度,我不知道在哪里得到项目的长度。我知道许多类型中都有一个大小变量,但是当该项目是数组或地图时,我不相信这是准确的。

1 个答案:

答案 0 :(得分:2)

这是msgpack-c的内存模型: https://github.com/msgpack/msgpack-c/wiki/v1_1_cpp_unpacker#memory-management

  

我知道许多类型中都有一个大小变量,但是当该项目是数组或地图时,我们不相信这是准确的。

真。 obj已经解压缩。它不适合持久化。 我认为直接存储msgpack格式的二进制数据是更好的方法。首先,将msgpack分隔为前两个和第三个。然后,将前两个打包为一个数组。最后,只需打包第三个值。那就是包装过程。

    pk.pack_array(2); // for the first two
    pk.pack(var1);
    pk.pack(var2);
    pk.pack(var3);    // for the thrid one

解包时,用偏移量解压缩前两个数据。

    // Unpacking
    size_t off = 0;
    msgpack::unpacked result = msgpack::unpack(sbuf.data(), sbuf.size(), off);
    // off has been set

解压缩后,已设置偏移量。因此,您可以获得第三个数据的起点。然后,存储msgpack格式的二进制数据。

    std::string store; // file/db/redis/memcached/etc
    std::copy(sbuf.data() + off, sbuf.data() + sbuf.size(), std::back_inserter(store));

那就是存储过程。

当您从存储中获取msgpack格式的二进制数据时,请将其解压缩。

这是一个完整的代码示例:

#include <msgpack.hpp>

#include <iostream>
#include <string>
#include <algorithm>

int main() {
    msgpack::sbuffer sbuf;
    msgpack::packer<msgpack::sbuffer> pk(&sbuf);

    int var1 = 10;
    std::string var2 = "test";
    double var3 = 3.14159; // could be any type

    // Separate the data into the two msgpacks
    pk.pack_array(2); // for the first two
    pk.pack(var1);
    pk.pack(var2);
    pk.pack(var3);    // for the thrid one

    // Unpacking
    size_t off = 0;
    msgpack::unpacked result = msgpack::unpack(sbuf.data(), sbuf.size(), off);
    msgpack::object obj = result.get();

    auto converted = obj.as<std::tuple<int, std::string>>();
    std::cout << std::get<0>(converted) << std::endl;
    std::cout << std::get<1>(converted) << std::endl;

    // Storing the thrid one
    std::cout << "off: " << off << std::endl;
    std::string store; // file/db/redis/memcached/etc
    std::copy(sbuf.data() + off, sbuf.data() + sbuf.size(), std::back_inserter(store));

    {
        // Unpack the thrid one from store
        msgpack::unpacked result = msgpack::unpack(store.data(), store.size());
        msgpack::object obj = result.get();
        if (obj.type == msgpack::type::FLOAT) {
            auto f = obj.as<float>();
            std::cout << f << std::endl;
        }
    }
}

您可以在此处检查上述代码的行为: http://melpon.org/wandbox/permlink/uFfRGKQLqnIIiDrv