range spec bits required is constexpr

This commit is contained in:
Mindaugas Vinkelis
2017-02-16 20:42:27 +02:00
parent 0ed492d9b4
commit 5d2d547330
4 changed files with 63 additions and 59 deletions

View File

@@ -51,6 +51,9 @@ struct BIGGER_TYPE<char> {
template <typename T>
constexpr size_t ARITHMETIC_OR_ENUM_SIZE = std::is_arithmetic<T>::value || std::is_enum<T>::value ? sizeof(T) : 0;
template <typename T>
using UINT_FOR_FLOATING_POINT = std::conditional_t<std::is_same<T,float>::value, uint32_t, uint64_t>;
template <size_t SIZE>
struct ProcessAnyType {
template <typename S, typename T>
@@ -72,12 +75,8 @@ struct ProcessAnyType<0> {
template <typename S, typename T, typename std::enable_if<std::is_same<T, ObjectType>::value || std::is_same<T, const ObjectType>::value>::type* = nullptr> \
S& serialize(S& s, T& o)
extern int no_symbol;
template <typename T>
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 <typename T>
class RangeSpec<T, typename std::enable_if<std::is_enum<T>::value>::type> {
public:
using value_type = typename std::underlying_type<T>::type;
constexpr RangeSpec(T min, T max):
_min{static_cast<value_type>(min)},
_max{static_cast<value_type>(max)},
_bitsRequired{calcRequiredBits(_min, _max)}
{
_min{min},
_max{max},
_bitsRequired{calcRequiredBits(
static_cast<std::underlying_type_t<T>>(_min),
static_cast<std::underlying_type_t<T>>(_max))}
{
}
constexpr size_t bitsRequired() const {
return _bitsRequired;
}
constexpr bool isValid(const T& v) const {
return !(_max < static_cast<value_type>(v) || static_cast<value_type>(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 <typename T>
class RangeSpec<T, typename std::enable_if<std::is_floating_point<T>::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<UINT_FOR_FLOATING_POINT<T>>({}, ((max - min) / precision))}
{
}
constexpr size_t bitsRequired() const {
return _bitsRequired;
}
private:
const T _min;
const T _max;
const size_t _bitsRequired;
};
class ObjectMemoryPosition {

View File

@@ -28,9 +28,7 @@ public:
static_assert(std::numeric_limits<double>::is_iec559, "");
constexpr size_t ValueSize = VSIZE == 0 ? sizeof(T) : VSIZE;
using CT = std::conditional_t<std::is_same<T,float>::value, uint32_t, uint64_t>;
static_assert(sizeof(CT) == ValueSize, "");
_reader.template readBytes<ValueSize>(reinterpret_cast<CT&>(v));
_reader.template readBytes<ValueSize>(reinterpret_cast<UINT_FOR_FLOATING_POINT<T>&>(v));
return *this;
}
@@ -54,8 +52,9 @@ public:
*/
template <typename T>
Deserializer& range(T& v, RangeSpec<T> r) {
_reader.template readBits(r.valueProxy(v), r.bitsRequired());
Deserializer& range(T& v, const RangeSpec<T>& range) {
//ValueWriteProxy<T> proxy{v, range};
//_reader.template readBits(proxy.value(), r.bitsRequired());
return *this;
}

View File

@@ -27,9 +27,8 @@ public:
static_assert(std::numeric_limits<float>::is_iec559, "");
static_assert(std::numeric_limits<double>::is_iec559, "");
constexpr size_t ValueSize = VSIZE == 0 ? sizeof(T) : VSIZE;
using CT = std::conditional_t<std::is_same<T,float>::value, uint32_t, uint64_t>;
_writter.template writeBytes<ValueSize>(reinterpret_cast<const CT&>(v));
constexpr size_t ValueSize = VSIZE == 0 ? sizeof(T) : VSIZE;
_writter.template writeBytes<ValueSize>(reinterpret_cast<const UINT_FOR_FLOATING_POINT<T>&>(v));
return *this;
}
@@ -52,9 +51,9 @@ public:
*/
template <typename T>
Serializer& range(const T& v, RangeSpec<T> r) {
assert(r.isValid(v));
_writter.template writeBits(r.value(v), r.bitsRequired());
Serializer& range(const T& v, const RangeSpec<T>& r) {
//assert(r.isValid(v));
//_writter.template writeBits(r.value(v), r.bitsRequired());
return *this;
}

View File

@@ -6,27 +6,17 @@
#include "SerializationTestUtils.h"
using namespace testing;
TEST(Ranges, IntegralRanges) {
TEST(Ranges, RequiredBitsIsConstexpr) {
constexpr RangeSpec<int> 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<MyEnumClass> 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<int> r3{x,3};
EXPECT_THAT(r3.bitsRequired(), Eq(2));
constexpr RangeSpec<double> r3{-1.0,1.0, 5u, 0};
static_assert(r3.bitsRequired() == 5);
constexpr RangeSpec<float> 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});
}