added more std containers

This commit is contained in:
fraillt
2017-10-04 10:10:59 +03:00
parent ab5cc8a2c0
commit 982374be42
54 changed files with 2234 additions and 400 deletions

View File

@@ -1,4 +1,4 @@
# [3.0.0](https://github.com/fraillt/bitsery/compare/v2.0.1...v3.0.0) (2017-09-21)
# [4.0.0](https://github.com/fraillt/bitsery/compare/v3.0.0...v4.0.0) (2017-10-02)
new flexible syntax
traits changed,
@@ -6,6 +6,14 @@ traits changed,
text is separate from container, only has length, and addNUL
buffer traits removed difference type
improved reading, writing performance (because of isContiguous and difference_type)
BasicBufferWriter/Reader no longer has bit-packing operations by default
Bit-packing is enabled via template parameter in Serializer/Deserializer, additionally added new method enableBitPacking.
Additionally Serializer/Deserializer is no longer copyable, because it stores bit-packer state.
ExtensionTraits gain additional patameter BitPackingRequired, static_asserts if bit-packing is not enabled.
Removed boolByte, boolBit, and added boolValue and it writes bit or byte, depeding on if bit-packing is enabled or not.
added missing std containers support: forward_list, deque, stack, queue, priority_queue, set, multiset, unordered_set, unordered_multiset
Renamed ContainerMap to StdMap, Optional to StdOptional
todo write tests:
bufferreader accepts const data

View File

@@ -82,7 +82,7 @@ int main() {
//2) create buffer writer that is able to write bytes or bits to buffer
BasicBufferWriter<NonDefaultConfig> bw{buffer};
//3) create serializer
BasicSerializer<NonDefaultConfig> ser{bw};
BasicSerializer<NonDefaultConfig, false> ser{bw};
//serialize object, can also be invoked like this: serialize(ser, data)
ser.object(data);
@@ -94,7 +94,7 @@ int main() {
//1) create buffer reader
BasicBufferReader<NonDefaultConfig> br{bw.getWrittenRange()};
//2) create deserializer
BasicDeserializer<NonDefaultConfig> des{br};
BasicDeserializer<NonDefaultConfig, false> des{br};
//deserialize same object, can also be invoked like this: serialize(des, data)
MyTypes::Monster res{};

View File

@@ -31,6 +31,9 @@
namespace bitsery {
template <typename Config>
class BitPackingReader;
template<typename Config>
struct BasicBufferReader {
@@ -50,12 +53,12 @@ namespace bitsery {
static_assert(sizeof(ValueType) == 1, "currently only supported BufferValueType is 1 byte");
}
BasicBufferReader(BufferRange<BufferIteratorType> range)
explicit BasicBufferReader(BufferRange<BufferIteratorType> range)
:BasicBufferReader(range.begin(), range.end()) {
static_assert(std::is_same<
typename std::iterator_traits<BufferIteratorType>::iterator_category,
std::random_access_iterator_tag>::value,
"BufferReader only accepts random access iterators");
"BufferReader only accepts random access iterators");
}
BasicBufferReader(const BasicBufferReader &) = delete;
@@ -69,13 +72,112 @@ namespace bitsery {
~BasicBufferReader() noexcept = default;
template<size_t SIZE, typename T>
void readBytes(T &v) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
directRead(&v, 1);
}
template<size_t SIZE, typename T>
void readBuffer(T *buf, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
directRead(buf, count);
}
void align() {
}
bool isCompletedSuccessfully() const {
return _bufferContext.isCompletedSuccessfully() && !_session.hasActiveSessions();
}
BufferReaderError getError() const {
auto err = _bufferContext.getError();
if (_session.hasActiveSessions() && err == BufferReaderError::BUFFER_OVERFLOW)
return BufferReaderError::NO_ERROR;
return err;
}
void setError(BufferReaderError error) {
return _bufferContext.setError(error);
}
void beginSession() {
if (getError() != BufferReaderError::INVALID_BUFFER_DATA) {
_session.begin();
}
}
void endSession() {
if (getError() != BufferReaderError::INVALID_BUFFER_DATA) {
_session.end();
}
}
private:
friend class BitPackingReader<Config>;
details::ReadBufferContext<BufferType> _bufferContext;
typename std::conditional<Config::BufferSessionsEnabled,
details::BufferSessionsReader<BasicBufferReader<Config>, details::ReadBufferContext<BufferType>>,
details::DisabledBufferSessionsReader<Config>>::type
_session;
template<typename T>
void directRead(T *v, size_t count) {
static_assert(!std::is_const<T>::value, "");
_bufferContext.read(reinterpret_cast<ValueType *>(v), sizeof(T) * count);
//swap each byte if nessesarry
_swapDataBits(v, count, std::integral_constant<bool,
Config::NetworkEndianness != details::getSystemEndianness()>{});
}
template<typename T>
void _swapDataBits(T *v, size_t count, std::true_type) {
std::for_each(v, std::next(v, count), [this](T &x) { x = details::swap(x); });
}
template<typename T>
void _swapDataBits(T *v, size_t count, std::false_type) {
//empty function because no swap is required
}
};
template<typename Config>
struct BitPackingReader {
using ValueType = typename details::ContainerTraits<typename Config::BufferType>::TValue;
using ScratchType = typename details::SCRATCH_TYPE<ValueType>::type;
explicit BitPackingReader(BasicBufferReader<Config>& reader):_reader{reader}
{
static_assert(std::is_unsigned<ValueType>(), "Config::BufferValueType must be unsigned");
static_assert(std::is_unsigned<ScratchType>(), "Config::BufferScrathType must be unsigned");
static_assert(sizeof(ValueType) * 2 == sizeof(ScratchType),
"ScratchType must be 2x bigger than value type");
static_assert(sizeof(ValueType) == 1, "currently only supported BufferValueType is 1 byte");
}
BitPackingReader(const BitPackingReader&) = delete;
BitPackingReader& operator = (const BitPackingReader&) = delete;
BitPackingReader(BitPackingReader&& ) noexcept = default;
BitPackingReader& operator = (BitPackingReader&& ) noexcept = default;
~BitPackingReader() {
align();
}
template<size_t SIZE, typename T>
void readBytes(T &v) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
using UT = typename std::make_unsigned<T>::type;
if (!m_scratchBits)
directRead(&v, 1);
_reader.template readBytes<SIZE,T>(v);
else
readBits(reinterpret_cast<UT &>(v), details::BITS_SIZE<T>::value);
}
@@ -86,7 +188,7 @@ namespace bitsery {
static_assert(sizeof(T) == SIZE, "");
if (!m_scratchBits) {
directRead(buf, count);
_reader.template readBuffer<SIZE,T>(buf, count);
} else {
using UT = typename std::make_unsigned<T>::type;
//todo improve implementation
@@ -113,61 +215,31 @@ namespace bitsery {
}
bool isCompletedSuccessfully() const {
return _bufferContext.isCompletedSuccessfully() && !_session.hasActiveSessions();
return _reader.isCompletedSuccessfully();
}
BufferReaderError getError() const {
auto err = _bufferContext.getError();
if (_session.hasActiveSessions() && err == BufferReaderError::BUFFER_OVERFLOW)
return BufferReaderError::NO_ERROR;
return err;
return _reader.getError();
}
void setError(BufferReaderError error) {
return _bufferContext.setError(error);
_reader.setError(error);
}
void beginSession() {
align();
if (getError() != BufferReaderError::INVALID_BUFFER_DATA) {
_session.begin();
}
_reader.beginSession();
}
void endSession() {
align();
if (getError() != BufferReaderError::INVALID_BUFFER_DATA) {
_session.end();
}
_reader.endSession();
}
private:
details::ReadBufferContext<BufferType> _bufferContext;
BasicBufferReader<Config>& _reader;
ScratchType m_scratch{};
size_t m_scratchBits{};
typename std::conditional<Config::BufferSessionsEnabled,
details::BufferSessionsReader<BasicBufferReader<Config>, details::ReadBufferContext<BufferType>>,
details::DisabledBufferSessionsReader<Config>>::type
_session;
template<typename T>
void directRead(T *v, size_t count) {
static_assert(!std::is_const<T>::value, "");
_bufferContext.read(reinterpret_cast<ValueType *>(v), sizeof(T) * count);
//swap each byte if nessesarry
_swapDataBits(v, count, std::integral_constant<bool,
Config::NetworkEndianness != details::getSystemEndianness()>{});
}
template<typename T>
void _swapDataBits(T *v, size_t count, std::true_type) {
std::for_each(v, std::next(v, count), [this](T &x) { x = details::swap(x); });
}
template<typename T>
void _swapDataBits(T *v, size_t count, std::false_type) {
//empty function because no swap is required
}
template<typename T>
void readBitsInternal(T &v, size_t size) {
@@ -177,7 +249,7 @@ namespace bitsery {
auto bits = std::min(bitsLeft, details::BITS_SIZE<ValueType>::value);
if (m_scratchBits < bits) {
ValueType tmp;
directRead(&tmp, 1);
_reader.template readBytes<sizeof(ValueType), ValueType>(tmp);
m_scratch |= static_cast<ScratchType>(tmp) << m_scratchBits;
m_scratchBits += details::BITS_SIZE<ValueType>::value;
}

View File

@@ -92,6 +92,10 @@ namespace bitsery {
size_t _sessionsBytesCount{};
};
template <typename Config>
class BitPackingWriter;
template<typename Config>
struct BasicBufferWriter {
using BufferType = typename Config::BufferType;
@@ -122,46 +126,23 @@ namespace bitsery {
void writeBytes(const T &v) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
directWrite(&v, 1);
if (!_scratchBits) {
directWrite(&v, 1);
} else {
using UT = typename std::make_unsigned<T>::type;
writeBits(reinterpret_cast<const UT &>(v), details::BITS_SIZE<T>::value);
}
}
template<size_t SIZE, typename T>
void writeBuffer(const T *buf, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
if (!_scratchBits) {
directWrite(buf, count);
} else {
using UT = typename std::make_unsigned<T>::type;
//todo improve implementation
const auto end = buf + count;
for (auto it = buf; it != end; ++it)
writeBits(reinterpret_cast<const UT &>(*it), details::BITS_SIZE<T>::value);
}
}
template<typename T>
void writeBits(const T &v, size_t bitsCount) {
static_assert(std::is_integral<T>() && std::is_unsigned<T>(), "");
assert(0 < bitsCount && bitsCount <= details::BITS_SIZE<T>::value);
assert(v <= (bitsCount < 64
? (1ULL << bitsCount) - 1
: (1ULL << (bitsCount-1)) + ((1ULL << (bitsCount-1)) -1)));
writeBitsInternal(v, bitsCount);
directWrite(buf, count);
}
//to have the same interface as bitpackingwriter
void align() {
writeBitsInternal(ValueType{}, (details::BITS_SIZE<ValueType>::value - _scratchBits) % 8);
}
void flush() {
align();
_session.flushSessions(*this);
}
@@ -170,17 +151,15 @@ namespace bitsery {
}
void beginSession() {
align();
_session.begin(*this);
}
void endSession() {
align();
_session.end(*this);
}
private:
friend class BitPackingWriter<Config>;
template<typename T>
void directWrite(T &&v, size_t count) {
_directWriteSwapTag(std::forward<T>(v), count, std::integral_constant<bool,
@@ -200,6 +179,100 @@ namespace bitsery {
_bufferContext.write(reinterpret_cast<const ValueType *>(v), count * sizeof(T));
}
BufferContext _bufferContext;
typename std::conditional<Config::BufferSessionsEnabled,
details::BufferSessionsWriter<BasicBufferWriter<Config>>,
details::DisabledBufferSessionsWriter<Config>>::type
_session{};
};
template<typename Config>
struct BitPackingWriter {
using ValueType = typename details::ContainerTraits<typename Config::BufferType>::TValue;
using ScratchType = typename details::SCRATCH_TYPE<ValueType>::type;
explicit BitPackingWriter(BasicBufferWriter<Config> &writer)
: _writer{writer}
{
static_assert(std::is_unsigned<ValueType>(), "Config::BufferType value type must be unsigned");
static_assert(sizeof(ValueType) * 2 == sizeof(ScratchType),
"ScratchType must be 2x bigger than value type");
static_assert(sizeof(ValueType) == 1, "currently only supported BufferValueType is 1 byte");
}
BitPackingWriter(const BitPackingWriter&) = delete;
BitPackingWriter& operator = (const BitPackingWriter&) = delete;
BitPackingWriter(BitPackingWriter&& ) noexcept = default;
BitPackingWriter& operator = (BitPackingWriter&& ) noexcept = default;
~BitPackingWriter() {
align();
}
template<size_t SIZE, typename T>
void writeBytes(const T &v) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
if (!_scratchBits) {
_writer.template writeBytes<SIZE,T>(v);
} else {
using UT = typename std::make_unsigned<T>::type;
writeBitsInternal(reinterpret_cast<const UT &>(v), details::BITS_SIZE<T>::value);
}
}
template<size_t SIZE, typename T>
void writeBuffer(const T *buf, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
if (!_scratchBits) {
_writer.template writeBuffer<SIZE,T>(buf, count);
} else {
using UT = typename std::make_unsigned<T>::type;
//todo improve implementation
const auto end = buf + count;
for (auto it = buf; it != end; ++it)
writeBitsInternal(reinterpret_cast<const UT &>(*it), details::BITS_SIZE<T>::value);
}
}
template<typename T>
void writeBits(const T &v, size_t bitsCount) {
static_assert(std::is_integral<T>() && std::is_unsigned<T>(), "");
assert(0 < bitsCount && bitsCount <= details::BITS_SIZE<T>::value);
assert(v <= (bitsCount < 64
? (1ULL << bitsCount) - 1
: (1ULL << (bitsCount-1)) + ((1ULL << (bitsCount-1)) -1)));
writeBitsInternal(v, bitsCount);
}
void align() {
writeBitsInternal(ValueType{}, (details::BITS_SIZE<ValueType>::value - _scratchBits) % 8);
}
void flush() {
align();
_writer._session.flushSessions(_writer);
}
BufferRange<typename details::BufferContainerTraits<typename Config::BufferType>::TIterator> getWrittenRange() const {
return _writer.getWrittenRange();
}
void beginSession() {
align();
_writer._session.begin(_writer);
}
void endSession() {
align();
_writer._session.end(_writer);
}
private:
template<typename T>
void writeBitsInternal(const T &v, size_t size) {
constexpr size_t valueSize = details::BITS_SIZE<ValueType>::value;
@@ -211,7 +284,7 @@ namespace bitsery {
_scratchBits += bits;
if (_scratchBits >= valueSize) {
auto tmp = static_cast<ValueType>(_scratch & _MASK);
directWrite(&tmp, 1);
_writer.template writeBytes<sizeof(ValueType), ValueType >(tmp);
_scratch >>= valueSize;
_scratchBits -= valueSize;
@@ -228,22 +301,18 @@ namespace bitsery {
_scratchBits += size;
if (_scratchBits >= details::BITS_SIZE<ValueType>::value) {
auto tmp = static_cast<ValueType>(_scratch & _MASK);
directWrite(&tmp, 1);
_writer.template writeBytes<sizeof(ValueType), ValueType>(tmp);
_scratch >>= details::BITS_SIZE<ValueType>::value;
_scratchBits -= details::BITS_SIZE<ValueType>::value;
}
}
}
const ValueType _MASK = std::numeric_limits<ValueType>::max();
BufferContext _bufferContext;
ScratchType _scratch{};
size_t _scratchBits{};
typename std::conditional<Config::BufferSessionsEnabled,
details::BufferSessionsWriter<BasicBufferWriter<Config>>,
details::DisabledBufferSessionsWriter<Config>>::type
_session{};
BasicBufferWriter<Config>& _writer;
};
//helper type

View File

@@ -31,10 +31,23 @@
namespace bitsery {
template<typename Config>
template<typename Config, bool BitPackingEnabled>
class BasicDeserializer {
public:
explicit BasicDeserializer(BasicBufferReader<Config> &r, void* context = nullptr) : _reader{r}, _context{context} {};
using BPEnabledType = BasicDeserializer<Config, true>;
explicit BasicDeserializer(BasicBufferReader<Config> &r, void* context = nullptr)
: _reader{r},
_context{context}
{};
//copying disabled
BasicDeserializer(const BasicDeserializer&) = delete;
BasicDeserializer& operator = (const BasicDeserializer&) = delete;
//move enabled
BasicDeserializer(BasicDeserializer&& ) noexcept = default;
BasicDeserializer& operator = (BasicDeserializer&& ) noexcept = default;
/*
* get serialization context.
@@ -50,8 +63,7 @@ namespace bitsery {
template<typename T>
void object(T &&obj) {
using TValue = typename std::decay<T>::type;
details::SerializeFunction<BasicDeserializer, TValue>::invoke(*this, std::forward<T>(obj));
details::SerializeFunction<BasicDeserializer, T>::invoke(*this, std::forward<T>(obj));
}
template<typename T, typename Fnc>
@@ -71,7 +83,7 @@ namespace bitsery {
}
/*
* value overloads
* value
*/
template<size_t VSIZE, typename T, typename std::enable_if<details::IsFundamentalType<T>::value>::type * = nullptr>
@@ -80,6 +92,14 @@ namespace bitsery {
_reader.template readBytes<VSIZE>(reinterpret_cast<TValue &>(v));
}
/*
* enable bit-packing
*/
template <typename Fnc>
void enableBitPacking(Fnc&& fnc) {
procEnableBitPacking(std::forward<Fnc>(fnc), std::integral_constant<bool, !BitPackingEnabled>{});
}
/*
* extension functions
*/
@@ -88,6 +108,8 @@ namespace bitsery {
void ext(T &obj, const Ext &extension, Fnc &&fnc) {
static_assert(details::ExtensionTraits<Ext,T>::SupportLambdaOverload,
"extension doesn't support overload with lambda");
static_assert(BitPackingEnabled || !details::ExtensionTraits<Ext,T>::BitPackingRequired,
"Extension requires bit-packing to be enabled, (call `enableBitPacking`)");
extension.deserialize(*this, _reader, obj, std::forward<Fnc>(fnc));
};
@@ -97,7 +119,9 @@ namespace bitsery {
"extension doesn't support overload with `value<N>`");
using ExtVType = typename details::ExtensionTraits<Ext, T>::TValue;
using VType = typename std::conditional<std::is_void<ExtVType>::value, details::DummyType, ExtVType>::type;
extension.deserialize(*this, _reader, obj, [this](VType &v) { value<VSIZE>(v); });
static_assert(BitPackingEnabled || !details::ExtensionTraits<Ext,T>::BitPackingRequired,
"Extension requires bit-packing to be enabled, (call `enableBitPacking`)");
extension.deserialize(*this, _reader, obj, [this](VType &v) { value<VSIZE>(v);});
};
template<typename T, typename Ext>
@@ -106,25 +130,16 @@ namespace bitsery {
"extension doesn't support overload with `object`");
using ExtVType = typename details::ExtensionTraits<Ext, T>::TValue;
using VType = typename std::conditional<std::is_void<ExtVType>::value, details::DummyType, ExtVType>::type;
static_assert(BitPackingEnabled || !details::ExtensionTraits<Ext,T>::BitPackingRequired,
"Extension requires bit-packing to be enabled, (call `enableBitPacking`)");
extension.deserialize(*this, _reader, obj, [this](VType &v) { object(v); });
};
/*
* bool
* boolValue
*/
void boolBit(bool &v) {
uint8_t tmp{};
_reader.readBits(tmp, 1);
v = tmp == 1;
}
void boolByte(bool &v) {
unsigned char tmp;
_reader.template readBytes<1>(tmp);
if (tmp > 1)
_reader.setError(BufferReaderError::INVALID_BUFFER_DATA);
v = tmp == 1;
void boolValue(bool &v) {
procBoolValue(v, std::integral_constant<bool, BitPackingEnabled>{});
}
/*
@@ -283,7 +298,11 @@ namespace bitsery {
void container8b(T &&obj) { container<8>(std::forward<T>(obj)); }
private:
BasicBufferReader<Config> &_reader;
typename std::conditional<BitPackingEnabled,
BitPackingReader<Config>,//by value
BasicBufferReader<Config>&//by reference
>::type _reader;
void* _context;
//process value types
@@ -329,6 +348,34 @@ namespace bitsery {
*end = {};
}
//proc bool writing bit or byte, depending on if BitPackingEnabled or not
void procBoolValue(bool &v, std::true_type) {
uint8_t tmp{};
_reader.readBits(tmp, 1);
v = tmp == 1;
}
void procBoolValue(bool &v, std::false_type) {
unsigned char tmp;
_reader.template readBytes<1>(tmp);
if (tmp > 1)
_reader.setError(BufferReaderError::INVALID_BUFFER_DATA);
v = tmp == 1;
}
//enable bit-packing or do nothing if it is already enabled
template <typename Fnc>
void procEnableBitPacking(const Fnc& fnc, std::true_type) {
BPEnabledType tmp{_reader, _context};
fnc(tmp);
}
template <typename Fnc>
void procEnableBitPacking(const Fnc& fnc, std::false_type) {
fnc(*this);
}
//these are dummy functions for extensions that have TValue = void
void object(details::DummyType&) {
@@ -346,7 +393,7 @@ namespace bitsery {
};
//helper type
using Deserializer = BasicDeserializer<DefaultConfig>;
using Deserializer = BasicDeserializer<DefaultConfig, false>;
}

View File

@@ -24,6 +24,7 @@
#define BITSERY_DETAILS_FLEXIBLE_COMMON_H
#include "traits.h"
#include <limits>
namespace bitsery {
namespace flexible {

View File

@@ -37,6 +37,7 @@ namespace bitsery {
}
};
namespace details {
//used for extensions, when extension TValue = void

View File

@@ -41,6 +41,12 @@ namespace bitsery {
//when this is void, it will compile, but value and object overloads will do nothing.
using TValue = void;
//specify if extension required bitpacking operations
//if current serialization instance is not bit-packing enabled,
//then new instance will be created with bit-packing enabled,
//and bits will be flushed automaticaly after extension finish executing.
static constexpr bool BitPackingRequired = false;
//does extension support ext<N>(...) syntax, by calling value<N> with TValue
static constexpr bool SupportValueOverload = true;
//does extension support ext(...) syntax, by calling object with TValue

View File

@@ -46,8 +46,14 @@ namespace bitsery {
class Entropy {
public:
constexpr explicit Entropy(TContainer& values) : _values{values} {
/**
* Allows entropy-encoding technique, by writing few bits for most common values
* @param values list of most common values
* @param alignBeforeData only makes sense when bit-packing enabled, by default aligns after writing bits for index
*/
constexpr Entropy(TContainer& values, bool alignBeforeData=true)
: _values{values},
_alignBeforeData{alignBeforeData} {
};
template<typename Ser, typename Writer, typename T, typename Fnc>
@@ -55,6 +61,8 @@ namespace bitsery {
assert(details::ContainerTraits<TContainer>::size(_values) > 0);
auto index = details::findEntropyIndex(obj, _values);
s.ext(index, ext::ValueRange<size_t>{0u, details::ContainerTraits<TContainer>::size(_values)});
if (_alignBeforeData)
s.align();
if (!index)
fnc(const_cast<T &>(obj));
}
@@ -64,6 +72,8 @@ namespace bitsery {
assert(details::ContainerTraits<TContainer>::size(_values) > 0);
size_t index{};
d.ext(index, ext::ValueRange<size_t>{0u, details::ContainerTraits<TContainer>::size(_values)});
if (_alignBeforeData)
d.align();
if (index)
obj = *std::next(std::begin(_values), index-1);
else
@@ -72,6 +82,7 @@ namespace bitsery {
private:
TContainer& _values;
bool _alignBeforeData;
};
}
@@ -79,6 +90,7 @@ namespace bitsery {
template<typename TContainer, typename T>
struct ExtensionTraits<ext::Entropy<TContainer>, T> {
using TValue = T;
static constexpr bool BitPackingRequired = true;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;

View File

@@ -53,6 +53,7 @@ namespace bitsery {
template<typename T>
struct ExtensionTraits<ext::Growable, T> {
using TValue = T;
static constexpr bool BitPackingRequired = false;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;

View File

@@ -20,16 +20,18 @@
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
#ifndef BITSERY_EXT_CONTAINER_MAP_H
#define BITSERY_EXT_CONTAINER_MAP_H
#ifndef BITSERY_EXT_STD_MAP_H
#define BITSERY_EXT_STD_MAP_H
#include "../details/both_common.h"
namespace bitsery {
namespace ext {
class ContainerMap {
class StdMap {
public:
constexpr explicit ContainerMap(size_t maxSize):_maxSize{maxSize} {}
constexpr explicit StdMap(size_t maxSize):_maxSize{maxSize} {}
template<typename Ser, typename Writer, typename T, typename Fnc>
void serialize(Ser &, Writer &writer, const T &obj, Fnc &&fnc) const {
@@ -67,8 +69,9 @@ namespace bitsery {
namespace details {
template<typename T>
struct ExtensionTraits<ext::ContainerMap, T> {
struct ExtensionTraits<ext::StdMap, T> {
using TValue = void;
static constexpr bool BitPackingRequired = false;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = true;
@@ -78,4 +81,4 @@ namespace bitsery {
}
#endif //BITSERY_EXT_CONTAINER_MAP_H
#endif //BITSERY_EXT_STD_MAP_H

View File

@@ -21,8 +21,8 @@
//SOFTWARE.
#ifndef BITSERY_EXT_OPTIONAL_H
#define BITSERY_EXT_OPTIONAL_H
#ifndef BITSERY_EXT_STD_OPTIONAL_H
#define BITSERY_EXT_STD_OPTIONAL_H
//this module do not include optional, but expects it to be declared in std::optional
@@ -40,9 +40,14 @@ namespace bitsery {
template<typename T>
using std_optional = ::std::optional<T>;
class Optional {
class StdOptional {
public:
/**
* Works with std::optional types
* @param alignBeforeData only makes sense when bit-packing enabled, by default aligns after writing/reading bool state of optional
*/
explicit StdOptional(bool alignBeforeData=true):_alignBeforeData{alignBeforeData} {}
template<typename T>
constexpr void assertType() const {
using TOpt = typename std::remove_cv<T>::type;
@@ -54,7 +59,9 @@ namespace bitsery {
template<typename Ser, typename Writer, typename T, typename Fnc>
void serialize(Ser &ser, Writer &, const T &obj, Fnc &&fnc) const {
assertType<T>();
ser.boolByte(static_cast<bool>(obj));
ser.boolValue(static_cast<bool>(obj));
if (_alignBeforeData)
ser.align();
if (obj)
fnc(const_cast<typename T::value_type & >(*obj));
}
@@ -63,7 +70,9 @@ namespace bitsery {
void deserialize(Des &des, Reader &, T &obj, Fnc &&fnc) const {
assertType<T>();
bool exists{};
des.boolByte(exists);
des.boolValue(exists);
if (_alignBeforeData)
des.align();
if (exists) {
typename T::value_type tmp{};
fnc(tmp);
@@ -73,13 +82,16 @@ namespace bitsery {
obj = T{};
}
}
private:
bool _alignBeforeData;
};
}
namespace details {
template<typename T>
struct ExtensionTraits<ext::Optional, T> {
struct ExtensionTraits<ext::StdOptional, T> {
using TValue = typename T::value_type;
static constexpr bool BitPackingRequired = false;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
@@ -89,4 +101,4 @@ namespace bitsery {
}
#endif //BITSERY_EXT_OPTIONAL_H
#endif //BITSERY_EXT_STD_OPTIONAL_H

View File

@@ -0,0 +1,112 @@
//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.
#ifndef BITSERY_EXT_STD_QUEUE_H
#define BITSERY_EXT_STD_QUEUE_H
#include <type_traits>
#include <queue>
//include type traits for deque and vector, because they are defaults for queue and priority_queue
#include "../traits/deque.h"
#include "../traits/vector.h"
namespace bitsery {
namespace ext {
class StdQueue {
private:
//inherit from queue so we could take underlying container
template <typename T, typename C>
struct QueueCnt : public std::queue<T, C>
{
static const C& getContainer(const std::queue<T, C>& s )
{
//get address of underlying container
return s.*(&QueueCnt::c);
}
static C& getContainer(std::queue<T, C>& s )
{
//get address of underlying container
return s.*(&QueueCnt::c);
}
};
//inherit from queue so we could take underlying container
template <typename T, typename C>
struct PriorityQueueCnt : public std::priority_queue<T, C>
{
static const C& getContainer(const std::priority_queue<T, C>& s )
{
//get address of underlying container
return s.*(&PriorityQueueCnt::c);
}
static C& getContainer(std::priority_queue<T, C>& s )
{
//get address of underlying container
return s.*(&PriorityQueueCnt::c);
}
};
size_t _maxSize;
public:
explicit StdQueue(size_t maxSize):_maxSize{maxSize} {};
//for queue
template<typename Ser, typename Writer, typename T, typename C, typename Fnc>
void serialize(Ser &ser, Writer &, const std::queue<T,C> &obj, Fnc &&fnc) const {
ser.container(QueueCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename Reader, typename T, typename C, typename Fnc>
void deserialize(Des &des, Reader &, std::queue<T,C> &obj, Fnc &&fnc) const {
des.container(QueueCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
//for priority_queue
template<typename Ser, typename Writer, typename T, typename C, typename Fnc>
void serialize(Ser &ser, Writer &, const std::priority_queue<T,C> &obj, Fnc &&fnc) const {
ser.container(PriorityQueueCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename Reader, typename T, typename C, typename Fnc>
void deserialize(Des &des, Reader &, std::priority_queue<T,C> &obj, Fnc &&fnc) const {
des.container(PriorityQueueCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
};
}
namespace details {
template<typename T>
struct ExtensionTraits<ext::StdQueue, T> {
using TValue = typename T::value_type;
static constexpr bool BitPackingRequired = false;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_QUEUE_H

View File

@@ -0,0 +1,98 @@
//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.
#ifndef BITSERY_EXT_STD_SET_H
#define BITSERY_EXT_STD_SET_H
#include <cassert>
#include "../details/both_common.h"
//we need this, so we could
#include <unordered_set>
namespace bitsery {
namespace ext {
class StdSet {
public:
constexpr explicit StdSet(size_t maxSize):_maxSize{maxSize} {}
template<typename Ser, typename Writer, typename T, typename Fnc>
void serialize(Ser &, Writer &writer, const T &obj, Fnc &&fnc) const {
using TKey = typename T::key_type;
auto size = obj.size();
assert(size <= _maxSize);
details::writeSize(writer, size);
for (auto &v:obj)
fnc(const_cast<TKey &>(v));
}
template<typename Des, typename Reader, typename T, typename Fnc>
void deserialize(Des &, Reader &reader, T &obj, Fnc &&fnc) const {
using TKey = typename T::key_type;
size_t size{};
details::readSize(reader, size, _maxSize);
auto hint = obj.begin();
obj.clear();
reserve(obj, size);
for (auto i = 0u; i < size; ++i) {
TKey key;
fnc(key);
hint = obj.emplace_hint(hint, std::move(key));
}
}
private:
template <typename T>
void reserve(std::unordered_set<T>& obj, size_t size) const {
obj.reserve(size);
}
template <typename T>
void reserve(std::unordered_multiset<T>& obj, size_t size) const {
obj.reserve(size);
}
template <typename T>
void reserve(T obj, size_t size) const {
//for ordered container do nothing
}
size_t _maxSize;
};
}
namespace details {
template<typename T>
struct ExtensionTraits<ext::StdSet, T> {
using TValue = typename T::key_type;
static constexpr bool BitPackingRequired = false;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_SET_H

View File

@@ -0,0 +1,83 @@
//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.
#ifndef BITSERY_EXT_STD_STACK_H
#define BITSERY_EXT_STD_STACK_H
#include <type_traits>
#include <stack>
//include type traits for deque, because stack default underlying container is deque
#include "../traits/deque.h"
namespace bitsery {
namespace ext {
class StdStack {
private:
//inherit from stack so we could take underlying container
template <typename T, typename C>
struct StackCnt : public std::stack<T, C>
{
static const C& getContainer(const std::stack<T, C>& s )
{
//get address of underlying container
return s.*(&StackCnt::c);
}
static C& getContainer(std::stack<T, C>& s )
{
//get address of underlying container
return s.*(&StackCnt::c);
}
};
size_t _maxSize;
public:
explicit StdStack(size_t maxSize):_maxSize{maxSize} {};
template<typename Ser, typename Writer, typename T, typename C, typename Fnc>
void serialize(Ser &ser, Writer &, const std::stack<T,C> &obj, Fnc &&fnc) const {
ser.container(StackCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename Reader, typename T, typename C, typename Fnc>
void deserialize(Des &des, Reader &, std::stack<T,C> &obj, Fnc &&fnc) const {
des.container(StackCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
};
}
namespace details {
template<typename T>
struct ExtensionTraits<ext::StdStack, T> {
using TValue = typename T::value_type;
static constexpr bool BitPackingRequired = false;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_STACK_H

View File

@@ -194,6 +194,7 @@ namespace bitsery {
template<typename T>
struct ExtensionTraits<ext::ValueRange<T>, T> {
using TValue = void;
static constexpr bool BitPackingRequired = true;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;

View File

@@ -73,7 +73,7 @@ namespace bitsery {
//define serialize function for fundamental types
template<typename S>
void serialize(S &s, bool &v) {
s.boolByte(v);
s.boolValue(v);
}
template<typename S, typename T, typename std::enable_if<details::IsFundamentalType<T>::value>::type * = nullptr>
@@ -85,14 +85,14 @@ namespace bitsery {
//if array is integral type, specify explicitly how to process: as text or container
template<typename S, typename T, size_t N, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
void serialize(S &s, T (&v)[N]) {
void serialize(S &s, T (&obj)[N]) {
static_assert(N == 0,
"\nPlease use 'asText(obj)' or 'asContainer(obj)' when using c-style array with integral types\n");
};
template<typename S, typename T, size_t N, typename std::enable_if<!std::is_integral<T>::value>::type * = nullptr>
void serialize(S &s, T (&obj)[N]) {
s.container(obj);
flexible::processContainer(s, obj);
};
}

View File

@@ -21,8 +21,8 @@
//SOFTWARE.
#ifndef BITSERY_FLEXIBLE_TYPE_ARRAY_H
#define BITSERY_FLEXIBLE_TYPE_ARRAY_H
#ifndef BITSERY_FLEXIBLE_TYPE_STD_ARRAY_H
#define BITSERY_FLEXIBLE_TYPE_STD_ARRAY_H
#include "../traits/array.h"
#include "../details/flexible_common.h"
@@ -34,4 +34,4 @@ namespace bitsery {
}
}
#endif //BITSERY_FLEXIBLE_TYPE_ARRAY_H
#endif //BITSERY_FLEXIBLE_TYPE_STD_ARRAY_H

View File

@@ -0,0 +1,37 @@
//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.
#ifndef BITSERY_FLEXIBLE_TYPE_STD_DEQUE_H
#define BITSERY_FLEXIBLE_TYPE_STD_DEQUE_H
#include "../traits/deque.h"
#include "../details/flexible_common.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::deque<TArgs... > &obj) {
flexible::processContainer(s, obj);
}
}
#endif //BITSERY_FLEXIBLE_TYPE_STD_DEQUE_H

View File

@@ -0,0 +1,37 @@
//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.
#ifndef BITSERY_FLEXIBLE_TYPE_STD_FORWARD_LIST_H
#define BITSERY_FLEXIBLE_TYPE_STD_FORWARD_LIST_H
#include "../traits/forward_list.h"
#include "../details/flexible_common.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::forward_list<TArgs... > &obj) {
flexible::processContainer(s, obj);
}
}
#endif //BITSERY_FLEXIBLE_TYPE_STD_FORWARD_LIST_H

View File

@@ -21,8 +21,8 @@
//SOFTWARE.
#ifndef BITSERY_FLEXIBLE_TYPE_LIST_H
#define BITSERY_FLEXIBLE_TYPE_LIST_H
#ifndef BITSERY_FLEXIBLE_TYPE_STD_LIST_H
#define BITSERY_FLEXIBLE_TYPE_STD_LIST_H
#include "../traits/list.h"
#include "../details/flexible_common.h"
@@ -34,4 +34,4 @@ namespace bitsery {
}
}
#endif //BITSERY_FLEXIBLE_TYPE_LIST_H
#endif //BITSERY_FLEXIBLE_TYPE_STD_LIST_H

View File

@@ -21,18 +21,29 @@
//SOFTWARE.
#ifndef BITSERY_FLEXIBLE_TYPE_MAP_H
#define BITSERY_FLEXIBLE_TYPE_MAP_H
#ifndef BITSERY_FLEXIBLE_TYPE_STD_MAP_H
#define BITSERY_FLEXIBLE_TYPE_STD_MAP_H
#include <map>
#include "../ext/container_map.h"
#include "bitsery/ext/std_map.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::map<TArgs ... > &obj) {
using TKey = typename std::map<TArgs...>::key_type;
using TValue = typename std::map<TArgs...>::mapped_type;
s.ext(obj, ext::ContainerMap{std::numeric_limits<size_t>::max()},
s.ext(obj, ext::StdMap{std::numeric_limits<size_t>::max()},
[&s](TKey& key, TValue& value) {
s.object(key);
s.object(value);
});
}
template<typename S, typename ... TArgs>
void serialize(S &s, std::multimap<TArgs ... > &obj) {
using TKey = typename std::multimap<TArgs...>::key_type;
using TValue = typename std::multimap<TArgs...>::mapped_type;
s.ext(obj, ext::StdMap{std::numeric_limits<size_t>::max()},
[&s](TKey& key, TValue& value) {
s.object(key);
s.object(value);
@@ -40,4 +51,4 @@ namespace bitsery {
}
}
#endif //BITSERY_FLEXIBLE_TYPE_MAP_H
#endif //BITSERY_FLEXIBLE_TYPE_STD_MAP_H

View File

@@ -0,0 +1,42 @@
//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.
#ifndef BITSERY_FLEXIBLE_TYPE_STD_QUEUE_H
#define BITSERY_FLEXIBLE_TYPE_STD_QUEUE_H
#include "../ext/std_queue.h"
namespace bitsery {
template<typename S, typename T, typename C>
void serialize(S &s, std::queue<T, C> &obj) {
s.ext(obj, ext::StdQueue{std::numeric_limits<size_t>::max()});
}
template<typename S, typename T, typename C, typename Comp>
void serialize(S &s, std::priority_queue<T, C, Comp> &obj) {
s.ext(obj, ext::StdQueue{std::numeric_limits<size_t>::max()});
}
}
#endif //BITSERY_FLEXIBLE_TYPE_STD_QUEUE_H

View File

@@ -0,0 +1,43 @@
//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.
#ifndef BITSERY_FLEXIBLE_TYPE_STD_SET_H
#define BITSERY_FLEXIBLE_TYPE_STD_SET_H
#include <set>
#include "../ext/std_set.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::set<TArgs...> &obj) {
s.ext(obj, ext::StdSet{std::numeric_limits<size_t>::max()});
}
template<typename S, typename ... TArgs>
void serialize(S &s, std::multiset<TArgs...> &obj) {
s.ext(obj, ext::StdSet{std::numeric_limits<size_t>::max()});
}
}
#endif //BITSERY_FLEXIBLE_TYPE_STD_SET_H

View File

@@ -0,0 +1,36 @@
//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.
#ifndef BITSERY_FLEXIBLE_TYPE_STD_STACK_H
#define BITSERY_FLEXIBLE_TYPE_STD_STACK_H
#include "../ext/std_stack.h"
namespace bitsery {
template<typename S, typename T, typename C>
void serialize(S &s, std::stack<T, C> &obj) {
s.ext(obj, ext::StdStack{std::numeric_limits<size_t>::max()});
}
}
#endif //BITSERY_FLEXIBLE_TYPE_STD_STACK_H

View File

@@ -21,8 +21,8 @@
//SOFTWARE.
#ifndef BITSERY_FLEXIBLE_TYPE_STRING_H
#define BITSERY_FLEXIBLE_TYPE_STRING_H
#ifndef BITSERY_FLEXIBLE_TYPE_STD_STRING_H
#define BITSERY_FLEXIBLE_TYPE_STD_STRING_H
#include "../traits/string.h"
#include "../details/flexible_common.h"
@@ -34,4 +34,4 @@ namespace bitsery {
}
}
#endif //BITSERY_FLEXIBLE_TYPE_STRING_H
#endif //BITSERY_FLEXIBLE_TYPE_STD_STRING_H

View File

@@ -21,23 +21,35 @@
//SOFTWARE.
#ifndef BITSERY_FLEXIBLE_TYPE_UNORDERED_MAP_H
#define BITSERY_FLEXIBLE_TYPE_UNORDERED_MAP_H
#ifndef BITSERY_FLEXIBLE_TYPE_STD_UNORDERED_MAP_H
#define BITSERY_FLEXIBLE_TYPE_STD_UNORDERED_MAP_H
#include <unordered_map>
#include "../ext/container_map.h"
#include "bitsery/ext/std_map.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::unordered_map<TArgs ... > &obj) {
using TKey = typename std::unordered_map<TArgs...>::key_type;
using TValue = typename std::unordered_map<TArgs...>::mapped_type;
s.ext(obj, ext::ContainerMap{std::numeric_limits<size_t>::max()},
s.ext(obj, ext::StdMap{std::numeric_limits<size_t>::max()},
[&s](TKey& key, TValue& value) {
s.object(key);
s.object(value);
});
}
template<typename S, typename ... TArgs>
void serialize(S &s, std::unordered_multimap<TArgs ... > &obj) {
using TKey = typename std::unordered_multimap<TArgs...>::key_type;
using TValue = typename std::unordered_multimap<TArgs...>::mapped_type;
s.ext(obj, ext::StdMap{std::numeric_limits<size_t>::max()},
[&s](TKey& key, TValue& value) {
s.object(key);
s.object(value);
});
}
}
#endif //BITSERY_FLEXIBLE_TYPE_UNORDERED_MAP_H
#endif //BITSERY_FLEXIBLE_TYPE_STD_UNORDERED_MAP_H

View File

@@ -0,0 +1,43 @@
//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.
#ifndef BITSERY_FLEXIBLE_TYPE_STD_UNORDERED_SET_H
#define BITSERY_FLEXIBLE_TYPE_STD_UNORDERED_SET_H
#include <unordered_set>
#include "../ext/std_set.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::unordered_set<TArgs...> &obj) {
s.ext(obj, ext::StdSet{std::numeric_limits<size_t>::max()});
}
template<typename S, typename ... TArgs>
void serialize(S &s, std::unordered_multiset<TArgs...> &obj) {
s.ext(obj, ext::StdSet{std::numeric_limits<size_t>::max()});
}
}
#endif //BITSERY_FLEXIBLE_TYPE_STD_UNORDERED_SET_H

View File

@@ -21,8 +21,8 @@
//SOFTWARE.
#ifndef BITSERY_FLEXIBLE_TYPE_VECTOR_H
#define BITSERY_FLEXIBLE_TYPE_VECTOR_H
#ifndef BITSERY_FLEXIBLE_TYPE_STD_VECTOR_H
#define BITSERY_FLEXIBLE_TYPE_STD_VECTOR_H
#include "../traits/vector.h"
#include "../details/flexible_common.h"
@@ -34,4 +34,4 @@ namespace bitsery {
}
}
#endif //BITSERY_FLEXIBLE_TYPE_VECTOR_H
#endif //BITSERY_FLEXIBLE_TYPE_STD_VECTOR_H

View File

@@ -30,10 +30,23 @@
namespace bitsery {
template<typename Config>
template<typename Config, bool BitPackingEnabled>
class BasicSerializer {
public:
explicit BasicSerializer(BasicBufferWriter<Config> &w, void* context = nullptr) : _writter{w}, _context{context} {};
using BPEnabledType = BasicSerializer<Config, true>;
explicit BasicSerializer(BasicBufferWriter<Config> &w, void* context = nullptr)
: _writer{w},
_context{context}
{};
//copying disabled
BasicSerializer(const BasicSerializer&) = delete;
BasicSerializer& operator = (const BasicSerializer&) = delete;
//move enabled
BasicSerializer(BasicSerializer&& ) noexcept = default;
BasicSerializer& operator = (BasicSerializer&& ) noexcept = default;
/*
* get serialization context.
@@ -74,7 +87,15 @@ namespace bitsery {
template<size_t VSIZE, typename T, typename std::enable_if<details::IsFundamentalType<T>::value>::type * = nullptr>
void value(const T &v) {
using TValue = typename details::IntegralFromFundamental<T>::TValue;
_writter.template writeBytes<VSIZE>(reinterpret_cast<const TValue &>(v));
_writer.template writeBytes<VSIZE>(reinterpret_cast<const TValue &>(v));
}
/*
* enable bit-packing
*/
template <typename Fnc>
void enableBitPacking(Fnc&& fnc) {
procEnableBitPacking(std::forward<Fnc>(fnc), std::integral_constant<bool, !BitPackingEnabled>{});
}
/*
@@ -85,7 +106,9 @@ namespace bitsery {
void ext(const T &obj, const Ext &extension, Fnc &&fnc) {
static_assert(details::ExtensionTraits<Ext,T>::SupportLambdaOverload,
"extension doesn't support overload with lambda");
extension.serialize(*this, _writter, obj, std::forward<Fnc>(fnc));
static_assert(BitPackingEnabled || !details::ExtensionTraits<Ext,T>::BitPackingRequired,
"Extension requires bit-packing to be enabled, (call `enableBitPacking`)");
extension.serialize(*this, _writer, obj, std::forward<Fnc>(fnc));
};
template<size_t VSIZE, typename T, typename Ext>
@@ -94,7 +117,9 @@ namespace bitsery {
"extension doesn't support overload with `value<N>`");
using ExtVType = typename details::ExtensionTraits<Ext, T>::TValue;
using VType = typename std::conditional<std::is_void<ExtVType>::value, details::DummyType, ExtVType>::type;
extension.serialize(*this, _writter, obj, [this](VType &v) { value<VSIZE>(v); });
static_assert(BitPackingEnabled || !details::ExtensionTraits<Ext,T>::BitPackingRequired,
"Extension requires bit-packing to be enabled, (call `enableBitPacking`)");
extension.serialize(*this, _writer, obj, [this](VType &v) { value<VSIZE>(v); });
};
template<typename T, typename Ext>
@@ -103,19 +128,17 @@ namespace bitsery {
"extension doesn't support overload with `object`");
using ExtVType = typename details::ExtensionTraits<Ext, T>::TValue;
using VType = typename std::conditional<std::is_void<ExtVType>::value, details::DummyType, ExtVType>::type;
extension.serialize(*this, _writter, obj, [this](VType &v) { object(v); });
static_assert(BitPackingEnabled || !details::ExtensionTraits<Ext,T>::BitPackingRequired,
"Extension requires bit-packing to be enabled, (call `enableBitPacking`)");
extension.serialize(*this, _writer, obj, [this](VType &v) { object(v); });
};
/*
* bool
* boolValue
*/
void boolBit(bool v) {
_writter.writeBits(static_cast<unsigned char>(v ? 1 : 0), 1);
}
void boolByte(bool v) {
_writter.template writeBytes<1>(static_cast<unsigned char>(v ? 1 : 0));
void boolValue(bool v) {
procBoolValue(v, std::integral_constant<bool, BitPackingEnabled>{});
}
/*
@@ -149,7 +172,7 @@ namespace bitsery {
"use container(const T&, Fnc) overload without `maxSize` for static containers");
auto size = details::ContainerTraits<T>::size(obj);
assert(size <= maxSize);
details::writeSize(_writter, size);
details::writeSize(_writer, size);
procContainer(std::begin(obj), std::end(obj), std::forward<Fnc>(fnc));
}
@@ -160,7 +183,7 @@ namespace bitsery {
static_assert(VSIZE > 0, "");
auto size = details::ContainerTraits<T>::size(obj);
assert(size <= maxSize);
details::writeSize(_writter, size);
details::writeSize(_writer, size);
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::integral_constant<bool, details::ContainerTraits<T>::isContiguous>{});
}
@@ -171,7 +194,7 @@ namespace bitsery {
"use container(const T&) overload without `maxSize` for static containers");
auto size = details::ContainerTraits<T>::size(obj);
assert(size <= maxSize);
details::writeSize(_writter, size);
details::writeSize(_writer, size);
procContainer(std::begin(obj), std::end(obj));
}
@@ -200,7 +223,7 @@ namespace bitsery {
}
void align() {
_writter.align();
_writer.align();
}
//overloads for functions with explicit type size
@@ -272,7 +295,11 @@ namespace bitsery {
void container8b(T &&obj) { container<8>(std::forward<T>(obj)); }
private:
BasicBufferWriter<Config> &_writter;
typename std::conditional<BitPackingEnabled,
BitPackingWriter<Config>,//by value
BasicBufferWriter<Config>&//by reference
>::type _writer;
void* _context;
//process value types
@@ -290,7 +317,8 @@ namespace bitsery {
using TValue = typename std::decay<decltype(*first)>::type;
using TIntegral = typename details::IntegralFromFundamental<TValue>::TValue;
if (first != last)
_writter.template writeBuffer<VSIZE>(reinterpret_cast<const TIntegral*>(&(*first)), std::distance(first, last));
_writer.template writeBuffer<VSIZE>(reinterpret_cast<const TIntegral*>(&(*first)),
static_cast<size_t>(std::distance(first, last)));
};
//process by calling functions
@@ -307,7 +335,7 @@ namespace bitsery {
void procText(const T& str, size_t maxSize) {
auto length = details::TextTraits<T>::length(str);
assert((length + (details::TextTraits<T>::addNUL ? 1u : 0u)) <= maxSize);
details::writeSize(_writter, length);
details::writeSize(_writer, length);
auto begin = std::begin(str);
procContainer<VSIZE>(begin, std::next(begin, length), std::integral_constant<bool, details::ContainerTraits<T>::isContiguous>{});
};
@@ -319,6 +347,27 @@ namespace bitsery {
object(*first);
};
//proc bool writing bit or byte, depending on if BitPackingEnabled or not
void procBoolValue(bool v, std::true_type) {
_writer.writeBits(static_cast<unsigned char>(v ? 1 : 0), 1);
}
void procBoolValue(bool v, std::false_type) {
_writer.template writeBytes<1>(static_cast<unsigned char>(v ? 1 : 0));
}
//enable bit-packing or do nothing if it is already enabled
template <typename Fnc>
void procEnableBitPacking(const Fnc& fnc, std::true_type) {
BPEnabledType tmp{_writer, _context};
fnc(tmp);
}
template <typename Fnc>
void procEnableBitPacking(const Fnc& fnc, std::false_type) {
fnc(*this);
}
//these are dummy functions for extensions that have TValue = void
void object(const details::DummyType&) {
@@ -336,7 +385,7 @@ namespace bitsery {
};
//helper type
using Serializer = BasicSerializer<DefaultConfig>;
using Serializer = BasicSerializer<DefaultConfig, false>;
}
#endif //BITSERY_SERIALIZER_H

View File

@@ -21,8 +21,8 @@
//SOFTWARE.
#ifndef BITSERY_TRAITS_ARRAY_H
#define BITSERY_TRAITS_ARRAY_H
#ifndef BITSERY_TRAITS_STD_ARRAY_H
#define BITSERY_TRAITS_STD_ARRAY_H
#include "helper/std_defaults.h"
#include <array>
@@ -41,4 +41,4 @@ namespace bitsery {
}
#endif //BITSERY_TYPE_TRAITS_ARRAY_H
#endif //BITSERY_TYPE_TRAITS_STD_ARRAY_H

View File

@@ -0,0 +1,42 @@
//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.
#ifndef BITSERY_TRAITS_STD_DEQUE_H
#define BITSERY_TRAITS_STD_DEQUE_H
#include "helper/std_defaults.h"
#include <deque>
namespace bitsery {
namespace details {
template<typename ... TArgs>
struct ContainerTraits<std::deque<TArgs...>>
: public StdContainer<std::deque<TArgs...>, true, false> {};
}
}
#endif //BITSERY_TRAITS_STD_DEQUE_H

View File

@@ -0,0 +1,49 @@
//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.
#ifndef BITSERY_TRAITS_STD_FORWARD_LIST_H
#define BITSERY_TRAITS_STD_FORWARD_LIST_H
#include <forward_list>
namespace bitsery {
namespace details {
template<typename ... TArgs>
struct ContainerTraits<std::forward_list<TArgs...>> {
using TValue = typename std::forward_list<TArgs...>::value_type;
static constexpr bool isResizable = true;
static constexpr bool isContiguous = false;
static size_t size(const std::forward_list<TArgs...>& container) {
return static_cast<size_t>(std::distance(container.begin(), container.end()));
}
static void resize(std::forward_list<TArgs...>& container, size_t size) {
container.resize(size);
}
};
}
}
#endif //BITSERY_TRAITS_STD_FORWARD_LIST_H

View File

@@ -0,0 +1,78 @@
//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.
#ifndef BITSERY_TRAITS_HELPER_STD_DEFAULTS_H
#define BITSERY_TRAITS_HELPER_STD_DEFAULTS_H
namespace bitsery {
namespace details {
/*
* these are helper types, to easier write specializations for std types
*/
template<typename T, bool Resizable, bool Contiguous>
struct StdContainer {
using TValue = typename T::value_type;
static constexpr bool isResizable = Resizable;
static constexpr bool isContiguous = Contiguous;
static size_t size(const T& container) {
return container.size();
}
};
//specialization for resizable
template<typename T, bool Contiguous>
struct StdContainer<T, true, Contiguous> {
using TValue = typename T::value_type;
static constexpr bool isResizable = true;
static constexpr bool isContiguous = Contiguous;
static size_t size(const T& container) {
return container.size();
}
static void resize(T& container, size_t size) {
container.resize(size);
}
};
template <typename T, bool Resizable = ContainerTraits<T>::isResizable>
struct StdContainerForBuffer {
using TIterator = typename T::iterator;
};
template <typename T>
struct StdContainerForBuffer<T, true> {
static void increaseBufferSize(T& container) {
//use default implementation behaviour;
//call push_back to use default resize strategy
container.push_back({});
//after allocation resize to take all capacity
container.resize(container.capacity());
}
using TIterator = typename T::iterator;
};
}
}
#endif //BITSERY_TRAITS_HELPER_STD_DEFAULTS_H

View File

@@ -0,0 +1,42 @@
//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.
#ifndef BITSERY_TRAITS_STD_LIST_H
#define BITSERY_TRAITS_STD_LIST_H
#include "helper/std_defaults.h"
#include <list>
namespace bitsery {
namespace details {
template<typename ... TArgs>
struct ContainerTraits<std::list<TArgs...>>
: public StdContainer<std::list<TArgs...>, true, false> {};
}
}
#endif //BITSERY_TRAITS_STD_LIST_H

View File

@@ -0,0 +1,71 @@
//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.
#ifndef BITSERY_TRAITS_STD_STRING_H
#define BITSERY_TRAITS_STD_STRING_H
#include "helper/std_defaults.h"
#include <string>
namespace bitsery {
namespace details {
// specialization for string, because string is already included for std::char_traits
template<typename ... TArgs>
struct ContainerTraits<std::basic_string<TArgs...>>
:public StdContainer<std::basic_string<TArgs...>, true, true> {};
template <typename ... TArgs>
struct TextTraits<std::basic_string<TArgs...>> {
//string is automatically null-terminated
static constexpr bool addNUL = false;
//is is not 100% accurate, but for performance reasons assume that string stores text, not binary data
static size_t length(const std::basic_string<TArgs...>& str) {
return str.size();
}
};
//specialization for c-array
template <typename T, size_t N>
struct TextTraits<T[N]> {
static constexpr bool addNUL = true;
static size_t length(const T (&container)[N]) {
return std::char_traits<T>::length(container);
}
};
template<typename ... TArgs>
struct BufferContainerTraits<std::basic_string<TArgs...>>
:public StdContainerForBuffer<std::basic_string<TArgs...>> {};
}
}
#endif //BITSERY_TRAITS_VECTOR_H

View File

@@ -21,8 +21,8 @@
//SOFTWARE.
#ifndef BITSERY_TRAITS_VECTOR_H
#define BITSERY_TRAITS_VECTOR_H
#ifndef BITSERY_TRAITS_STD_VECTOR_H
#define BITSERY_TRAITS_STD_VECTOR_H
#include "helper/std_defaults.h"
#include <vector>
@@ -47,4 +47,4 @@ namespace bitsery {
}
#endif //BITSERY_TRAITS_VECTOR_H
#endif //BITSERY_TRAITS_STD_VECTOR_H

View File

@@ -44,7 +44,7 @@ file(GLOB TestSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
message(WARNING "extension tests for optional is disable for VS, because VS currenty doesn't have <optional>")
list(REMOVE_ITEM TestSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/serialization_ext_optional.cpp)
list(REMOVE_ITEM TestSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/serialization_ext_std_optional.cpp)
endif()
include(${ExtCMakeFilesDir}/LinkTestLib.cmake)

View File

@@ -161,18 +161,20 @@ TEST(BufferEndianness, WhenBufferValueTypeIs1ByteThenBitOperationsIsNotAffectedB
//create and write to buffer
Buffer buf{};
bitsery::BasicBufferWriter<DefaultConfig> bw{buf};
bw.writeBits(src.a, aBITS);
bw.writeBits(src.b, bBITS);
bw.writeBits(src.c, cBITS);
bw.writeBits(src.d, dBITS);
bw.flush();
bitsery::BitPackingWriter<DefaultConfig> bpw{bw};
bpw.writeBits(src.a, aBITS);
bpw.writeBits(src.b, bBITS);
bpw.writeBits(src.c, cBITS);
bpw.writeBits(src.d, dBITS);
bpw.flush();
//read from buffer using inverse endianness config
bitsery::BasicBufferReader<InverseEndiannessConfig> br{bw.getWrittenRange()};
bitsery::BasicBufferReader<InverseEndiannessConfig> br{bpw.getWrittenRange()};
bitsery::BitPackingReader<InverseEndiannessConfig> bpr{br};
IntegralUnsignedTypes res{};
br.readBits(res.a, aBITS);
br.readBits(res.b, bBITS);
br.readBits(res.c, cBITS);
br.readBits(res.d, dBITS);
bpr.readBits(res.a, aBITS);
bpr.readBits(res.b, bBITS);
bpr.readBits(res.c, cBITS);
bpr.readBits(res.d, dBITS);
//check results
EXPECT_THAT(res.a, Eq(src.a));
EXPECT_THAT(res.b, Eq(src.b));

View File

@@ -30,6 +30,9 @@ using testing::Eq;
using testing::ContainerEq;
using bitsery::BufferWriter;
using bitsery::BufferReader;
using BitPackingWriter = bitsery::BitPackingWriter<bitsery::DefaultConfig>;
using BitPackingReader = bitsery::BitPackingReader<bitsery::DefaultConfig>;
using Buffer = bitsery::DefaultConfig::BufferType;
struct IntegralUnsignedTypes {
@@ -50,21 +53,23 @@ constexpr size_t getBits(T v) {
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();
BitPackingWriter bpw{bw};
bpw.writeBits(std::numeric_limits<uint64_t>::max(), 64);
bpw.writeBits(std::numeric_limits<uint32_t>::max(), 32);
bpw.writeBits(std::numeric_limits<uint16_t>::max(), 16);
bpw.writeBits(std::numeric_limits<uint8_t>::max(), 8);
bpw.flush();
BufferReader br{bw.getWrittenRange()};
BufferReader br{bpw.getWrittenRange()};
BitPackingReader bpr{br};
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);
bpr.readBits(v64, 64);
bpr.readBits(v32, 32);
bpr.readBits(v16, 16);
bpr.readBits(v8, 8);
EXPECT_THAT(v64, Eq(std::numeric_limits<uint64_t>::max()));
EXPECT_THAT(v32, Eq(std::numeric_limits<uint32_t>::max()));
@@ -91,25 +96,28 @@ TEST(BufferBitsAndBytesOperations, WriteAndReadBits) {
//create and write to buffer
Buffer buf;
BufferWriter bw{buf};
BitPackingWriter bpw{bw};
bw.writeBits(data.a, aBITS);
bw.writeBits(data.b, bBITS);
bw.writeBits(data.c, cBITS);
bw.writeBits(data.d, dBITS);
bw.writeBits(data.e, eBITS);
bw.flush();
auto range = bw.getWrittenRange();
bpw.writeBits(data.a, aBITS);
bpw.writeBits(data.b, bBITS);
bpw.writeBits(data.c, cBITS);
bpw.writeBits(data.d, dBITS);
bpw.writeBits(data.e, eBITS);
bpw.flush();
auto range = bpw.getWrittenRange();
auto bytesCount = ((aBITS + bBITS + cBITS + dBITS + eBITS) / 8) +1 ;
EXPECT_THAT(std::distance(range.begin(), range.end()), Eq(bytesCount));
//read from buffer
BufferReader br{range};
IntegralUnsignedTypes res;
BitPackingReader bpr{br};
br.readBits(res.a, aBITS);
br.readBits(res.b, bBITS);
br.readBits(res.c, cBITS);
br.readBits(res.d, dBITS);
br.readBits(res.e, eBITS);
IntegralUnsignedTypes res{};
bpr.readBits(res.a, aBITS);
bpr.readBits(res.b, bBITS);
bpr.readBits(res.c, cBITS);
bpr.readBits(res.d, dBITS);
bpr.readBits(res.e, eBITS);
EXPECT_THAT(res.a, Eq(data.a));
EXPECT_THAT(res.b, Eq(data.b));
@@ -125,66 +133,72 @@ TEST(BufferBitsAndBytesOperations, BufferSizeIsCountedPerByteNotPerBit) {
//create and write to buffer
Buffer buf;
BufferWriter bw{buf};
BitPackingWriter bpw{bw};
bw.writeBits(7u,3);
bw.flush();
auto range = bw.getWrittenRange();
bpw.writeBits(7u,3);
bpw.flush();
auto range = bpw.getWrittenRange();
EXPECT_THAT(std::distance(range.begin(), range.end()), Eq(1));
//read from buffer
BufferReader br{range};
BitPackingReader bpr{br};
uint16_t tmp;
br.readBits(tmp,4);
br.readBits(tmp,2);
br.readBits(tmp,2);
EXPECT_THAT(br.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
br.readBits(tmp,2);
EXPECT_THAT(br.getError(), Eq(bitsery::BufferReaderError::BUFFER_OVERFLOW));//false
bpr.readBits(tmp,4);
bpr.readBits(tmp,2);
bpr.readBits(tmp,2);
EXPECT_THAT(bpr.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
bpr.readBits(tmp,2);
EXPECT_THAT(bpr.getError(), Eq(bitsery::BufferReaderError::BUFFER_OVERFLOW));//false
//part of next byte
BufferReader br1{range};
br1.readBits(tmp,2);
EXPECT_THAT(br1.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
br1.readBits(tmp,7);
EXPECT_THAT(br1.getError(), Eq(bitsery::BufferReaderError::BUFFER_OVERFLOW));//false
BitPackingReader bpr1{br1};
bpr1.readBits(tmp,2);
EXPECT_THAT(bpr1.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
bpr1.readBits(tmp,7);
EXPECT_THAT(bpr1.getError(), Eq(bitsery::BufferReaderError::BUFFER_OVERFLOW));//false
//bigger than byte
BufferReader br2{range};
br2.readBits(tmp,9);
EXPECT_THAT(br2.getError(), Eq(bitsery::BufferReaderError::BUFFER_OVERFLOW));//false
BitPackingReader bpr2{br2};
bpr2.readBits(tmp,9);
EXPECT_THAT(bpr2.getError(), Eq(bitsery::BufferReaderError::BUFFER_OVERFLOW));//false
}
TEST(BufferBitsAndBytesOperations, ConsecutiveCallsToAlignHasNoEffect) {
Buffer buf;
BufferWriter bw{buf};
BitPackingWriter bpw{bw};
bw.writeBits(3u, 2);
bpw.writeBits(3u, 2);
//3 calls to align after 1st data
bw.align();
bw.align();
bw.align();
bw.writeBits(7u, 3);
bpw.align();
bpw.align();
bpw.align();
bpw.writeBits(7u, 3);
//1 call to align after 2nd data
bw.align();
bw.writeBits(15u, 4);
bw.flush();
bpw.align();
bpw.writeBits(15u, 4);
bpw.flush();
unsigned char tmp;
BufferReader br{bw.getWrittenRange()};
br.readBits(tmp,2);
BufferReader br{bpw.getWrittenRange()};
BitPackingReader bpr{br};
bpr.readBits(tmp,2);
EXPECT_THAT(tmp, Eq(3u));
br.align();
EXPECT_THAT(br.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
br.readBits(tmp,3);
br.align();
br.align();
br.align();
bpr.align();
EXPECT_THAT(bpr.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
bpr.readBits(tmp,3);
bpr.align();
bpr.align();
bpr.align();
EXPECT_THAT(tmp, Eq(7u));
EXPECT_THAT(br.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
EXPECT_THAT(bpr.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
br.readBits(tmp,4);
bpr.readBits(tmp,4);
EXPECT_THAT(tmp, Eq(15u));
EXPECT_THAT(br.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
EXPECT_THAT(bpr.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
}
TEST(BufferBitsAndBytesOperations, AlignWritesZerosBits) {
@@ -193,25 +207,28 @@ TEST(BufferBitsAndBytesOperations, AlignWritesZerosBits) {
//create and write to buffer
Buffer buf;
BufferWriter bw{buf};
BitPackingWriter bpw{bw};
//write 2 bits and align
bw.writeBits(3u, 2);
bw.align();
bw.flush();
auto range = bw.getWrittenRange();
bpw.writeBits(3u, 2);
bpw.align();
bpw.flush();
auto range = bpw.getWrittenRange();
EXPECT_THAT(std::distance(range.begin(), range.end()), Eq(1));
unsigned char tmp;
BufferReader br1{range};
br1.readBits(tmp,2);
BitPackingReader bpr1{br1};
bpr1.readBits(tmp,2);
//read aligned bits
br1.readBits(tmp,6);
bpr1.readBits(tmp,6);
EXPECT_THAT(tmp, Eq(0));
BufferReader br2{range};
BitPackingReader bpr2{br2};
//read 2 bits
br2.readBits(tmp,2);
br2.align();
EXPECT_THAT(br2.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
bpr2.readBits(tmp,2);
bpr2.align();
EXPECT_THAT(bpr2.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
}
@@ -295,23 +312,25 @@ TEST(BufferBitsAndBytesOperations, ReadWriteBufferCanWorkOnUnalignedData) {
//create and write to buffer
Buffer buf{};
BufferWriter bw{buf};
bw.writeBits(15u, 4);
bw.writeBuffer<2>(src, DATA_SIZE);
bw.writeBits(12u, 4);
bw.flush();
auto range = bw.getWrittenRange();
BitPackingWriter bpw{bw};
bpw.writeBits(15u, 4);
bpw.writeBuffer<2>(src, DATA_SIZE);
bpw.writeBits(12u, 4);
bpw.flush();
auto range = bpw.getWrittenRange();
EXPECT_THAT(std::distance(range.begin(), range.end()), Eq(sizeof(src) + 1));
//read from buffer
BufferReader br1{range};
BitPackingReader bpr1{br1};
int16_t dst[DATA_SIZE]{};
uint8_t tmp{};
br1.readBits(tmp, 4);
bpr1.readBits(tmp, 4);
EXPECT_THAT(tmp, Eq(15));
br1.readBuffer<2>(dst, DATA_SIZE);
EXPECT_THAT(br1.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
bpr1.readBuffer<2>(dst, DATA_SIZE);
EXPECT_THAT(bpr1.getError(), Eq(bitsery::BufferReaderError::NO_ERROR));
EXPECT_THAT(dst, ContainerEq(src));
br1.readBits(tmp, 4);
bpr1.readBits(tmp, 4);
EXPECT_THAT(tmp, Eq(12));
}
@@ -322,21 +341,23 @@ TEST(BufferBitsAndBytesOperations, RegressionTestReadBytesAfterReadBitsWithLotsO
//create and write to buffer
Buffer buf{};
BufferWriter bw{buf};
bw.writeBits(2u, 2);
bw.writeBytes<2>(data[0]);
bw.writeBytes<2>(data[1]);
bw.align();
bw.flush();
auto range = bw.getWrittenRange();
BitPackingWriter bpw{bw};
bpw.writeBits(2u, 2);
bpw.writeBytes<2>(data[0]);
bpw.writeBytes<2>(data[1]);
bpw.align();
bpw.flush();
auto range = bpw.getWrittenRange();
//read from buffer
BufferReader br{range};
BitPackingReader bpr{br};
uint8_t tmp{};
br.readBits(tmp, 2);
bpr.readBits(tmp, 2);
EXPECT_THAT(tmp, Eq(2));
br.readBytes<2>(res[0]);
br.readBytes<2>(res[1]);
br.align();
bpr.readBytes<2>(res[0]);
bpr.readBytes<2>(res[1]);
bpr.align();
EXPECT_THAT(res[0], Eq(data[0]));
EXPECT_THAT(res[1], Eq(data[1]));
}

View File

@@ -140,17 +140,18 @@ TEST(BufferReading, WhenReaderHasErrorsAllOperationsReadsReturnZero) {
bw.flush();
//read from buffer
BufferReader br{bw.getWrittenRange()};
bitsery::BitPackingReader<bitsery::DefaultConfig> bpr{br};
int32_t c;
br.readBytes<4>(c);
bpr.readBytes<4>(c);
EXPECT_THAT(br.getError(), Eq(bitsery::BufferReaderError::BUFFER_OVERFLOW));
int16_t r1= {-645};
uint32_t r2[2] = {54898,87854};
uint8_t r3 = 0xFF;
br.readBytes<2>(r1);
br.readBuffer<4>(r2, 2);
br.readBits(r3, 7);
bpr.readBytes<2>(r1);
bpr.readBuffer<4>(r2, 2);
bpr.readBits(r3, 7);
EXPECT_THAT(r1, Eq(0));
EXPECT_THAT(r2[0], Eq(0u));
EXPECT_THAT(r2[1], Eq(0u));

View File

@@ -44,9 +44,9 @@ TEST(BufferReadingErrors, WhenReadingBoolByteReadsMoreThanOneThenInvalidBufferDa
ser.value1b(uint8_t{2});
bool res{};
auto des = ctx.createDeserializer();
des.boolByte(res);
des.boolValue(res);
EXPECT_THAT(res, Eq(true));
des.boolByte(res);
des.boolValue(res);
EXPECT_THAT(res, Eq(false));
EXPECT_THAT(ctx.br->getError(), Eq(bitsery::BufferReaderError::INVALID_BUFFER_DATA));
}
@@ -57,11 +57,13 @@ TEST(BufferReadingErrors, WhenReadingAlignHasNonZerosThenInvalidBufferDataError)
uint8_t tmp{0xFF};
bw.writeBytes<1>(tmp);
bw.flush();
BufferReader br{bw.getWrittenRange()};
br.readBits(tmp,3);
br.align();
EXPECT_THAT(br.getError(), Eq(bitsery::BufferReaderError::INVALID_BUFFER_DATA));
BufferReader br{bw.getWrittenRange()};
bitsery::BitPackingReader<bitsery::DefaultConfig> bpr{br};
bpr.readBits(tmp,3);
bpr.align();
EXPECT_THAT(bpr.getError(), Eq(bitsery::BufferReaderError::INVALID_BUFFER_DATA));
}
TEST(BufferReadingErrors, WhenReadingNewSessionInMiddleOfOldDataThenInvalidBufferError) {

View File

@@ -83,10 +83,11 @@ TYPED_TEST(BufferWriting, WhenWritingBitsThenMustFlushWriter) {
using Buffer = typename Config::BufferType;
Buffer buf{};
bitsery::BasicBufferWriter<Config> bw{buf};
bw.writeBits(3u, 2);
auto range1 = bw.getWrittenRange();
bw.flush();
auto range2 = bw.getWrittenRange();
bitsery::BitPackingWriter<Config> bpw{bw};
bpw.writeBits(3u, 2);
auto range1 = bpw.getWrittenRange();
bpw.flush();
auto range2 = bpw.getWrittenRange();
EXPECT_THAT(std::distance(range1.begin(), range1.end()), Eq(0));
EXPECT_THAT(std::distance(range2.begin(), range2.end()), Eq(1));
}
@@ -96,12 +97,12 @@ TYPED_TEST(BufferWriting, WhenDataAlignedThenFlushHasNoEffect) {
using Buffer = typename Config::BufferType;
Buffer buf{};
bitsery::BasicBufferWriter<Config> bw{buf};
bw.writeBits(3u, 2);
bw.align();
auto range1 = bw.getWrittenRange();
bw.flush();
auto range2 = bw.getWrittenRange();
bitsery::BitPackingWriter<Config> bpw{bw};
bpw.writeBits(3u, 2);
bpw.align();
auto range1 = bpw.getWrittenRange();
bpw.flush();
auto range2 = bpw.getWrittenRange();
EXPECT_THAT(std::distance(range1.begin(), range1.end()), Eq(1));
EXPECT_THAT(std::distance(range2.begin(), range2.end()), Eq(1));
}

351
tests/flexible_syntax.cpp Normal file
View File

@@ -0,0 +1,351 @@
//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/flexible.h>
#include <bitsery/flexible/string.h>
#include <bitsery/flexible/array.h>
#include <bitsery/flexible/vector.h>
#include <bitsery/flexible/list.h>
#include <bitsery/flexible/forward_list.h>
#include <bitsery/flexible/deque.h>
#include <bitsery/flexible/queue.h>
#include <bitsery/flexible/stack.h>
#include <bitsery/flexible/map.h>
#include <bitsery/flexible/unordered_map.h>
#include <bitsery/flexible/set.h>
#include <bitsery/flexible/unordered_set.h>
using testing::Eq;
TEST(FlexibleSyntax, FundamentalTypesAndBool) {
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double_t td = -454184.48445;
bool tb=true;
SerializationContext ctx;
ctx.createSerializer().archive(ti,te,tf,td,tb);
//result
int ri{};
MyEnumClass re{};
float rf{};
double_t rd{};
bool rb{};
ctx.createDeserializer().archive(ri,re,rf,rd,rb);
//test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
}
TEST(FlexibleSyntax, UseObjectFncInsteadOfValueN) {
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double_t td = -454184.48445;
bool tb=true;
SerializationContext ctx;
auto ser = ctx.createSerializer();
ser.object(ti);
ser.object(te);
ser.object(tf);
ser.object(td);
ser.object(tb);
//result
int ri{};
MyEnumClass re{};
float rf{};
double_t rd{};
bool rb{};
auto des = ctx.createDeserializer();
des.object(ri);
des.object(re);
des.object(rf);
des.object(rd);
des.object(rb);
//test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
}
TEST(FlexibleSyntax, MixDifferentSyntax) {
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double_t td = -454184.48445;
bool tb=true;
SerializationContext ctx;
auto ser = ctx.createSerializer();
ser.value<sizeof(ti)>(ti);
ser.archive(te, tf, td);
ser.object(tb);
//result
int ri{};
MyEnumClass re{};
float rf{};
double_t rd{};
bool rb{};
auto des = ctx.createDeserializer();
des.archive(ri, re, rf);
des.value8b(rd);
des.object(rb);
//test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
}
template <typename T>
T procArchive(const T& testData) {
SerializationContext ctx;
ctx.createSerializer().archive(testData);
T res;
ctx.createDeserializer().archive(res);
return res;
}
TEST(FlexibleSyntax, CStyleArrayForValueTypesAsContainer) {
const int t1[3]{8748,-484,45};
int r1[3]{0,0,0};
SerializationContext ctx;
ctx.createSerializer().archive(bitsery::asContainer(t1));
ctx.createDeserializer().archive(bitsery::asContainer(r1));
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
}
TEST(FlexibleSyntax, CStyleArrayForIntegralTypesAsText) {
const char t1[3]{"hi"};
char r1[3]{0,0,0};
SerializationContext ctx;
ctx.createSerializer().archive(bitsery::asText(t1));
ctx.createDeserializer().archive(bitsery::asText(r1));
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
}
TEST(FlexibleSyntax, CStyleArray) {
const MyEnumClass t1[3]{MyEnumClass::E1, MyEnumClass::E4, MyEnumClass::E2};
MyEnumClass r1[3]{};
SerializationContext ctx;
ctx.createSerializer().archive(t1);
ctx.createDeserializer().archive(r1);
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
}
TEST(FlexibleSyntax, StdString) {
std::string t1{"my nice string"};
std::string t2{};
EXPECT_THAT(procArchive(t1), Eq(t1));
EXPECT_THAT(procArchive(t2), Eq(t2));
}
TEST(FlexibleSyntax, StdArray) {
std::array<int, 3> t1{8748,-484,45};
std::array<int, 0> t2{};
EXPECT_THAT(procArchive(t1), Eq(t1));
EXPECT_THAT(procArchive(t2), Eq(t2));
}
TEST(FlexibleSyntax, StdVector) {
std::vector<int> t1{8748,-484,45};
std::vector<float> t2{5.f,0.198f};
EXPECT_THAT(procArchive(t1), Eq(t1));
EXPECT_THAT(procArchive(t2), Eq(t2));
}
TEST(FlexibleSyntax, StdList) {
std::list<int> t1{8748,-484,45};
std::list<float> t2{5.f,0.198f};
EXPECT_THAT(procArchive(t1), Eq(t1));
EXPECT_THAT(procArchive(t2), Eq(t2));
}
TEST(FlexibleSyntax, StdForwardList) {
std::forward_list<int> t1{8748,-484,45};
std::forward_list<float> t2{5.f,0.198f};
EXPECT_THAT(procArchive(t1), Eq(t1));
EXPECT_THAT(procArchive(t2), Eq(t2));
}
TEST(FlexibleSyntax, StdDeque) {
std::deque<int> t1{8748,-484,45};
std::deque<float> t2{5.f,0.198f};
EXPECT_THAT(procArchive(t1), Eq(t1));
EXPECT_THAT(procArchive(t2), Eq(t2));
}
TEST(FlexibleSyntax, StdQueue) {
std::queue<std::string> t1;
t1.push("first");
t1.push("second string");
EXPECT_THAT(procArchive(t1), Eq(t1));
}
TEST(FlexibleSyntax, StdPriorityQueue) {
std::priority_queue<std::string> t1;
t1.push("first");
t1.push("second string");
t1.push("third");
t1.push("fourth");
auto r1 = procArchive(t1);
//we cannot compare priority queue directly
EXPECT_THAT(r1.size(), Eq(t1.size()));
for (auto i = 0u; i < r1.size(); ++i) {
EXPECT_THAT(r1.top(), Eq(t1.top()));
r1.pop();
t1.pop();
}
}
TEST(FlexibleSyntax, StdStack) {
std::stack<std::string> t1;
t1.push("first");
t1.push("second string");
EXPECT_THAT(procArchive(t1), Eq(t1));
}
TEST(FlexibleSyntax, StdUnorderedMap) {
std::unordered_map<int, int> t1;
t1.emplace(3423,624);
t1.emplace(-5484,-845);
EXPECT_THAT(procArchive(t1), Eq(t1));
}
TEST(FlexibleSyntax, StdUnorderedMultiMap) {
std::unordered_multimap<std::string, int> t1;
t1.emplace("one",624);
t1.emplace("two",-845);
t1.emplace("one",897);
EXPECT_TRUE(procArchive(t1) == t1);
}
TEST(FlexibleSyntax, StdMap) {
std::map<int, int> t1;
t1.emplace(3423,624);
t1.emplace(-5484,-845);
EXPECT_THAT(procArchive(t1), Eq(t1));
}
TEST(FlexibleSyntax, StdMultiMap) {
std::multimap<std::string, int> t1;
t1.emplace("one",624);
t1.emplace("two",-845);
t1.emplace("one",897);
auto res = procArchive(t1);
//same key values is not ordered, and operator == compares each element at same position
//so we need to compare our selves
EXPECT_THAT(res.size(), Eq(3));
for (auto it = t1.begin(); it != t1.end();) {
const auto lr = t1.equal_range(it->first);
const auto rr = res.equal_range(it->first);
EXPECT_TRUE(std::distance(lr.first, lr.second) == std::distance(rr.first, rr.second));
EXPECT_TRUE(std::is_permutation(lr.first, lr.second, rr.first));
it = lr.second;
}
}
TEST(FlexibleSyntax, StdUnorderedSet) {
std::unordered_set<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
EXPECT_TRUE(procArchive(t1) == t1);
}
TEST(FlexibleSyntax, StdUnorderedMultiSet) {
std::unordered_multiset<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
t1.emplace("one");
EXPECT_TRUE(procArchive(t1) == t1);
}
TEST(FlexibleSyntax, StdSet) {
std::set<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
EXPECT_TRUE(procArchive(t1) == t1);
}
TEST(FlexibleSyntax, StdMultiSet) {
std::multiset<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
t1.emplace("one");
t1.emplace("two");
EXPECT_TRUE(procArchive(t1) == t1);
}
TEST(FlexibleSyntax, NestedTypes) {
std::unordered_map<std::string, std::vector<std::string>> t1;
t1.emplace("my key", std::vector<std::string>{"very", "nice", "string"});
t1.emplace("other key", std::vector<std::string>{"just a string"});
EXPECT_THAT(procArchive(t1), Eq(t1));
}

View File

@@ -26,19 +26,30 @@
using testing::Eq;
template <bool BitPackingEnabled>
using Serializer = bitsery::BasicSerializer<bitsery::DefaultConfig, BitPackingEnabled>;
template <bool BitPackingEnabled>
using Deserializer = bitsery::BasicDeserializer<bitsery::DefaultConfig, BitPackingEnabled>;
TEST(SerializeBooleans, BoolAsBit) {
SerializationContext ctx;
bool t1{true};
bool t2{false};
bool res1;
bool res2;
auto ser = ctx.createSerializer();
ser.boolBit(t1);
ser.boolBit(t2);
ser.enableBitPacking([&t1, &t2](Serializer<true>& sbp) {
sbp.boolValue(t1);
sbp.boolValue(t2);
});
auto des = ctx.createDeserializer();
des.boolBit(res1);
des.boolBit(res2);
des.enableBitPacking([&res1, &res2](Deserializer <true>& sbp) {
sbp.boolValue(res1);
sbp.boolValue(res2);
});
EXPECT_THAT(res1, Eq(t1));
EXPECT_THAT(res2, Eq(t2));
@@ -52,11 +63,11 @@ TEST(SerializeBooleans, BoolAsByte) {
bool res1;
bool res2;
auto ser = ctx.createSerializer();
ser.boolByte(t1);
ser.boolByte(t2);
ser.boolValue(t1);
ser.boolValue(t2);
auto des = ctx.createDeserializer();
des.boolByte(res1);
des.boolByte(res2);
des.boolValue(res1);
des.boolValue(res2);
EXPECT_THAT(res1, Eq(t1));
EXPECT_THAT(res2, Eq(t2));

View File

@@ -25,13 +25,12 @@
#include <gmock/gmock.h>
#include <algorithm>
#include <numeric>
// #include <deque>
#include "serialization_test_utils.h"
#include <bitsery/traits/array.h>
#include <bitsery/traits/list.h>
#include <bitsery/traits/deque.h>
#include <bitsery/traits/forward_list.h>
using testing::ContainerEq;
using testing::Eq;
@@ -81,13 +80,15 @@ public:
TContainer res{};
size_t getExpectedBufSize(const SerializationContext &ctx) const {
return ctx.containerSizeSerializedBytesCount(src.size()) + src.size() * sizeof(TValue);
auto size = bitsery::details::ContainerTraits<TContainer>::size(src);
return ctx.containerSizeSerializedBytesCount(size) + size * sizeof(TValue);
}
};
//std::forward_list is not supported, because it doesn't have size() method
using SequenceContainersWithArthmeticTypes = ::testing::Types<
std::vector<int>,
std::list<float>,
std::forward_list<int>,
std::deque<unsigned short>>;
TYPED_TEST_CASE(SerializeContainerDynamicSizeArthmeticTypes, SequenceContainersWithArthmeticTypes);

View File

@@ -36,15 +36,15 @@ TEST(SerializeExtensionEntropy, WhenEntropyEncodedThenOnlyWriteIndexUsingMinRequ
constexpr size_t N = 3;
int32_t values[3] = {485,4849,89};
SerializationContext ctx;
ctx.createSerializer().ext4b(v, Entropy<int32_t[3]>{values});
ctx.createDeserializer().ext4b(res, Entropy<int32_t[3]>{values});
ctx.createBPEnabledSerializer().ext4b(v, Entropy<int32_t[3]>{values});
ctx.createBPEnabledDeserializer().ext4b(res, Entropy<int32_t[3]>{values});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
SerializationContext ctx1;
ctx1.createSerializer().ext4b(v, Entropy<int32_t[3]>{values});
auto des = ctx1.createDeserializer();
ctx1.createBPEnabledSerializer().ext4b(v, Entropy<int32_t[3]>{values});
auto des = ctx1.createBPEnabledDeserializer();
des.ext(res, bitsery::ext::ValueRange<int32_t>{0, static_cast<int32_t>(N + 1)});
EXPECT_THAT(res, Eq(2));
}
@@ -54,8 +54,8 @@ TEST(SerializeExtensionEntropy, WhenNoEntropyEncodedThenWriteZeroBitsAndValueOrO
int16_t res;
std::initializer_list<int> values{485,4849,89};
SerializationContext ctx;
ctx.createSerializer().ext2b(v, Entropy<std::initializer_list<int>>{values});
ctx.createDeserializer().ext2b(res, Entropy<std::initializer_list<int>>{values});
ctx.createBPEnabledSerializer().ext2b(v, Entropy<std::initializer_list<int>>{values});
ctx.createBPEnabledDeserializer().ext2b(res, Entropy<std::initializer_list<int>>{values});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(sizeof(int16_t)+1));
@@ -70,8 +70,8 @@ TEST(SerializeExtensionEntropy, CustomTypeEntropyEncoded) {
MyStruct1{12, 10}, MyStruct1{485, 454},
MyStruct1{4849, 89}, MyStruct1{0, 1}};
SerializationContext ctx;
ctx.createSerializer().ext(v, Entropy<MyStruct1[N]>{values});
ctx.createDeserializer().ext(res, Entropy<MyStruct1[N]>{values});
ctx.createBPEnabledSerializer().ext(v, Entropy<MyStruct1[N]>{values});
ctx.createBPEnabledDeserializer().ext(res, Entropy<MyStruct1[N]>{values});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
@@ -86,14 +86,14 @@ TEST(SerializeExtensionEntropy, CustomTypeNotEntropyEncoded) {
MyStruct1{4849,89}, MyStruct1{0,1}};
SerializationContext ctx;
ctx.createSerializer().ext(v, Entropy<std::initializer_list<MyStruct1>>{values});
ctx.createDeserializer().ext(res, Entropy<std::initializer_list<MyStruct1>>{values});
ctx.createBPEnabledSerializer().ext(v, Entropy<std::initializer_list<MyStruct1>>{values});
ctx.createBPEnabledDeserializer().ext(res, Entropy<std::initializer_list<MyStruct1>>{values});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(MyStruct1::SIZE + 1));
}
TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncoded) {
TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncodedWithNoAlignBeforeData) {
MyStruct1 v = {8945,4456};
MyStruct1 res;
constexpr size_t N = 4;
@@ -103,29 +103,61 @@ TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncoded) {
MyStruct1{4849,89}, MyStruct1{0,1}};
auto rangeForValue = bitsery::ext::ValueRange<int>{0, 10000};
auto rangeForIndex = bitsery::ext::ValueRange<size_t>{0u, N+1};
SerializationContext ctx;
auto ser = ctx.createSerializer();
auto& ser = ctx.createBPEnabledSerializer();
//lambdas differ only in capture clauses, it would make sense to use std::bind, but debugger crashes when it sees std::bind...
auto serLambda = [&ser, &rangeForValue](MyStruct1& v) {
ser.ext(v.i1, rangeForValue);
ser.ext(v.i2, rangeForValue);
auto serLambda = [&ser, &rangeForValue](MyStruct1& data) {
ser.ext(data.i1, rangeForValue);
ser.ext(data.i2, rangeForValue);
};
ser.ext(v, Entropy<std::vector<MyStruct1>>(values), serLambda);
ser.ext(v, Entropy<std::vector<MyStruct1>>(values, false), serLambda);
auto des = ctx.createDeserializer();
auto desLambda = [&des, &rangeForValue](MyStruct1& v) {
des.ext(v.i1, rangeForValue);
des.ext(v.i2, rangeForValue);
auto des = ctx.createBPEnabledDeserializer();
auto desLambda = [&des, &rangeForValue](MyStruct1& data) {
des.ext(data.i1, rangeForValue);
des.ext(data.i2, rangeForValue);
};
des.ext(res, Entropy<std::vector<MyStruct1>>(values), desLambda);
des.ext(res, Entropy<std::vector<MyStruct1>>(values, false), desLambda);
EXPECT_THAT(res, Eq(v));
auto rangeForIndex = bitsery::ext::ValueRange<size_t>{0u, N+1};
EXPECT_THAT(ctx.getBufferSize(), Eq((rangeForIndex.getRequiredBits() + rangeForValue.getRequiredBits() * 2 - 1) / 8 + 1 ));
}
TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncodedWithAlignBeforeData) {
MyStruct1 v = {8945,4456};
MyStruct1 res;
std::vector<MyStruct1> values{
MyStruct1{12,10}, MyStruct1{485, 454},
MyStruct1{4849,89}, MyStruct1{0,1}};
auto rangeForValue = bitsery::ext::ValueRange<int>{0, 10000};
SerializationContext ctx;
auto& ser = ctx.createBPEnabledSerializer();
//lambdas differ only in capture clauses, it would make sense to use std::bind, but debugger crashes when it sees std::bind...
auto serLambda = [&ser, &rangeForValue](MyStruct1& data) {
ser.ext(data.i1, rangeForValue);
ser.ext(data.i2, rangeForValue);
};
ser.ext(v, Entropy<std::vector<MyStruct1>>(values, true), serLambda);
auto des = ctx.createBPEnabledDeserializer();
auto desLambda = [&des, &rangeForValue](MyStruct1& data) {
des.ext(data.i1, rangeForValue);
des.ext(data.i2, rangeForValue);
};
des.ext(res, Entropy<std::vector<MyStruct1>>(values, true), desLambda);
EXPECT_THAT(res, Eq(v));
auto bitsForIndex = 8; //because aligned
EXPECT_THAT(ctx.getBufferSize(), Eq((bitsForIndex + rangeForValue.getRequiredBits() * 2 - 1) / 8 + 1 ));
}
TEST(SerializeExtensionEntropy, WhenEntropyEncodedThenCustomFunctionNotInvoked) {
MyStruct1 v = {4849,89};
MyStruct1 res;
@@ -134,8 +166,8 @@ TEST(SerializeExtensionEntropy, WhenEntropyEncodedThenCustomFunctionNotInvoked)
MyStruct1{4849,89}, MyStruct1{0,1}};
SerializationContext ctx;
ctx.createSerializer().ext(v, Entropy<std::list<MyStruct1>>{values}, [](MyStruct1& ) {});
ctx.createDeserializer().ext(res, Entropy<std::list<MyStruct1>>{values}, []( MyStruct1& ) {});
ctx.createBPEnabledSerializer().ext(v, Entropy<std::list<MyStruct1>>{values}, [](MyStruct1& ) {});
ctx.createBPEnabledDeserializer().ext(res, Entropy<std::list<MyStruct1>>{values}, []( MyStruct1& ) {});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));

View File

@@ -23,17 +23,15 @@
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <bitsery/ext/container_map.h>
#include <bitsery/ext/std_map.h>
#include <bitsery/ext/entropy.h>
#include <unordered_map>
#include <bitsery/traits/string.h>
using ContainerMap = bitsery::ext::ContainerMap;
using StdMap = bitsery::ext::StdMap;
using testing::Eq;
template<typename Container>
Container createData() {
return {};
@@ -49,7 +47,7 @@ std::unordered_map<std::string, MyStruct1> createData<std::unordered_map<std::st
}
template<>
std::unordered_map<int32_t, float> createData<std::unordered_map<int32_t, float>>() {
std::unordered_multimap<int32_t, float> createData<std::unordered_multimap<int32_t, float>>() {
return {
std::pair<int32_t , float>(545, 45.485f),
std::pair<int32_t , float>(6748, -7891.5f),
@@ -67,7 +65,7 @@ std::map<MyEnumClass, MyStruct1> createData<std::map<MyEnumClass, MyStruct1>>()
}
template<>
std::map<int32_t ,int64_t> createData<std::map<int32_t ,int64_t>>() {
std::multimap<int32_t ,int64_t> createData<std::multimap<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),
@@ -76,7 +74,7 @@ std::map<int32_t ,int64_t> createData<std::map<int32_t ,int64_t>>() {
}
template<typename T>
class SerializeExtensionContainerMap : public testing::Test {
class SerializeExtensionStdMap : public testing::Test {
public:
using TContainer = T;
@@ -84,28 +82,28 @@ public:
TContainer res{};
};
using SerializeExtensionContainerMapTypes = ::testing::Types<
using SerializeExtensionStdMapTypes = ::testing::Types<
std::unordered_map<std::string, MyStruct1>,
std::unordered_map<int32_t, float>,
std::unordered_multimap<int32_t, float>,
std::map<MyEnumClass , MyStruct1>,
std::map<int32_t ,int64_t>
std::multimap<int32_t ,int64_t>
>;
TYPED_TEST_CASE(SerializeExtensionContainerMap, SerializeExtensionContainerMapTypes);
TYPED_TEST_CASE(SerializeExtensionStdMap, SerializeExtensionStdMapTypes);
namespace bitsery {
template <typename S>
void serialize(S& s, std::unordered_map<std::string, MyStruct1>& o) {
s.ext(o, ContainerMap{10}, [&s](std::string& key, MyStruct1& value) {
s.ext(o, StdMap{10}, [&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.ext(o, ContainerMap{10}, [&s](int32_t& key, float& value) {
void serialize(S& s, std::unordered_multimap<int32_t, float>& o) {
s.ext(o, StdMap{10}, [&s](int32_t& key, float& value) {
s.value4b(key);
s.value4b(value);
});
@@ -113,26 +111,27 @@ namespace bitsery {
template <typename S>
void serialize(S& s, std::map<MyEnumClass , MyStruct1>& o) {
s.ext(o, ContainerMap{10}, [&s](MyEnumClass& key, MyStruct1& value) {
s.ext(o, StdMap{10}, [&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.ext(o, ContainerMap{10}, [&s](int32_t& key, int64_t& value) {
int64_t values[3]{1ll, 2ll, 3ll};
s.ext(key, bitsery::ext::ValueRange<int32_t>{-100,100});
s.ext8b(value, bitsery::ext::Entropy<int64_t[3]>{values});
void serialize(S& s, std::multimap<int32_t ,int64_t>& o) {
s.ext(o, StdMap{10}, [&s](int32_t& key, int64_t& value) {
s.enableBitPacking([&key, &value](typename S::BPEnabledType& sbp) {
int64_t values[3]{1ll, 2ll, 3ll};
sbp.ext(key, bitsery::ext::ValueRange<int32_t>{-100,100});
sbp.ext8b(value, bitsery::ext::Entropy<int64_t[3]>{values});
});
});
}
}
TYPED_TEST(SerializeExtensionContainerMap, SerializeAndDeserializeEquals) {
TYPED_TEST(SerializeExtensionStdMap, SerializeAndDeserializeEquals) {
SerializationContext ctx1;
ctx1.createSerializer().object(this->src);
ctx1.createDeserializer().object(this->res);

View File

@@ -0,0 +1,123 @@
//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"
#if __cplusplus > 201402L
#include <bitsery/ext/value_range.h>
#include<optional>
#include <bitsery/ext/std_optional.h>
using StdOptional = bitsery::ext::StdOptional;
using testing::Eq;
template <typename T>
void test(SerializationContext& ctx, const T& v, T& r) {
ctx.createSerializer().ext4b(v, StdOptional{});
ctx.createDeserializer().ext4b(r, StdOptional{});
}
TEST(SerializeExtensionStdOptional, EmptyOptional) {
std::optional<int32_t> t1{};
std::optional<int32_t> r1{};
SerializationContext ctx1;
test(ctx1,t1, r1);
EXPECT_THAT(ctx1.getBufferSize(), Eq(1));
EXPECT_THAT(t1, Eq(r1));
r1 = 3;
SerializationContext ctx2;
test(ctx2,t1, r1);
EXPECT_THAT(ctx2.getBufferSize(), Eq(1));
EXPECT_THAT(t1, Eq(r1));
}
TEST(SerializeExtensionStdOptional, OptionalHasValue) {
std::optional<int32_t> t1{43};
std::optional<int32_t> r1{52};
SerializationContext ctx1;
test(ctx1,t1, r1);
EXPECT_THAT(ctx1.getBufferSize(), Eq(1 + sizeof(int)));
EXPECT_THAT(t1.value(), Eq(r1.value()));
r1 = std::optional<int>{};
SerializationContext ctx2;
test(ctx2,t1, r1);
EXPECT_THAT(ctx2.getBufferSize(), Eq(1 + sizeof(int)));
EXPECT_THAT(t1.value(), Eq(r1.value()));
}
TEST(SerializeExtensionStdOptional, AlignAfterStateWriteRead) {
std::optional<int32_t> t1{43};
std::optional<int32_t> r1{52};
SerializationContext ctx;
auto& ser = ctx.createBPEnabledSerializer();
auto range = bitsery::ext::ValueRange<int>{40,60};
ser.ext(t1, StdOptional(true), [&ser, &range](int32_t& v) {
ser.ext(v, range);
});
auto des = ctx.createBPEnabledDeserializer();
des.ext(r1, StdOptional(true), [&des, &range](int32_t& v) {
des.ext(v, range);
});
EXPECT_THAT(ctx.getBufferSize(), Eq(2));//1byte for index + 1byte for value
EXPECT_THAT(t1.value(), Eq(r1.value()));
}
TEST(SerializeExtensionStdOptional, NoAlignAfterStateWriteRead) {
std::optional<int32_t> t1{43};
std::optional<int32_t> r1{52};
SerializationContext ctx;
auto& ser = ctx.createBPEnabledSerializer();
auto range = bitsery::ext::ValueRange<int>{40,60};
ser.ext(t1, StdOptional(false), [&ser, &range](int32_t& v) {
ser.ext(v, range);
});
auto des = ctx.createBPEnabledDeserializer();
des.ext(r1, StdOptional(false), [&des, &range](int32_t& v) {
des.ext(v, range);
});
EXPECT_THAT(range.getRequiredBits() + 1, ::testing::Lt(8));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(t1.value(), Eq(r1.value()));
}
#endif

View File

@@ -0,0 +1,99 @@
//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/std_queue.h>
using StdQueue = bitsery::ext::StdQueue;
using testing::Eq;
//inherit from queue so we could take underlying container, because priority queue doesn't have equal operator defined
template <typename T, typename C>
struct PriorityQueueCnt : public std::priority_queue<T, C>
{
static const C& getContainer(const std::priority_queue<T, C>& s )
{
//get address of underlying container
return s.*(&PriorityQueueCnt::c);
}
static C& getContainer(std::priority_queue<T, C>& s )
{
//get address of underlying container
return s.*(&PriorityQueueCnt::c);
}
};
template <typename T>
void test(SerializationContext& ctx, const T& v, T& r) {
ctx.createSerializer().ext4b(v, StdQueue{10});
ctx.createDeserializer().ext4b(r, StdQueue{10});
}
TEST(SerializeExtensionStdQueue, QueueDefaultContainer) {
std::queue<int32_t> t1{};
t1.push(3);
t1.push(-4854);
std::queue<int32_t> r1{};
SerializationContext ctx1;
test(ctx1,t1, r1);
EXPECT_THAT(t1, Eq(r1));
}
TEST(SerializeExtensionStdQueue, QueueVectorContainer) {
std::queue<int32_t, std::vector<int32_t>> t1{};
t1.push(3);
t1.push(-4854);
std::queue<int32_t, std::vector<int32_t>> r1{};
SerializationContext ctx1;
test(ctx1,t1, r1);
EXPECT_THAT(t1, Eq(r1));
}
TEST(SerializeExtensionStdQueue, PriorityQueueDefaultContainer) {
std::priority_queue<int32_t> t1{};
t1.push(3);
t1.push(-4854);
std::priority_queue<int32_t> r1{};
SerializationContext ctx1;
test(ctx1,t1, r1);
auto & ct1 = PriorityQueueCnt<int32_t, std::vector<int32_t>>::getContainer(t1);
auto & cr1 = PriorityQueueCnt<int32_t, std::vector<int32_t>>::getContainer(r1);
EXPECT_THAT(ct1, Eq(cr1));
}
TEST(SerializeExtensionStdQueue, PriorityQueueDequeContainer) {
std::priority_queue<int32_t, std::deque<int32_t>> t1{};
t1.push(678);
t1.push(-44);
std::priority_queue<int32_t, std::deque<int32_t>> r1{};
SerializationContext ctx1;
test(ctx1,t1, r1);
auto & ct1 = PriorityQueueCnt<int32_t, std::deque<int32_t>>::getContainer(t1);
auto & cr1 = PriorityQueueCnt<int32_t, std::deque<int32_t>>::getContainer(r1);
EXPECT_THAT(ct1, Eq(cr1));
}

View File

@@ -0,0 +1,78 @@
//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/std_set.h>
#include <set>
using StdSet = bitsery::ext::StdSet;
using testing::Eq;
template<typename T>
class SerializeExtensionStdSet : public testing::Test {
public:
using TContainer = T;
const TContainer src = {4, 8, 48, 4, 9845, 64, 8};
TContainer res{};
};
using SerializeExtensionStdSetTypes = ::testing::Types<
std::unordered_set<int32_t>,
std::unordered_multiset<int32_t>,
std::set<int32_t>,
std::multiset<int32_t>>;
TYPED_TEST_CASE(SerializeExtensionStdSet, SerializeExtensionStdSetTypes);
TYPED_TEST(SerializeExtensionStdSet, ValuesSyntaxDifferentSetTypes) {
SerializationContext ctx1;
ctx1.createSerializer().ext4b(this->src, StdSet{10});
ctx1.createDeserializer().ext4b(this->res, StdSet{10});
EXPECT_THAT(this->res, Eq(this->src));
}
TEST(SerializeExtensionStdSet, ObjectSyntax) {
SerializationContext ctx1;
std::set<MyStruct1> t1{MyStruct1{874 ,456}, MyStruct1{-874, -456}, MyStruct1{4894,0}};
std::set<MyStruct1> r1{};
ctx1.createSerializer().ext(t1, StdSet{10});
ctx1.createDeserializer().ext(r1, StdSet{10});
EXPECT_THAT(r1, Eq(t1));
}
TEST(SerializeExtensionStdSet, FunctionSyntax) {
SerializationContext ctx1;
std::unordered_multiset<int32_t> t1{54,-484,841,79};
std::unordered_multiset<int32_t> r1{};
auto ser = ctx1.createSerializer();
ser.ext(t1, StdSet{10}, [&ser](int32_t& v) {
ser.value4b(v);
});
auto des = ctx1.createDeserializer();
des.ext(r1, StdSet{10}, [&des](int32_t& v) {
des.value4b(v);
});
EXPECT_THAT(r1, Eq(t1));
}

View File

@@ -22,61 +22,37 @@
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <bitsery/ext/std_stack.h>
#if __cplusplus > 201402L
#include<optional>
#include <bitsery/ext/optional.h>
using Optional = bitsery::ext::Optional;
using StdStack = bitsery::ext::StdStack;
using testing::Eq;
template <typename T>
void test(SerializationContext& ctx, const T& v, T& r) {
ctx.createSerializer().ext4b(v, Optional{});
ctx.createDeserializer().ext4b(r, Optional{});
ctx.createSerializer().ext4b(v, StdStack{10});
ctx.createDeserializer().ext4b(r, StdStack{10});
}
TEST(SerializeExtensionOptional, EmptyOptional) {
std::optional<int32_t> t1{};
std::optional<int32_t> r1{};
TEST(SerializeExtensionStdStack, DefaultContainer) {
std::stack<int32_t> t1{};
t1.push(3);
t1.push(-4854);
std::stack<int32_t> r1{};
SerializationContext ctx1;
test(ctx1,t1, r1);
EXPECT_THAT(ctx1.getBufferSize(), Eq(1));
EXPECT_THAT(t1, Eq(r1));
r1 = 3;
SerializationContext ctx2;
test(ctx2,t1, r1);
EXPECT_THAT(ctx2.getBufferSize(), Eq(1));
EXPECT_THAT(t1, Eq(r1));
}
TEST(SerializeExtensionOptional, OptionalHasValue) {
std::optional<int32_t> t1{43};
std::optional<int32_t> r1{52};
TEST(SerializeExtensionStdStack, VectorContainer) {
std::stack<int32_t, std::vector<int32_t>> t1{};
t1.push(3);
t1.push(-4854);
std::stack<int32_t, std::vector<int32_t>> r1{};
SerializationContext ctx1;
test(ctx1,t1, r1);
EXPECT_THAT(ctx1.getBufferSize(), Eq(1 + sizeof(int)));
EXPECT_THAT(t1.value(), Eq(r1.value()));
r1 = std::optional<int>{};
SerializationContext ctx2;
test(ctx2,t1, r1);
EXPECT_THAT(ctx2.getBufferSize(), Eq(1 + sizeof(int)));
EXPECT_THAT(t1.value(), Eq(r1.value()));
EXPECT_THAT(t1, Eq(r1));
}
#endif

View File

@@ -55,8 +55,8 @@ TEST(SerializeExtensionValueRange, IntegerNegative) {
int t1{-8};
int res1;
ctx.createSerializer().ext(t1, r1);
ctx.createDeserializer().ext(res1, r1);
ctx.createBPEnabledSerializer().ext(t1, r1);
ctx.createBPEnabledDeserializer().ext(res1, r1);
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(res1, Eq(t1));
@@ -69,8 +69,8 @@ TEST(SerializeExtensionValueRange, IntegerPositive) {
unsigned t1{8};
unsigned res1;
ctx.createSerializer().ext(t1, r1);
ctx.createDeserializer().ext(res1, r1);
ctx.createBPEnabledSerializer().ext(t1, r1);
ctx.createBPEnabledDeserializer().ext(res1, r1);
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(res1, Eq(t1));
@@ -83,8 +83,8 @@ TEST(SerializeExtensionValueRange, EnumTypes) {
MyEnumClass t1{MyEnumClass::E2};
MyEnumClass res1;
ctx.createSerializer().ext(t1, r1);
ctx.createDeserializer().ext(res1, r1);
ctx.createBPEnabledSerializer().ext(t1, r1);
ctx.createBPEnabledDeserializer().ext(res1, r1);
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(res1, Eq(t1));
@@ -101,8 +101,8 @@ TEST(SerializeExtensionValueRange, FloatUsingPrecisionConstraint1) {
float res1;
ctx.createSerializer().ext(t1, r1);
ctx.createDeserializer().ext(res1, r1);
ctx.createBPEnabledSerializer().ext(t1, r1);
ctx.createBPEnabledDeserializer().ext(res1, r1);
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(res1, ::testing::FloatNear(t1, (max - min) * precision));
@@ -118,8 +118,8 @@ TEST(SerializeExtensionValueRange, DoubleUsingPrecisionConstraint2) {
double res1;
ctx.createSerializer().ext(t1, r1);
ctx.createDeserializer().ext(res1, r1);
ctx.createBPEnabledSerializer().ext(t1, r1);
ctx.createBPEnabledDeserializer().ext(res1, r1);
EXPECT_THAT(ctx.getBufferSize(), Eq(5));
EXPECT_THAT(res1, ::testing::DoubleNear(t1, (max - min) * precision));
@@ -135,8 +135,8 @@ TEST(SerializeExtensionValueRange, FloatUsingBitsSizeConstraint1) {
float res1;
ctx.createSerializer().ext(t1, r1);
ctx.createDeserializer().ext(res1, r1);
ctx.createBPEnabledSerializer().ext(t1, r1);
ctx.createBPEnabledDeserializer().ext(res1, r1);
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(res1, ::testing::FloatNear(t1, (max - min) / (static_cast<bitsery::details::SAME_SIZE_UNSIGNED<float>>(1) << bits)));
@@ -152,8 +152,8 @@ TEST(SerializeExtensionValueRange, DoubleUsingBitsSizeConstraint2) {
double res1;
ctx.createSerializer().ext(t1, r1);
ctx.createDeserializer().ext(res1, r1);
ctx.createBPEnabledSerializer().ext(t1, r1);
ctx.createBPEnabledDeserializer().ext(res1, r1);
EXPECT_THAT(ctx.getBufferSize(), Eq(7));
EXPECT_THAT(res1, ::testing::DoubleNear(t1, (max - min) / (static_cast<bitsery::details::SAME_SIZE_UNSIGNED<double>>(1) << bits)));
@@ -164,8 +164,8 @@ TEST(SerializeExtensionValueRange, WhenDataIsInvalidThenReturnMinimumRangeValue)
ValueRange<int> r1{4, 10};//6 is max, but 3bits required
int res1;
uint8_t tmp{0xFF};//write all 1 so when reading 3 bits we get 7
ctx.createSerializer().value1b(tmp);
ctx.createDeserializer().ext(res1, r1);
ctx.createBPEnabledSerializer().value1b(tmp);
ctx.createBPEnabledDeserializer().ext(res1, r1);
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(res1, Eq(4));

View File

@@ -43,6 +43,9 @@ struct MyStruct1 {
bool operator==(const MyStruct1 &rhs) const {
return i1 == rhs.i1 && i2 == rhs.i2;
}
friend bool operator < (const MyStruct1 &lhs, const MyStruct1 &rhs) {
return lhs.i1 < rhs.i1 || (lhs.i1 == rhs.i1 && lhs.i2 < rhs.i2);
}
static constexpr size_t SIZE = sizeof(MyStruct1::i1) + sizeof(MyStruct1::i2);
};
@@ -88,6 +91,7 @@ public:
bitsery::DefaultConfig::BufferType buf{};
std::unique_ptr<bitsery::BufferWriter> bw;
std::unique_ptr<bitsery::BufferReader> br;
std::unique_ptr<bitsery::BasicSerializer<bitsery::DefaultConfig, true>> sbp;
bitsery::Serializer createSerializer() {
//make_unique is not in c++11
@@ -95,6 +99,14 @@ public:
return bitsery::Serializer{*bw};
};
bitsery::BasicSerializer<bitsery::DefaultConfig, true>& createBPEnabledSerializer() {
//make_unique is not in c++11
bw = std::unique_ptr<bitsery::BufferWriter>(new bitsery::BufferWriter(buf));
sbp = std::unique_ptr<bitsery::BasicSerializer<bitsery::DefaultConfig, true>>(
new bitsery::BasicSerializer<bitsery::DefaultConfig, true>{*bw});
return *sbp;
};
size_t getBufferSize() const {
auto range = bw->getWrittenRange();
return std::distance(range.begin(), range.end());
@@ -116,6 +128,13 @@ public:
br = std::unique_ptr<bitsery::BufferReader>(new bitsery::BufferReader(bw->getWrittenRange()));
return bitsery::Deserializer{*br};
};
bitsery::BasicDeserializer<bitsery::DefaultConfig, true> createBPEnabledDeserializer() {
sbp.reset(nullptr);
//make_unique is not in c++11
br = std::unique_ptr<bitsery::BufferReader>(new bitsery::BufferReader(bw->getWrittenRange()));
return bitsery::BasicDeserializer<bitsery::DefaultConfig, true>{*br};
};
};
#endif //BITSERY_SERIALIZER_TEST_UTILS_H