diff --git a/include/Common.h b/include/Common.h index 4802839..1c6a6f0 100644 --- a/include/Common.h +++ b/include/Common.h @@ -51,6 +51,9 @@ struct BIGGER_TYPE { template constexpr size_t ARITHMETIC_OR_ENUM_SIZE = std::is_arithmetic::value || std::is_enum::value ? sizeof(T) : 0; +template +using UINT_FOR_FLOATING_POINT = std::conditional_t::value, uint32_t, uint64_t>; + template struct ProcessAnyType { template @@ -72,12 +75,8 @@ 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); +constexpr size_t calcRequiredBits(T min, T max) { size_t res{}; for (auto diff = max - min; diff > 0; diff >>= 1) ++res; @@ -93,54 +92,71 @@ public: :_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; + const T _min; + const T _max; + const 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)} - { - + _min{min}, + _max{max}, + _bitsRequired{calcRequiredBits( + static_cast>(_min), + static_cast>(_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; + const T _min; + const T _max; + const size_t _bitsRequired; }; +template +class RangeSpec::value>::type> { +public: + + //todo bits should be separate size not implicitly convertable from floating point types, so these constructors would be ambiguous + constexpr RangeSpec(T min, T max, size_t bits, int tmp): + _min{min}, + _max{max}, + _bitsRequired{bits} + { + } + + constexpr RangeSpec(T min, T max, T precision): + _min{min}, + _max{max}, + _bitsRequired{calcRequiredBits>({}, ((max - min) / precision))} + { + + } + + constexpr size_t bitsRequired() const { + return _bitsRequired; + } + +private: + const T _min; + const T _max; + const size_t _bitsRequired; +}; class ObjectMemoryPosition { diff --git a/include/Deserializer.h b/include/Deserializer.h index 5a2b1ee..4ff3b85 100644 --- a/include/Deserializer.h +++ b/include/Deserializer.h @@ -28,9 +28,7 @@ public: static_assert(std::numeric_limits::is_iec559, ""); constexpr size_t ValueSize = VSIZE == 0 ? sizeof(T) : VSIZE; - using CT = std::conditional_t::value, uint32_t, uint64_t>; - static_assert(sizeof(CT) == ValueSize, ""); - _reader.template readBytes(reinterpret_cast(v)); + _reader.template readBytes(reinterpret_cast&>(v)); return *this; } @@ -54,8 +52,9 @@ public: */ template - Deserializer& range(T& v, RangeSpec r) { - _reader.template readBits(r.valueProxy(v), r.bitsRequired()); + Deserializer& range(T& v, const RangeSpec& range) { + //ValueWriteProxy proxy{v, range}; + //_reader.template readBits(proxy.value(), r.bitsRequired()); return *this; } diff --git a/include/Serializer.h b/include/Serializer.h index 169a090..e216a6a 100644 --- a/include/Serializer.h +++ b/include/Serializer.h @@ -27,9 +27,8 @@ public: static_assert(std::numeric_limits::is_iec559, ""); static_assert(std::numeric_limits::is_iec559, ""); - constexpr size_t ValueSize = VSIZE == 0 ? sizeof(T) : VSIZE; - using CT = std::conditional_t::value, uint32_t, uint64_t>; - _writter.template writeBytes(reinterpret_cast(v)); + constexpr size_t ValueSize = VSIZE == 0 ? sizeof(T) : VSIZE; + _writter.template writeBytes(reinterpret_cast&>(v)); return *this; } @@ -52,9 +51,9 @@ public: */ template - Serializer& range(const T& v, RangeSpec r) { - assert(r.isValid(v)); - _writter.template writeBits(r.value(v), r.bitsRequired()); + Serializer& range(const T& v, const RangeSpec& r) { + //assert(r.isValid(v)); + //_writter.template writeBits(r.value(v), r.bitsRequired()); return *this; } diff --git a/tests/SerializationRangeTests.cpp b/tests/SerializationRangeTests.cpp index 89faa8c..418bb4b 100644 --- a/tests/SerializationRangeTests.cpp +++ b/tests/SerializationRangeTests.cpp @@ -6,27 +6,17 @@ #include "SerializationTestUtils.h" using namespace testing; -TEST(Ranges, IntegralRanges) { +TEST(Ranges, RequiredBitsIsConstexpr) { 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)); + static_assert(r2.bitsRequired() == 2); - int x= 0; - RangeSpec r3{x,3}; - EXPECT_THAT(r3.bitsRequired(), Eq(2)); + constexpr RangeSpec r3{-1.0,1.0, 5u, 0}; + static_assert(r3.bitsRequired() == 5); + constexpr RangeSpec r4{-1.0f,1.0f, 0.01f}; + static_assert(r4.bitsRequired() == 8); - 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