diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 2caf148..ebbbdfe 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -7,5 +7,9 @@ file(GLOB EXAMPLE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) FOREACH(EXAMPLE ${EXAMPLE_FILES}) get_filename_component(EXAMPLE_NAME ${EXAMPLE} NAME_WE) add_executable(${EXAMPLE_NAME} ${EXAMPLE}) + + set_property(TARGET ${EXAMPLE_NAME} PROPERTY CXX_STANDARD 14) + set_property(TARGET ${EXAMPLE_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) + ENDFOREACH() diff --git a/include/Common.h b/include/Common.h index d4f91c4..4802839 100644 --- a/include/Common.h +++ b/include/Common.h @@ -72,6 +72,76 @@ struct ProcessAnyType<0> { template ::value || std::is_same::value>::type* = nullptr> \ S& serialize(S& s, T& o) +extern int no_symbol; + +template +constexpr size_t calcRequiredBits(T min, T max) { + (T)min != min ? throw (no_symbol) : 0; + assert(min < max); + size_t res{}; + for (auto diff = max - min; diff > 0; diff >>= 1) + ++res; + return res; +} + + +template +class RangeSpec { +public: + + constexpr RangeSpec(T min, T max) + :_min{min}, + _max{max}, + _bitsRequired{calcRequiredBits(_min, _max)} + { + + } + + constexpr size_t bitsRequired() const { + return _bitsRequired; + } + + constexpr bool isValid(const T& v) const { + return !(_max < v || v < _min); + } + + +private: + T _min; + T _max; + size_t _bitsRequired; +}; + + +template +class RangeSpec::value>::type> { +public: + using value_type = typename std::underlying_type::type; + constexpr RangeSpec(T min, T max): + _min{static_cast(min)}, + _max{static_cast(max)}, + _bitsRequired{calcRequiredBits(_min, _max)} + { + + } + constexpr size_t bitsRequired() const { + return _bitsRequired; + } + constexpr bool isValid(const T& v) const { + return !(_max < static_cast(v) || static_cast(v) < _min); + } + + T getValue(T v) const { + //return v - _min; + return v; + } +private: + value_type _min; + value_type _max; + size_t _bitsRequired; +}; + + class ObjectMemoryPosition { public: diff --git a/include/Deserializer.h b/include/Deserializer.h index 8111d58..5a2b1ee 100644 --- a/include/Deserializer.h +++ b/include/Deserializer.h @@ -49,6 +49,16 @@ public: return *this; } + /* + * range + */ + + template + Deserializer& range(T& v, RangeSpec r) { + _reader.template readBits(r.valueProxy(v), r.bitsRequired()); + return *this; + } + /* * text overloads */ diff --git a/include/Serializer.h b/include/Serializer.h index 436c01d..169a090 100644 --- a/include/Serializer.h +++ b/include/Serializer.h @@ -47,6 +47,17 @@ public: return *this; } + /* + * range + */ + + template + Serializer& range(const T& v, RangeSpec r) { + assert(r.isValid(v)); + _writter.template writeBits(r.value(v), r.bitsRequired()); + return *this; + } + /* * text overloads */ diff --git a/tests/SerializationRangeTests.cpp b/tests/SerializationRangeTests.cpp new file mode 100644 index 0000000..89faa8c --- /dev/null +++ b/tests/SerializationRangeTests.cpp @@ -0,0 +1,32 @@ +// +// Created by fraillt on 17.2.15. +// + +#include +#include "SerializationTestUtils.h" +using namespace testing; + +TEST(Ranges, IntegralRanges) { + constexpr RangeSpec r1{0, 31}; + static_assert(r1.bitsRequired() == 5); + EXPECT_TRUE(r1.isValid(0)); + EXPECT_TRUE(r1.isValid(15)); + EXPECT_TRUE(r1.isValid(31)); + EXPECT_FALSE(r1.isValid(-1)); + EXPECT_FALSE(r1.isValid(32)); + + constexpr RangeSpec r2{MyEnumClass::E1, MyEnumClass::E4}; + EXPECT_TRUE(r2.isValid(MyEnumClass::E2)); + EXPECT_FALSE(r2.isValid(MyEnumClass::E5)); + + int x= 0; + RangeSpec r3{x,3}; + EXPECT_THAT(r3.bitsRequired(), Eq(2)); + + + SerializationContext ctx; +// ctx.createSerializer().range(486, {0,900}); +// ctx.createSerializer().range(MyEnumClass::E4, {MyEnumClass::E1,MyEnumClass::E6}); +// ctx.createSerializer().range(4.5f, {0.0f,10.0f, 10}); +// ctx.createSerializer().range(4.5f, {0.0f,10.0f, 0.001f}); +} \ No newline at end of file diff --git a/tests/SerializationTestUtils.h b/tests/SerializationTestUtils.h index 50cd12e..08e0f1e 100644 --- a/tests/SerializationTestUtils.h +++ b/tests/SerializationTestUtils.h @@ -28,9 +28,13 @@ SERIALIZE(MyStruct1) { value(o.i2); } +enum class MyEnumClass { + E1, E2, E3, E4, E5, E6 +}; + struct MyStruct2 { enum MyEnum { - V1, V2, V3 + V1, V2, V3, V4, V5, V6 }; MyStruct2(MyEnum e, MyStruct1 s):e1{e}, s1{s} {}