mirror of
https://github.com/fraillt/bitsery.git
synced 2026-08-15 15:49:55 +00:00
range spec bits required is constexpr
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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});
|
||||
}
|
||||
Reference in New Issue
Block a user