refactoring to work with C++11, and added containerMap extension

This commit is contained in:
fraillt
2017-09-19 11:13:59 +03:00
parent 2f8ae0075c
commit ad7090539e
25 changed files with 713 additions and 251 deletions

View File

@@ -40,7 +40,6 @@ constexpr EndiannessType getInverseEndianness(EndiannessType e) {
struct InverseEndiannessConfig {
static constexpr bitsery::EndiannessType NetworkEndianness = getInverseEndianness(DefaultConfig::NetworkEndianness);
static constexpr bool FixedBufferSize = DefaultConfig::FixedBufferSize;
using BufferType = DefaultConfig::BufferType;
};
@@ -147,7 +146,7 @@ struct IntegralUnsignedTypes {
TEST(BufferEndianness, WhenBufferValueTypeIs1ByteThenBitOperationsIsNotAffectedByEndianness) {
//fill initial values
static_assert(sizeof(DefaultConfig::BufferType::value_type) == 1, "currently only 1 byte size, value size is supported");
static_assert(sizeof(bitsery::details::BufferContainerTraits<DefaultConfig::BufferType>::TValue) == 1, "currently only 1 byte size, value size is supported");
//fill initial values
constexpr IntegralUnsignedTypes src {
0x0000334455667788,//bits 19

View File

@@ -47,6 +47,31 @@ constexpr size_t getBits(T v) {
// *** bits operations
TEST(BufferBitsAndBytesOperations, WriteAndReadBitsMaxTypeValues) {
Buffer buf;
BufferWriter bw{buf};
bw.writeBits(std::numeric_limits<uint64_t>::max(), 64);
bw.writeBits(std::numeric_limits<uint32_t>::max(), 32);
bw.writeBits(std::numeric_limits<uint16_t>::max(), 16);
bw.writeBits(std::numeric_limits<uint8_t>::max(), 8);
bw.flush();
BufferReader br{bw.getWrittenRange()};
uint64_t v64{};
uint32_t v32{};
uint16_t v16{};
uint8_t v8{};
br.readBits(v64, 64);
br.readBits(v32, 32);
br.readBits(v16, 16);
br.readBits(v8, 8);
EXPECT_THAT(v64, Eq(std::numeric_limits<uint64_t>::max()));
EXPECT_THAT(v32, Eq(std::numeric_limits<uint32_t>::max()));
EXPECT_THAT(v16, Eq(std::numeric_limits<uint16_t>::max()));
EXPECT_THAT(v8, Eq(std::numeric_limits<uint8_t>::max()));
}
TEST(BufferBitsAndBytesOperations, WriteAndReadBits) {
//setup data
constexpr IntegralUnsignedTypes data{

View File

@@ -33,13 +33,11 @@ using Buffer = bitsery::DefaultConfig::BufferType;
struct FixedBufferConfig {
static constexpr bitsery::EndiannessType NetworkEndianness = DefaultConfig::NetworkEndianness;
static constexpr bool FixedBufferSize = true;
using BufferType = std::array<uint8_t, 100>;
};
struct NonFixedBufferConfig {
static constexpr bitsery::EndiannessType NetworkEndianness = DefaultConfig::NetworkEndianness;
static constexpr bool FixedBufferSize = false;
using BufferType = std::vector<uint8_t>;
};

View File

@@ -101,22 +101,21 @@ TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, Values) {
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, CustomFunctionIncrements) {
SerializationContext ctx{};
using TValue = typename TestFixture::TValue;
auto ser = ctx.createSerializer();
ser.container(this->src, 1000, [](auto &s, auto v) {
//increment by 1 before writing
v++;
s.template value<sizeof(v)>(v);
ser.container(this->src, 1000, [&ser](TValue& v) {
ser.template value<sizeof(v)>(v);
});
auto des = ctx.createDeserializer();
des.container(this->res, 1000, [](auto &s, auto &v) {
s.template value<sizeof(v)>(v);
des.container(this->res, 1000, [&des](TValue &v) {
des.template value<sizeof(v)>(v);
//increment by 1 after reading
v++;
});
//decrement result by 2, before comparing for eq
//decrement result by 1, before comparing for eq
for (auto &v:this->res)
v -= 2;
v -= 1;
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
@@ -157,9 +156,9 @@ TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes, DefaultSerializeFunction
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes, CustomFunctionThatDoNothing) {
SerializationContext ctx{};
using TValue = typename TestFixture::TValue;
auto emptyFnc = [](auto &s, auto &v) {};
auto emptyFnc = [](TValue &v) {};
ctx.createSerializer().container(this->src, 1000, emptyFnc);
ctx.createDeserializer().container(this->res, 1000, emptyFnc);
@@ -204,8 +203,7 @@ class SerializeContainerFixedSizeCompositeTypes : public SerializeContainerFixed
};
using StaticContainersWithCompositeTypes = ::testing::Types<
std::array<MyStruct1, 4>,
MyStruct1[4]>;
std::array<MyStruct1, 4>, MyStruct1[4]>;
TYPED_TEST_CASE(SerializeContainerFixedSizeCompositeTypes, StaticContainersWithCompositeTypes);
@@ -227,18 +225,20 @@ TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, CustomFunctionThatSerializ
Container src{MyStruct1{0, 1}, MyStruct1{2, 3}, MyStruct1{4, 5}, MyStruct1{5134, 1532}};
Container res{};
using TValue = decltype(*std::begin(res));
SerializationContext ctx;
auto ser = ctx.createSerializer();
ser.container(src, [](auto &s, auto &v) {
ser.container(src, [&ser](TValue &v) {
char tmp{};
s.object(v);
s.value1b(tmp);
ser.object(v);
ser.value1b(tmp);
});
auto des = ctx.createDeserializer();
des.container(res, [](auto &s, auto &v) {
des.container(res, [&des](TValue &v) {
char tmp{};
s.object(v);
s.value1b(tmp);
des.object(v);
des.value1b(tmp);
});
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * (MyStruct1::SIZE + sizeof(char))));
@@ -246,4 +246,3 @@ TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, CustomFunctionThatSerializ
}

View File

@@ -101,16 +101,16 @@ TEST(SerializeEntropyEncoding, CustomFunctionNotEntropyEncoded) {
auto ser = ctx.createSerializer();
//lambdas differ only in capture clauses, it would make sense to use std::bind, but debugger crashes when it sees std::bind...
auto serLambda = [rangeForValue](auto& s, const MyStruct1& v) {
s.range(v.i1, rangeForValue);
s.range(v.i2, rangeForValue);
auto serLambda = [&ser, rangeForValue](MyStruct1& v) {
ser.range(v.i1, rangeForValue);
ser.range(v.i2, rangeForValue);
};
ser.entropy(v, entropyValues, serLambda);
auto des = ctx.createDeserializer();
auto desLambda = [rangeForValue](auto& s, MyStruct1& v) {
s.range(v.i1, rangeForValue);
s.range(v.i2, rangeForValue);
auto desLambda = [&des, rangeForValue](MyStruct1& v) {
des.range(v.i1, rangeForValue);
des.range(v.i2, rangeForValue);
};
des.entropy(res, entropyValues, desLambda);
@@ -127,8 +127,8 @@ TEST(SerializeEntropyEncoding, WhenEntropyEncodedThenCustomFunctionNotInvoked) {
MyStruct1{4849,89}, MyStruct1{0,1}};
SerializationContext ctx;
ctx.createSerializer().entropy(v, entropyValues, [](bitsery::Serializer<bitsery::BufferWriter>& ,const MyStruct1& ) {});
ctx.createDeserializer().entropy(res, entropyValues, [](bitsery::Deserializer<bitsery::BufferReader>&, MyStruct1& ) {});
ctx.createSerializer().entropy(v, entropyValues, [](MyStruct1& ) {});
ctx.createDeserializer().entropy(res, entropyValues, []( MyStruct1& ) {});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));

View File

@@ -0,0 +1,138 @@
//MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <bitsery/ext/container_map.h>
#include <unordered_map>
#include <map>
using containerMap = bitsery::ext::containerMap;
using testing::Eq;
template<typename Container>
Container createData() {
return {};
}
template<>
std::unordered_map<std::string, MyStruct1> createData<std::unordered_map<std::string, MyStruct1>>() {
return {
std::make_pair("some key", MyStruct1{874,456}),
std::make_pair("other key", MyStruct1{-34,8645}),
std::make_pair("secret key", MyStruct1{-4878,3468975})
};
}
template<>
std::unordered_map<int32_t, float> createData<std::unordered_map<int32_t, float>>() {
return {
std::pair<int32_t , float>(545, 45.485f),
std::pair<int32_t , float>(6748, -7891.5f),
std::pair<int32_t , float>(845, -457.0f)
};
}
template<>
std::map<MyEnumClass, MyStruct1> createData<std::map<MyEnumClass, MyStruct1>>() {
return {
std::make_pair(MyEnumClass::E3, MyStruct1{874,456}),
std::make_pair(MyEnumClass::E6, MyStruct1{-34,8645}),
std::make_pair(MyEnumClass::E2, MyStruct1{-4878,3468975})
};
}
template<>
std::map<int32_t ,int64_t> createData<std::map<int32_t ,int64_t>>() {
return {//these are optimized with range and entropy
std::pair<int32_t, int64_t>(-45, -984196845ll),
std::pair<int32_t, int64_t>(54, 1ll),
std::pair<int32_t, int64_t>(98, 3ll)
};
}
template<typename T>
class SerializeExtensionContainerMap : public testing::Test {
public:
using TContainer = T;
const TContainer src = createData<TContainer>();
TContainer res{};
};
using SerializeExtensionContainerMapTypes = ::testing::Types<
std::unordered_map<std::string, MyStruct1>,
std::unordered_map<int32_t, float>,
std::map<MyEnumClass , MyStruct1>,
std::map<int32_t ,int64_t>
>;
TYPED_TEST_CASE(SerializeExtensionContainerMap, SerializeExtensionContainerMapTypes);
namespace bitsery {
template <typename S>
void serialize(S& s, std::unordered_map<std::string, MyStruct1>& o) {
s.extend(o, containerMap{}, [&s](std::string& key, MyStruct1& value) {
s.text1b(key, 100);
s.object(value);
});
}
template <typename S>
void serialize(S& s, std::unordered_map<int32_t, float>& o) {
s.extend(o, containerMap{}, [&s](int32_t& key, float& value) {
s.value4b(key);
s.value4b(value);
});
}
template <typename S>
void serialize(S& s, std::map<MyEnumClass , MyStruct1>& o) {
s.extend(o, containerMap{}, [&s](MyEnumClass& key, MyStruct1& value) {
s.value4b(key);
s.object(value);
});
}
template <typename S>
void serialize(S& s, std::map<int32_t ,int64_t>& o) {
s.extend(o, containerMap{}, [&s](int32_t& key, int64_t& value) {
s.range(key, bitsery::RangeSpec<int32_t>{-100,100});
constexpr int64_t ev[3]{1ll, 2ll, 3ll};
s.entropy8b(value, ev);
});
}
}
TYPED_TEST(SerializeExtensionContainerMap, SerializeAndDeserializeEquals) {
SerializationContext ctx1;
ctx1.createSerializer().object(this->src);
ctx1.createDeserializer().object(this->res);
EXPECT_THAT(this->res, Eq(this->src));
}

View File

@@ -26,7 +26,7 @@
using namespace testing;
using Buffer = typename bitsery::DefaultConfig::BufferType;
using DiffType = typename Buffer::difference_type;
using DiffType = typename bitsery::details::BufferContainerTraits<Buffer>::TDifference;
struct DataV1 {
int32_t v1;
@@ -46,7 +46,7 @@ struct DataV3 {
TEST(SerializeGrowable, WriteSessionsDataAtBufferEndAfterFlush) {
SerializationContext ctx;
ctx.createSerializer().growable(int8_t{}, [] (auto& s, auto& v) { });
ctx.createSerializer().growable(int8_t{}, [] (int8_t& v) { });
EXPECT_THAT(ctx.getBufferSize(), Eq(0));
ctx.bw->flush();
EXPECT_THAT(ctx.getBufferSize(), Gt(0));
@@ -60,7 +60,8 @@ TEST(SerializeGrowable, SessionDataConsistOfSessionsEndPosAnd2BytesSessionsDataO
constexpr size_t DATA_SIZE = 4;
int32_t data{};
ctx.createSerializer().growable(data, [](auto&s, auto& v) { s.value4b(v);});
auto ser = ctx.createSerializer();
ser.growable(data, [&ser](int32_t & v) { ser.value4b(v);});
ctx.createDeserializer();//to flush data and create buffer reader
EXPECT_THAT(ctx.getBufferSize(), Eq(3 + DATA_SIZE));

View File

@@ -49,26 +49,29 @@ struct Y {
struct Z { X x{}; Y y{}; };
SERIALIZE(Z)
template <typename S>
void serialize(S& s, Z& o)
{
s.object(o.x);
s.object(o.y);
}
SERIALIZE(X)
template <typename S>
void serialize(S& s, X& o)
{
s.template value<sizeof(o.x)>(o.x);
s.template text<1>(o.s, 1000);
}
SERIALIZE(Y)
template <typename S>
void serialize(S& s, Y& o)
{
auto writeInt = [](auto& s, auto& v) { s.template value<sizeof(v)>(v); };
auto writeInt = [&s]( int& v) { s.template value<sizeof(v)>(v); };
s.template text<1>(o.s, 10000);
s.template value<sizeof(o.y)>(o.y);
s.container(o.arr, writeInt);
s.container(o.carr, writeInt);
s.container(o.vx, 10000, [](auto& s, auto& v) { s.object(v); });
s.container(o.vx, 10000, [&s](X& v) { s.object(v); });
}

View File

@@ -28,9 +28,9 @@ using testing::Eq;
bool SerializeDeserializeContainerSize(SerializationContext& ctx, const size_t size) {
std::vector<char> t1(size);
ctx.createSerializer().container(t1, size+1, [](auto , auto ){});
ctx.createSerializer().container(t1, size+1, []( char& ){});
t1.clear();
ctx.createDeserializer().container(t1, size+1, [](auto , auto ){});
ctx.createDeserializer().container(t1, size+1, []( char& ){});
return t1.size() == size;
}

View File

@@ -33,7 +33,7 @@
*/
struct MyStruct1 {
MyStruct1(int v1, int v2) : i1{v1}, i2{v2} {}
MyStruct1(int32_t v1, int32_t v2) : i1{v1}, i2{v2} {}
MyStruct1() : MyStruct1{0, 0} {}
@@ -47,12 +47,13 @@ struct MyStruct1 {
static constexpr size_t SIZE = sizeof(MyStruct1::i1) + sizeof(MyStruct1::i2);
};
SERIALIZE(MyStruct1) {
template <typename S>
void serialize(S& s, MyStruct1& o) {
s.template value<sizeof(o.i1)>(o.i1);
s.template value<sizeof(o.i2)>(o.i2);
}
enum class MyEnumClass {
enum class MyEnumClass:int32_t {
E1, E2, E3, E4, E5, E6
};
@@ -75,7 +76,8 @@ struct MyStruct2 {
static constexpr size_t SIZE = MyStruct1::SIZE + sizeof(MyStruct2::e1);
};
SERIALIZE(MyStruct2) {
template <typename S>
void serialize(S&s, MyStruct2& o) {
s.template value<sizeof(o.e1)>(o.e1);
s.object(o.s1);
}
@@ -87,9 +89,10 @@ public:
std::unique_ptr<bitsery::BufferWriter> bw;
std::unique_ptr<bitsery::BufferReader> br;
bitsery::Serializer<bitsery::BufferWriter> createSerializer() {
bw = std::make_unique<bitsery::BufferWriter>(buf);
return {*bw};
bitsery::Serializer createSerializer() {
//make_unique is not in c++11
bw = std::unique_ptr<bitsery::BufferWriter>(new bitsery::BufferWriter(buf));
return bitsery::Serializer{*bw};
};
size_t getBufferSize() const {
@@ -107,10 +110,11 @@ public:
return 4;
}
bitsery::Deserializer<bitsery::BufferReader> createDeserializer() {
bitsery::Deserializer createDeserializer() {
bw->flush();
br = std::make_unique<bitsery::BufferReader>(bw->getWrittenRange());
return {*br};
//make_unique is not in c++11
br = std::unique_ptr<bitsery::BufferReader>(new bitsery::BufferReader(bw->getWrittenRange()));
return bitsery::Deserializer{*br};
};
};

View File

@@ -108,17 +108,11 @@ TEST(SerializeText, CArraySerializesTextLength) {
EXPECT_THAT(r1, ContainerEq(t1));
}
TEST(SerializeText, WhenCArrayNotNullterminatedThenMakeItNullterminated) {
TEST(SerializeText, WhenCArrayNotNullterminatedThenAssert) {
SerializationContext ctx;
char16_t t1[CARR_LENGTH]{u"some text"};
//make last character not nullterminated
t1[CARR_LENGTH-1] = 'x';
char16_t r1[CARR_LENGTH]{};
ctx.createSerializer().text<2>(t1);
ctx.createDeserializer().text<2>(r1);
EXPECT_THAT(ctx.getBufferSize(), Eq(ctx.containerSizeSerializedBytesCount(CARR_LENGTH) +
(CARR_LENGTH - 1) * 2));
EXPECT_THAT(r1[CARR_LENGTH-1], Eq(0));
EXPECT_DEATH(ctx.createSerializer().text<2>(t1), "");
}