-
Notifications
You must be signed in to change notification settings - Fork 91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
No Heap Array support? #28
Comments
Do correct me if im wrong, but it seems like something that should really be supported. |
You're right. |
Any progress on this? I have a I tried this as a quick and dirty way: if (_ptr) {
for (auto i = 0 ; i < _size; ++i)
s.value1b(*((U8*)_ptr + i));
} but my data is many GBs so this is (understandably) way too slow. Edit: The |
Hi,
I would prefer to write an extension, it has more customization and less code to write. namespace bitsery {
namespace ext {
template <typename TSize>
class BufferData {
public:
explicit BufferData(TSize& size):_size{size} {}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
auto& writer = ser.adapter();
writer.template writeBytes<4>(static_cast<uint32_t>(_size));
writer.template writeBuffer<1>(static_cast<const uint8_t*>(obj), _size);
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
auto& reader = des.adapter();
uint32_t s=0u;
reader.template readBytes<4>(s);
_size = static_cast<TSize>(s);
reader.template readBuffer<1>(static_cast<uint8_t*>(obj), _size);
}
private:
TSize& _size;
};
}
namespace traits {
template<typename TSize, typename T>
struct ExtensionTraits<ext::BufferData<TSize>, T> {
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
}
struct MyStruct {
void* ptr;
int ptr_size;
};
template <typename S>
void serialize(S& s, MyStruct& o) {
s.ext(o.ptr, bitsery::ext::BufferData<int>(o.ptr_size));
}
|
@fraillt That's very helpful, thanks! |
For our use case we don't even need to store the size. It doesn't change per-object. Do you plan to merge this, btw? |
No, there are no plans to meet it, simply because it's easy to implement, but there might be too many edge cases that doesn't fit for everyone anyway. Like in your case, you don't need size;) but hope that this example will be useful for others as well:) |
Ok, though it's easy for you, you made the library :) For anyone else it'd take longer, for something that should be a basic feature (imo). You can simply base it off of |
I understand your view, and your points are valid. |
Ok :) Thanks for your work. |
Hi, I have a similar issue. I would like to serialize Eigen matrices. My use case will include Given the examples above I only managed to get something working like template <typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &matrix, Fnc &&fnc) const
{
uint32_t rows = matrix.rows();
uint32_t cols = matrix.cols();
uint32_t elems = rows * cols;
auto &writer = ser.adapter();
writer.template writeBytes<4>(static_cast<uint32_t>(rows));
writer.template writeBytes<4>(static_cast<uint32_t>(cols));
for (uint32_t i = 0; i < elems; ++i)
ser.value4b(matrix.data()[i]);
} I had to resort to the (according to comments above) slow version of writing separate values, because |
Actually I think I got it to work with template <typename Ser,
typename Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols,
typename Fnc>
void serialize(Ser &ser, const ::Eigen::Matrix<Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> &matrix, Fnc &&fnc) const
{
uint32_t rows = matrix.rows();
uint32_t cols = matrix.cols();
uint32_t elems = rows * cols;
auto &writer = ser.adapter();
writer.template writeBytes<4>(static_cast<uint32_t>(rows));
writer.template writeBytes<4>(static_cast<uint32_t>(cols));
static_assert(details::IsFundamentalType<Scalar>::value, "Value must be integral, float or enum type.");
using TValue = typename details::IntegralFromFundamental<Scalar>::TValue;
writer.template writeBuffer<sizeof(TValue)>(reinterpret_cast<const TValue *>(matrix.data()), elems);
} This might be a stupid question and the wrong place to ask, but I see that writeBuffer then basically does a for loop to write each value - is this efficient / is there a way to code it such that it attempts to copy the entire buffer at once? |
Hello, I'm glad you make it work, I assume you don't need to deserialize this. |
Ok thanks for the clarification! I will be deserializing it too, I just didn't post the code since it's trivially the same, basically just replacing |
If matrix element type is float, double or one of new fixed type int_32t, int_64t etc, then it's ok. |
Thanks, that's what I did. I'm posting the full code here in case it might help someone. Click to expand for full code (serializing dense Eigen matrices)
#ifndef BITSERY_EXT_EIGEN_H
#define BITSERY_EXT_EIGEN_H
#include "../traits/core/traits.h"
#include "../details/adapter_common.h"
#include "../details/serialization_common.h"
#include <Eigen/Dense>
#include <Eigen/Core>
namespace bitsery
{
namespace ext
{
namespace Eigen
{
class Matrix
{
public:
template <typename Ser,
typename Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols,
typename Fnc>
void serialize(Ser &ser, const ::Eigen::Matrix<Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> &matrix, Fnc &&fnc) const
{
uint32_t rows = matrix.rows();
uint32_t cols = matrix.cols();
uint32_t elems = rows * cols;
auto &writer = ser.adapter();
writer.template writeBytes<4>(static_cast<uint32_t>(rows));
writer.template writeBytes<4>(static_cast<uint32_t>(cols));
static_assert(details::IsFundamentalType<Scalar>::value, "Value must be integral, float or enum type.");
using TValue = typename details::IntegralFromFundamental<Scalar>::TValue;
writer.template writeBuffer<sizeof(TValue)>(reinterpret_cast<const TValue *>(matrix.data()), elems);
}
template <typename Des,
typename Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols,
typename Fnc>
void deserialize(Des &des, ::Eigen::Matrix<Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> &matrix, Fnc &&fnc) const
{
auto &reader = des.adapter();
uint32_t rows = 0u, cols = 0u;
reader.template readBytes<4>(rows);
reader.template readBytes<4>(cols);
uint32_t elems = rows * cols;
matrix.resize(rows, cols);
static_assert(details::IsFundamentalType<Scalar>::value, "Value must be integral, float or enum type.");
using TValue = typename details::IntegralFromFundamental<Scalar>::TValue;
reader.template readBuffer<sizeof(TValue)>(reinterpret_cast<TValue *>(matrix.data()), elems);
}
private:
};
} // namespace Eigen
} // namespace ext
namespace traits
{
template <typename T>
struct ExtensionTraits<ext::Eigen::Matrix, T>
{
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
} // namespace traits
} // namespace bitsery
#endif //BITSERY_EXT_EIGEN_H Usage: e.g. |
Thanks for sharing! |
In case this is useful to anyone else, I was running into performance issues with vectors of structs where the structs were just PODs. These could really just be readBuffer/writeBuffer when they don't need to swap byte order, and then fall back to their serialize methods if they do. I made an extension for it, I haven't tested the validity of the data yet but i can confirm its the same size! Click to expand
This concept should be able to be extended to heap arrays as well. |
Hello, I tried to use class BufferData (BitseryBufferData.h) in my code:
I received error: |
Hello, |
Thanks @fraillt , I changed my context to be PointerLinkingContext and I also tried to change my call to text, due to error I got. I tried to change it according to tests/serialization_text.cpp. My current code:
Errors I receive: bitsery-master/include/bitsery/serializer.h:105:8: error: 'void bitsery::Serializer<TOutputAdapter, TContext>::ext(const T&, const Ext&, Fnc&&) [with T = std::map<std::__cxx11::basic_string, Test*>; Ext = bitsery::ext::StdMap; Fnc = TestCache::serialize(S&) [with S = bitsery::Serializer<bitsery::BasicBufferedOutputStreamAdapter<char, bitsery::DefaultConfig, std::char_traits >, bitsery::ext::PointerLinkingContext>]::<lambda(bitsery::Serializer<bitsery::BasicBufferedOutputStreamAdapter<char, bitsery::DefaultConfig, std::char_traits >, bitsery::ext::PointerLinkingContext>&, std::string&, Test*&)>; TOutputAdapter = bitsery::BasicBufferedOutputStreamAdapter<char, bitsery::DefaultConfig, std::char_traits >; TContext = bitsery::ext::PointerLinkingContext]', declared using local type 'TestCache::serialize(S&) [with S = bitsery::Serializer<bitsery::BasicBufferedOutputStreamAdapter<char, bitsery::DefaultConfig, std::char_traits >, bitsery::ext::PointerLinkingContext>]::<lambda(bitsery::Serializer<bitsery::BasicBufferedOutputStreamAdapter<char, bitsery::DefaultConfig, std::char_traits >, bitsery::ext::PointerLinkingContext>&, std::string&, Test*&)>', is used but never defined [-fpermissive] |
Hello @fraillt , I managed to solve the text issue. Now I am trying to work through deserialization with BufferData. Errors:
Does the separation between serialize and deserialize functions in BufferData require separation in the class which uses this extension (class Test in my example) ? I'll be grateful for a sample code. Thanks,
|
you have text1b(), which would be the closest thing to char array support, though generic heap arrays arent supported at all, not even an option like
The text was updated successfully, but these errors were encountered: