fixed some errors before merging to master

This commit is contained in:
Mindaugas Vinkelis
2017-09-03 19:34:08 +03:00
parent 241f1f2940
commit cba80774e4
6 changed files with 77 additions and 79 deletions

View File

@@ -1,18 +1,20 @@
<a name="2.1.0"></a>
# [2.1.0](https://github.com/fraillt/bitsery/compare/v2.0.1...v2.1.0) (2017-08-07)
# [3.0.0](https://github.com/fraillt/bitsery/compare/v2.0.1...v3.0.0) (2017-09-02)
### Features
* added **SERIALIZE_FRIEND** macro to be able to serialize private struct fields.
* friendly static_assert message when serializing **object**, that doesn't have **serialize** function defined.
* added **custom** function to override default behaviour for **object** serialization.
* renamed function **ext** to **extension** and changed its interface, to make it more easy to extend.
* improved serialization performance: added support for fixed size buffer for best performance.
### Breaking changes
* now all serializer/deserializer functions return void, to avoid undefined behaviour for functions parameters evaluation when using method chaining. There was no benefits apart from *nicer* syntax, but could have undefined behaviour when building complex serialization flows.
* changed BufferWriter/Reader behaviour,
* after serialization, call *getWrittenRange* to get valid written range.
* BufferReader only has constructors with iterators.
* added *FixedBufferSize* config bool parameter for *BufferWriter* for better serializer performance (more than 50% improvement). Default is resizable buffer.
* BufferWritter for resizable buffer now always resize to *capacity* to avoid using *back_insert_iterator* for better performance.
* added **SERIALIZE_FRIEND** macro to be able to serialize private struct fields
* user friendly static_assert when trying to serialize object, that doesn't have **serialize** function defined.
* added **custom** function to override default behaviour for **object** serialization
* renamed function **ext** to **extension** and changed its interface, to make it more easy to extend
* changed BufferWriter/Reader behaviour:
* added *FixedBufferSize* config bool parameter for *BufferWriter* for better serializer performance (more than 50% improvement). Default config is resizable buffer (*std::vector<uint8_t>*).
* after serialization, call *getWrittenRange* to get valid range written to buffer, because BufferWritter for resizable buffer now always resize to *capacity* to avoid using *back_insert_iterator* for better performance.
* BufferReader only has constructors with iterators (range).
<a name="2.0.1"></a>
# [2.0.1](https://github.com/fraillt/bitsery/compare/v2.0.0...v2.0.1) (2017-08-12)
@@ -32,7 +34,7 @@
### Bug Fixes
* *align* method fixed in *BufferReader*
### Other notes
### Breaking changes
* file structure changed, added *details* folder.
* no longer support for implicit size converions for all functions (*value*, *array*, *container*), instead added helper functions with specific size, to avoid typing *s.template value<1>...* within serialization function body

View File

@@ -9,7 +9,7 @@ It is designed around the networking requirements for multiplayer real-time fast
All cross-platform requirements are enforced at compile time, so serialized data do not store any run-time type information and is as small as possible.
> **bitsery** is looking for your feedback.
> **bitsery** is looking for your feedback on [gitter](https://gitter.im/bitsery/Lobby)
## Features
@@ -39,10 +39,9 @@ struct MyStruct {
//define how object should be serialized/deserialized
SERIALIZE(MyStruct) {
return s.
value4(o.i).
value2(o.e).
container4(o.fs, 10);
s.value4(o.i);
s.value2(o.e);
s.container4(o.fs, 10);
};
using namespace bitsery;
@@ -68,7 +67,7 @@ int main() {
//create deserializer
//1) create buffer reader
BufferReader br{buffer};
BufferReader br{bw.getWrittenRange()};
//2) create deserializer
Deserializer<BufferReader> des{br};

View File

@@ -105,7 +105,8 @@ int main() {
serialize(ser, data);
bw.flush();
std::cout << "size: " << buf.size() << std::endl;
auto range = bw.getWrittenRange();
std::cout << "size: " << std::distance(range.begin(), range.end()) << std::endl;
return 0;
}
```
@@ -147,10 +148,13 @@ Serialization function is very readable, and explicitly express intent what and
> learn more about why you need to write [value4 instead of value](../design/function_n.md).
Finally before sending buffer to network you must *flush* BufferWriter, it writes any remaining bits to buffer. In our case it is not required, because we only worked with whole bytes, but it is good practice to always use it after finishing serialization.
Finally, before getting serialized data you must *flush* BufferWriter, it writes any remaining bits to buffer. In our case it is not required, because we only worked with whole bytes, but it is good practice to always use it after finishing serialization.
To actually get written data you must call *getWrittenRange*, it return begin/end iterators to our buffer (*std::vector<uint8_t> buf*), for performance reasons BufferWritter always resizes underlying buffer to *capacity* so it could use containers iterator to update data, instead of back_insert_iterator to insert data.
```cpp
bw.flush();
auto range = bw.getWrittenRange();
```
# Summary

View File

@@ -81,7 +81,7 @@ int main() {
bw.flush();
BufferReader br{buf};
BufferReader br{bw.getWrittenRange()};
Deserializer<BufferReader> des{br};
serialize(des, res);
@@ -104,16 +104,18 @@ name equals: 1
We created *Deserializer* and modified *serialize* function to accept *Serializer* and *Deserializer*.
Deserialization is very similar as serialization, it also consists of three separate components:
* Buffer - container that we read data from, in our case vector<uint8_t>.
* BufferReader - reads bytes and bits from *Buffer*, it also makes sure that it is portable across Little and Big endian systems.
* Buffer - container that we read data from, in our case *vector<uint8_t>*.
* BufferReader - reads bytes and bits from *Buffer*, it also makes sure that it is portable across Little and Big endian systems.
* Deserializer - same interface as *Serializer* that use *BufferReader* to read bits and bytes, and convert to specific type. Deserializer also checks for errors at runtime, because data might come from untrusted source and can terminate program with buffer-overflow or segmentation fault if we are not careful.
Since deserialization involves error checking there are two additional functions to check if everything is correct after deserialization.
* [BufferReader.isCompleted()](../reference/buf_is_completed.md) - returns true, if whole buffer was read during deserialization.
* [Deserializer.isValid()](../reference/fnc_is_valid.md) - returns true, if there was no errors during deserialization.
One thing to note about BufferReader is that it doesn't have constructor that accepts buffer directly. Instead it only accepts begin/end iterators, because it needs to know precise data buffer length, to correctly use *isComplete* function.
```cpp
BufferReader br{buf};
BufferReader br{bw.getWrittenRange()};
Deserializer<BufferReader> des{br};
```

View File

@@ -1,61 +1,47 @@
#include <vector>
#include <bitsery/bitsery.h>
#include <cstring>
#include <iostream>
struct Vector3f {
float x;
float y;
float z;
bool operator == (const Vector3f& o) const {
return x == o.x && y == o.y && z == o.z;
}
enum class MyEnum:uint16_t { V1,V2,V3 };
struct MyStruct {
uint32_t i;
MyEnum e;
std::vector<float> fs;
};
struct Player {
Vector3f pos;
char name[50];
//define how object should be serialized/deserialized
SERIALIZE(MyStruct) {
s.value4(o.i);
s.value2(o.e);
s.container4(o.fs, 10);
};
using namespace bitsery;
SERIALIZE(Player) {
s.value4(o.pos.x);
s.value4(o.pos.y);
s.value4(o.pos.z);
s.text1(o.name);
}
Player createData() {
Player data;
data.pos.x = 0.45f;
data.pos.y = 50.9f;
data.pos.z = -15687.87f;
strcpy(data.name,"Yolo");
return data;
}
int main() {
const Player data = createData();
Player res{};
//set some random data
MyStruct data{8941, MyEnum::V2, {15.0f, -8.5f, 0.045f}};
MyStruct res{};
std::vector<uint8_t> buf;
BufferWriter bw{buf};
//create serializer
//1) create buffer to store data
std::vector<uint8_t> buffer;
//2) create buffer writer that is able to write bytes or bits to buffer
BufferWriter bw{buffer};
//3) create serializer
Serializer<BufferWriter> ser{bw};
serialize(ser, data);
//serialize object, can also be invoked like this: serialize(ser, data)
ser.object(data);
//flush to buffer, before creating buffer reader
bw.flush();
BufferReader br{buf};
//create deserializer
//1) create buffer reader
BufferReader br{bw.getWrittenRange()};
//2) create deserializer
Deserializer<BufferReader> des{br};
serialize(des, res);
std::cout << "deserializer state: " << des.isValid() << std::endl
<< "buffer completed: " << br.isCompleted() << std::endl
<< "pos equals: " << (res.pos == data.pos) << std::endl
<< "name equals: " << (strcmp(res.name, data.name) == 0);
return 0;
//deserialize same object, can also be invoked like this: serialize(des, data)
des.object(res);
assert(data.fs == res.fs && data.i == res.i && data.e == res.e);
}

View File

@@ -37,7 +37,10 @@ struct FixedBufferConfig {
using BufferType = std::array<uint8_t, 100>;
};
struct NonFixedBufferConfig: public DefaultConfig {
struct NonFixedBufferConfig {
static constexpr bitsery::EndiannessType NetworkEndianness = DefaultConfig::NetworkEndianness;
static constexpr bool FixedBufferSize = false;
using BufferType = std::vector<uint8_t>;
};
template <typename Config>
@@ -66,7 +69,7 @@ void writeData(BW& bw) {
bw.template writeBytes<4>(tmp5);
}
TYPED_TEST(BufferWriting, GetWrittenRangeReturnsIterators) {
TYPED_TEST(BufferWriting, GetWrittenRangeReturnsBeginEndIterators) {
using Config = typename TestFixture::type;
using Buffer = typename Config::BufferType;
Buffer buf{};
@@ -77,8 +80,7 @@ TYPED_TEST(BufferWriting, GetWrittenRangeReturnsIterators) {
EXPECT_THAT(std::distance(range.begin(), range.end()), DATA_SIZE);
}
TYPED_TEST(BufferWriting, WhenWritingBitsThenFlushWriter) {
TYPED_TEST(BufferWriting, WhenWritingBitsThenMustFlushWriter) {
Buffer buf;
bitsery::BufferWriter bw{buf};
@@ -105,11 +107,14 @@ TYPED_TEST(BufferWriting, WhenDataAlignedThenFlushHasNoEffect) {
EXPECT_THAT(std::distance(range2.begin(), range2.end()), Eq(1));
}
//TEST(BufferWritingFixedBuffer, ) {
// FixedBufferConfig::BufferType buf{};
// bitsery::BasicBufferWriter<FixedBufferConfig> bw{buf};
// writeData(bw);
// bw.flush();
// auto r = bw.getWrittenRange();
// EXPECT_THAT(buf.begin(), r.begin());
//}
TEST(BufferWrittingNonFixedBuffer, BufferIsAlwaysResizedToCapacity) {
using Buffer = typename NonFixedBufferConfig::BufferType;
Buffer buf{};
bitsery::BasicBufferWriter<NonFixedBufferConfig> bw{buf};
for (auto i = 0; i < 5; ++i) {
uint32_t tmp{};
bw.writeBytes<4>(tmp);
bw.writeBytes<4>(tmp);
EXPECT_TRUE(buf.size() == buf.capacity());
}
}