Skip to content

Commit

Permalink
added inheritance extension, and ability to have internal contexts wi…
Browse files Browse the repository at this point in the history
…thin serializer/deserializer
  • Loading branch information
fraillt committed Nov 12, 2017
1 parent be9ccf0 commit f6d02ab
Show file tree
Hide file tree
Showing 27 changed files with 1,179 additions and 312 deletions.
27 changes: 24 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# [4.2.0](https://github.com/fraillt/bitsery/compare/v4.1.0...v4.2.0) (2017-11-12)

### Features

* serializer/deserializer can now have **internal context(s)** via configuration.
It is convenient way to pass context, when it doesn't convey useful information outside of serializer/deserializer and is default constructable.
* added **contextOrNull\<T\>()** overload to *BasicSerializer/BasicDeserializer*.
Difference between *contextOrNull\<T\>()* and *context\<T\>()* is, that using *context\<T\>()* code doesn't compile if T doesn't exists at all, while using *contextOrNull\<T\>()* code compiles, but returns *nullptr* at runtime.
* added inheritance support via extensions.
In order to correctly manage virtual inheritance two extensions was created in **<bitsery/ext/inheritance.h>** header:
* **BaseClass\<TBase\>** - use when inheriting from objects without virtual inheritance.
* **VirtualBaseClass\<TBase\>** - ensures that only one copy of each virtual base class is serialized.

To keep track of virtual base classes **InheritanceContext** is required, but it is optional if no virtual bases exists in serialization flow.
I.e. if context is not defined, code will not compile only if virtual inheritance is used.
See [inheritance](examples/inheritance.cpp) for usage example.

### Improvements
* added optional ctor parameter for *PointerOwner* and *PointerObserver* - **PointerType**, which specifies if pointer can be null or not.
Default is **Nullable**.

# [4.1.0](https://github.com/fraillt/bitsery/compare/v4.0.1...v4.1.0) (2017-10-27)

### Features
Expand All @@ -12,9 +33,9 @@ In order to correctly manage pointer ownership, three extensions was created in

*Currently polimorphism and std::shared_ptr, std::unique_ptr is not supported.*

* added **context\<T\>()** overload to *BasicSerializer/BasicDeserializer* and now serializers is typesafe.
Also for better pointers support, added posibility to have multiple types in context with *std::tuple*.
E.g. when using pointers together with your custom context, you can define your context as *std::tuple\<PointerLinkingContext, MyContext\>* and in serialization function you can correctly get your data via *context\<MyContext\>()*.
* added **context\<T\>()** overload to *BasicSerializer/BasicDeserializer* and now they became typesafe.
For better extensions support, added posibility to have multiple types in context with *std::tuple*.
E.g. when using multiple extensions, that requires specific contexts, together with your custom context, you can define your context as *std::tuple\<PointerLinkingContext, MyContext\>* and in serialization function you can correctly get your data via *context\<MyContext\>()*.


### Improvements
Expand Down
8 changes: 5 additions & 3 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Library design:
* `errors handling`
* `forward/backward compatibility via Growable extension`
* `pointers`
* `inheritance`


Core Serializer/Deserializer functions (alphabetical order):
Expand All @@ -18,11 +19,14 @@ Core Serializer/Deserializer functions (alphabetical order):
* `container`
* `ext`
* `context`
* `context<T>`
* `contextOrNull<T>`
* `object`
* `text`
* `value`

Serializer/Deserializer extensions via `ext` method (alphabetical order):
* `BaseClass`
* `Entropy`
* `Growable`
* `PointerOwner`
Expand All @@ -34,6 +38,7 @@ Serializer/Deserializer extensions via `ext` method (alphabetical order):
* `StdSet`
* `StdStack`
* `ValueRange`
* `VirtualBaseClass`

AdapterWriter/Reader functions:
* `writeBits/readBits`
Expand Down Expand Up @@ -62,9 +67,6 @@ Output adapters (buffer and stream) functions:
Tips and tricks:
* if you're getting static assert "please define 'serialize' function", most likely it is because your **serialize** function is not defined in same namespace as object.

Limitations:
* max **text** or **container** size can be 2^(n-2) (where n = sizeof(std::size_t) * 8) for 32-bit systems it is 1073741823 (0x3FFFFFF).

Other:
* [Contributing](../CONTRIBUTING.md)
* [Change log](../CHANGELOG.md)
117 changes: 117 additions & 0 deletions examples/inheritance.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//
//this example coverls all the corner cases that can happen using inherintace
//in reality virtual inherintance is usually avoided, so your code would look much simpler.
//

#include <bitsery/bitsery.h>
#include <bitsery/adapter/buffer.h>
#include <bitsery/traits/vector.h>

//include inheritance extension
//this header contains two extensions, that specifies inheritance type of base class
// BaseClass - normal inheritance
// VirtualBaseClass - when virtual inheritance is used
//in order for virtual inheritance to work, InheritanceContext is required.
//it can be created either internally (via configuration) or externally (pointer to context).
#include <bitsery/ext/inheritance.h>

using bitsery::ext::BaseClass;
using bitsery::ext::VirtualBaseClass;

struct Base {
uint8_t x{};
//Base doesn't have to be polymorphic class, inheritance works at compile-time.
};
template <typename S>
void serialize(S& s, Base& o) {
s.value1b(o.x);
}

struct Derive1:virtual Base {// virtually inherits from base
uint8_t y1{};
};
template <typename S>
void serialize(S& s, Derive1& o) {
//define virtual inheritance, it will not compile if InheritanceContext is not defined in serializer/deserialzer
s.ext(o, VirtualBaseClass<Base>{});
s.value1b(o.y1);
}

//to make it more interesting, serialize private member
struct Derived2:virtual Base {
explicit Derived2(uint8_t y):y2{y} {}

uint8_t getY2() const {
return y2;
};
private:
friend bitsery::Access;
uint8_t y2{};
template <typename S>
void serialize(S& s) {
//notice virtual inheritance
s.ext(*this, VirtualBaseClass<Base>{});
s.value1b(y2);
}
};

struct MultipleInheritance: Derive1, Derived2 {
explicit MultipleInheritance(uint8_t y2):Derived2{y2} {}
uint8_t z{};
};
template <typename S>
void serialize(S& s, MultipleInheritance& o) {
//has two bases, serialize them separately
s.ext(o, BaseClass<Derive1>{});
s.ext(o, BaseClass<Derived2>{});
s.value1b(o.z);
}

namespace bitsery {
// call to serialize function with Derived2 and MultipleInheritance is ambiguous,
// it matches two serialize functions: Base classes non-member fnc and Derived2 member fnc
// we need explicitly select which function to use
template <>
struct SelectSerializeFnc<Derived2>:UseMemberFnc {};

//multiple inheritance has non-member serialize function defined
template <>
struct SelectSerializeFnc<MultipleInheritance>:UseNonMemberFnc {};
}

using namespace bitsery;

// since in this example we're using virtual inheritance we need InheritanceContext as well.
// InheritanceContext is default constructable and has no useful information outside of serializer/deserializer
// lets create it internally, via configuration
struct ConfigWithContext:DefaultConfig {
//always add internal contexts to tuple
using InternalContext = std::tuple<ext::InheritanceContext>;
};

//some helper types
using Buffer = std::vector<uint8_t>;
using Writer = AdapterWriter<OutputBufferAdapter<Buffer>, ConfigWithContext>;
using Reader = AdapterReader<InputBufferAdapter<Buffer>, ConfigWithContext>;

int main() {

MultipleInheritance data{98};
data.x = 254;
data.y1 = 47;
data.z = 1;

Buffer buf{};

BasicSerializer<Writer> ser{OutputBufferAdapter<Buffer>{buf}, nullptr};
ser.object(data);
auto writtenSize = AdapterAccess::getWriter(ser).writtenBytesCount();

MultipleInheritance res{0};
BasicDeserializer<Reader> des{InputBufferAdapter<Buffer>{buf.begin(), writtenSize}};
des.object(res);
assert(AdapterAccess::getReader(des).error() == ReaderError::NoError && AdapterAccess::getReader(des).isCompletedSuccessfully());

assert(data.x == res.x && data.y1 == res.y1 && data.getY2() == res.getY2() && data.z == res.z);
assert(writtenSize == 4);//base is serialized once, because it is inherited virtually
}
5 changes: 3 additions & 2 deletions examples/raw_pointers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using bitsery::ext::ReferencedByPointer;
using bitsery::ext::PointerObserver;
using bitsery::ext::PointerOwner;
using bitsery::ext::PointerType ;

enum class MyEnum:uint16_t { V1,V2,V3 };
struct MyStruct {
Expand Down Expand Up @@ -71,8 +72,8 @@ struct Test1Data {
});
//observer
s.ext(po1, PointerObserver{});
//owner
s.ext4b(pi1, PointerOwner{});
//owner, mark it as not null
s.ext4b(pi1, PointerOwner{PointerType::NotNull});

}
};
Expand Down
6 changes: 3 additions & 3 deletions include/bitsery/adapter/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
//SOFTWARE.


#ifndef BITSERY_ADAPTERS_INPUT_BUFFER_ADAPTER_H
#define BITSERY_ADAPTERS_INPUT_BUFFER_ADAPTER_H
#ifndef BITSERY_ADAPTER_BUFFER_H
#define BITSERY_ADAPTER_BUFFER_H

#include "../details/adapter_common.h"
#include "../traits/core/traits.h"
Expand Down Expand Up @@ -204,4 +204,4 @@ namespace bitsery {

}

#endif //BITSERY_ADAPTERS_INPUT_BUFFER_ADAPTER_H
#endif //BITSERY_ADAPTER_BUFFER_H
6 changes: 3 additions & 3 deletions include/bitsery/adapter/stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
//SOFTWARE.


#ifndef BITSERY_ADAPTERS_DYNAMIC_STREAM_H
#define BITSERY_ADAPTERS_DYNAMIC_STREAM_H
#ifndef BITSERY_ADAPTER_STREAM_H
#define BITSERY_ADAPTER_STREAM_H

#include "../details/adapter_common.h"
#include "../traits/array.h"
Expand Down Expand Up @@ -224,4 +224,4 @@ namespace bitsery {
using OutputBufferedStreamAdapter = BasicBufferedOutputStreamAdapter<char, std::char_traits<char>>;
}

#endif //BITSERY_ADAPTERS_DYNAMIC_STREAM_H
#endif //BITSERY_ADAPTER_STREAM_H
9 changes: 5 additions & 4 deletions include/bitsery/adapter_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@



#ifndef BITSERY_BASIC_READER_H
#define BITSERY_BASIC_READER_H
#ifndef BITSERY_ADAPTER_READER_H
#define BITSERY_ADAPTER_READER_H

#include "details/sessions.h"
#include <algorithm>
Expand All @@ -39,7 +39,7 @@ namespace bitsery {
struct AdapterReader {
//this is required by deserializer
static constexpr bool BitPackingEnabled = false;

using TConfig = Config;
using TValue = typename InputAdapter::TValue;

static_assert(details::IsDefined<TValue>::value, "Please define adapter traits or include from <bitsery/traits/...>");
Expand Down Expand Up @@ -154,6 +154,7 @@ namespace bitsery {
public:
//this is required by deserializer
static constexpr bool BitPackingEnabled = true;
using TConfig = typename TReader::TConfig;
//make TValue unsigned for bitpacking
using UnsignedValue = typename std::make_unsigned<typename TReader::TValue>::type;
using ScratchType = typename details::ScratchType<UnsignedValue>::type;
Expand Down Expand Up @@ -268,4 +269,4 @@ namespace bitsery {
};
}

#endif //BITSERY_BUFFER_READER_H
#endif //BITSERY_ADAPTER_READER_H
16 changes: 11 additions & 5 deletions include/bitsery/adapter_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@



#ifndef BITSERY_BASIC_WRITER_H
#define BITSERY_BASIC_WRITER_H
#ifndef BITSERY_ADAPTER_WRITER_H
#define BITSERY_ADAPTER_WRITER_H

#include "details/sessions.h"

Expand All @@ -33,10 +33,12 @@

namespace bitsery {

struct MeasureSize {
template <typename Config>
struct BasicMeasureSize {
//measure class is bit-packing enabled, no need to create wrapper for it
static constexpr bool BitPackingEnabled = true;

using TConfig = Config;
template<size_t SIZE, typename T>
void writeBytes(const T &) {
static_assert(std::is_integral<T>(), "");
Expand Down Expand Up @@ -95,6 +97,9 @@ namespace bitsery {
size_t _sessionsBytesCount{};
};

//helper type for default config
using MeasureSize = BasicMeasureSize<DefaultConfig>;


template <typename TWriter>
class AdapterWriterBitPackingWrapper;
Expand All @@ -103,7 +108,7 @@ namespace bitsery {
struct AdapterWriter {
//this is required by serializer
static constexpr bool BitPackingEnabled = false;

using TConfig = Config;
using TValue = typename OutputAdapter::TValue;

static_assert(details::IsDefined<TValue>::value, "Please define adapter traits or include from <bitsery/traits/...>");
Expand Down Expand Up @@ -207,6 +212,7 @@ namespace bitsery {
public:
//this is required by serializer
static constexpr bool BitPackingEnabled = true;
using TConfig = typename TWriter::TConfig;

//make TValue unsigned for bit packing
using UnsignedType = typename std::make_unsigned<typename TWriter::TValue>::type;
Expand Down Expand Up @@ -334,4 +340,4 @@ namespace bitsery {
};
}

#endif //BITSERY_BASIC_WRITER_H
#endif //BITSERY_ADAPTER_WRITER_H
2 changes: 1 addition & 1 deletion include/bitsery/bitsery.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#define BITSERY_BITSERY_H

#define BITSERY_MAJOR_VERSION 4
#define BITSERY_MINOR_VERSION 1
#define BITSERY_MINOR_VERSION 2
#define BITSERY_PATCH_VERSION 0

#define BITSERY_QUOTE_MACRO(name) #name
Expand Down
7 changes: 6 additions & 1 deletion include/bitsery/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#ifndef BITSERY_COMMON_H
#define BITSERY_COMMON_H

#include <tuple>

namespace bitsery {

/*
Expand All @@ -41,7 +43,10 @@ namespace bitsery {
//this functionality allows to support backward/forward compatibility
//however reading from streams is not supported, because this functionality requires random access to buffer.
static constexpr bool BufferSessionsEnabled = false;

//list of contexts that will be instanciated internally within serializer/deserializer.
//contexts must be default constructable.
//internal context has priority, if external context with the same type exists.
using InternalContext = std::tuple<>;
};

}
Expand Down
Loading

0 comments on commit f6d02ab

Please sign in to comment.