2015-10-22 2 views
1

У меня есть некоторые данные, которые были упакованы с msgpack с использованием API C/C++ следующим образом:Получить указатель и длину элемента в msgpack массив из C/C++

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? 

Потенциально я мог бы сделать reinterpret_cast на obj.via.array.ptr [2], как показано выше, но в случае двоичных данных или msgpack'd структуры, простые StrLen() Wouldn» t получить меня длина, и я не вижу, где можно получить длину элемента. Я знаю, что во многих типах существует переменная размера, но не верю, что это точно, когда этот элемент является массивом или картой.

ответ

2

Вот модель память msgpack-с: https://github.com/msgpack/msgpack-c/wiki/v1_1_cpp_unpacker#memory-management

Я знаю, что есть переменный размер во многих типов, но не считаю, что это является точным, когда этот элемент является массивом или карта.

Истина. obj уже распакована. Он не подходит для настойчивости. Я думаю, что сохранение двоичных данных формата msgpack напрямую лучше. Сначала отделите msgpack к первым двум и к thrid одному. Затем упакуйте первые два в виде массива. Наконец, просто упакуйте третье значение. Это процесс упаковки.

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

+0

Большое спасибо, это будет работать хорошо для меня. Не передумал разбить массив и использовать смещение, чтобы смотреть мимо него. – mr19

 Смежные вопросы

  • Нет связанных вопросов^_^