mirror of
https://github.com/fraillt/bitsery.git
synced 2026-09-29 21:46:22 +00:00
range implementation complete
This commit is contained in:
110
include/Common.h
110
include/Common.h
@@ -51,8 +51,25 @@ 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, typename Enable = void>
|
||||
struct SAME_SIZE_UNSIGNED_TYPE {
|
||||
typedef std::make_unsigned_t<T> type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SAME_SIZE_UNSIGNED_TYPE<T, typename std::enable_if<std::is_enum<T>::value>::type> {
|
||||
typedef std::make_unsigned_t<std::underlying_type_t<T>> type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SAME_SIZE_UNSIGNED_TYPE<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
|
||||
typedef std::conditional_t<std::is_same<T,float>::value, uint32_t, uint64_t> type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using UINT_FOR_FLOATING_POINT = std::conditional_t<std::is_same<T,float>::value, uint32_t, uint64_t>;
|
||||
using SAME_SIZE_UNSIGNED = typename SAME_SIZE_UNSIGNED_TYPE<T>::type;
|
||||
|
||||
|
||||
template <size_t SIZE>
|
||||
struct ProcessAnyType {
|
||||
@@ -84,78 +101,65 @@ constexpr size_t calcRequiredBits(T min, T max) {
|
||||
}
|
||||
|
||||
|
||||
template <typename T, class Enable = void>
|
||||
class RangeSpec {
|
||||
public:
|
||||
template <typename T, typename Enable = void>
|
||||
struct RangeSpec {
|
||||
|
||||
constexpr RangeSpec(T min, T max)
|
||||
:_min{min},
|
||||
_max{max},
|
||||
_bitsRequired{calcRequiredBits(_min, _max)}
|
||||
{
|
||||
constexpr RangeSpec(T minValue, T maxValue)
|
||||
:min{minValue},
|
||||
max{maxValue},
|
||||
bitsRequired{calcRequiredBits(min, max)}
|
||||
{
|
||||
}
|
||||
|
||||
constexpr size_t bitsRequired() const {
|
||||
return _bitsRequired;
|
||||
}
|
||||
|
||||
private:
|
||||
const T _min;
|
||||
const T _max;
|
||||
const 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:
|
||||
|
||||
constexpr RangeSpec(T min, T max):
|
||||
_min{min},
|
||||
_max{max},
|
||||
_bitsRequired{calcRequiredBits(
|
||||
static_cast<std::underlying_type_t<T>>(_min),
|
||||
static_cast<std::underlying_type_t<T>>(_max))}
|
||||
struct RangeSpec<T, typename std::enable_if<std::is_enum<T>::value>::type> {
|
||||
|
||||
constexpr RangeSpec(T minValue, T maxValue):
|
||||
min{minValue},
|
||||
max{maxValue},
|
||||
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;
|
||||
}
|
||||
const T min;
|
||||
const T max;
|
||||
const size_t bitsRequired;
|
||||
};
|
||||
|
||||
private:
|
||||
const T _min;
|
||||
const T _max;
|
||||
const size_t _bitsRequired;
|
||||
//this class is used to make default RangeSpec float specialization always prefer constructor with precision
|
||||
struct BitsConstraint {
|
||||
explicit constexpr BitsConstraint(size_t bits):value{bits} {}
|
||||
const size_t value;
|
||||
};
|
||||
|
||||
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}
|
||||
struct RangeSpec<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
|
||||
|
||||
constexpr RangeSpec(T minValue, T maxValue, BitsConstraint bits):
|
||||
min{minValue},
|
||||
max{maxValue},
|
||||
bitsRequired{bits.value}
|
||||
{
|
||||
}
|
||||
|
||||
constexpr RangeSpec(T min, T max, T precision):
|
||||
_min{min},
|
||||
_max{max},
|
||||
_bitsRequired{calcRequiredBits<UINT_FOR_FLOATING_POINT<T>>({}, ((max - min) / precision))}
|
||||
constexpr RangeSpec(T minValue, T maxValue, T precision):
|
||||
min{minValue},
|
||||
max{maxValue},
|
||||
bitsRequired{calcRequiredBits<SAME_SIZE_UNSIGNED<T>>({}, ((max - min) / precision))}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
constexpr size_t bitsRequired() const {
|
||||
return _bitsRequired;
|
||||
}
|
||||
|
||||
private:
|
||||
const T _min;
|
||||
const T _max;
|
||||
const size_t _bitsRequired;
|
||||
const T min;
|
||||
const T max;
|
||||
const size_t bitsRequired;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
static_assert(std::numeric_limits<double>::is_iec559, "");
|
||||
|
||||
constexpr size_t ValueSize = VSIZE == 0 ? sizeof(T) : VSIZE;
|
||||
_reader.template readBytes<ValueSize>(reinterpret_cast<UINT_FOR_FLOATING_POINT<T>&>(v));
|
||||
_reader.template readBytes<ValueSize>(reinterpret_cast<SAME_SIZE_UNSIGNED<T>&>(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ public:
|
||||
|
||||
template <typename T>
|
||||
Deserializer& range(T& v, const RangeSpec<T>& range) {
|
||||
//ValueWriteProxy<T> proxy{v, range};
|
||||
//_reader.template readBits(proxy.value(), r.bitsRequired());
|
||||
_reader.template readBits(reinterpret_cast<SAME_SIZE_UNSIGNED<T>&>(v), range.bitsRequired);
|
||||
setRangeValue(v, range);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -186,5 +186,28 @@ private:
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* functions for range
|
||||
*/
|
||||
template<typename T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
|
||||
void setRangeValue(T& v, const RangeSpec<T>& r) {
|
||||
v += r.min;
|
||||
};
|
||||
|
||||
template<typename T, typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
|
||||
void setRangeValue(T& v, const RangeSpec<T>& r) {
|
||||
using VT = std::underlying_type_t<T>;
|
||||
reinterpret_cast<VT&>(v) += static_cast<VT>(r.min);
|
||||
};
|
||||
|
||||
template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
|
||||
void setRangeValue(T& v, const RangeSpec<T>& r) {
|
||||
using UIT = SAME_SIZE_UNSIGNED<T>;
|
||||
const auto intRep = reinterpret_cast<UIT&>(v);
|
||||
const UIT maxUint = (static_cast<UIT>(1) << r.bitsRequired) - 1;
|
||||
v = r.min + (static_cast<T>(intRep) / maxUint) * (r.max - r.min);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //TMP_DESERIALIZER_H
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
static_assert(std::numeric_limits<double>::is_iec559, "");
|
||||
|
||||
constexpr size_t ValueSize = VSIZE == 0 ? sizeof(T) : VSIZE;
|
||||
_writter.template writeBytes<ValueSize>(reinterpret_cast<const UINT_FOR_FLOATING_POINT<T>&>(v));
|
||||
_writter.template writeBytes<ValueSize>(reinterpret_cast<const SAME_SIZE_UNSIGNED<T>&>(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -51,9 +51,9 @@ public:
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
Serializer& range(const T& v, const RangeSpec<T>& r) {
|
||||
//assert(r.isValid(v));
|
||||
//_writter.template writeBits(r.value(v), r.bitsRequired());
|
||||
Serializer& range(const T& v, const RangeSpec<T>& range) {
|
||||
assert(isRangeValid(v, range));
|
||||
_writter.template writeBits(getRangeValue(v,range), range.bitsRequired);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -174,7 +174,41 @@ private:
|
||||
if (size)
|
||||
_writter.template writeBuffer<VSIZE>(str, size);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* functions for range
|
||||
*/
|
||||
|
||||
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
|
||||
bool isRangeValid(const T& v, const RangeSpec<T>& r) {
|
||||
return !(r.min > v || v > r.max);
|
||||
}
|
||||
|
||||
template<typename T, typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
|
||||
bool isRangeValid(const T& v, const RangeSpec<T>& r) {
|
||||
using VT = std::underlying_type_t<T>;
|
||||
return !(static_cast<VT>(r.min) > static_cast<VT>(v)
|
||||
|| static_cast<VT>(v) > static_cast<VT>(r.max));
|
||||
}
|
||||
|
||||
|
||||
template<typename T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
|
||||
auto getRangeValue(const T& v, const RangeSpec<T>& r) {
|
||||
return static_cast<SAME_SIZE_UNSIGNED<T>>(v - r.min);
|
||||
};
|
||||
|
||||
template<typename T, typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
|
||||
auto getRangeValue(const T& v, const RangeSpec<T>& r) {
|
||||
return static_cast<SAME_SIZE_UNSIGNED<T>>(v) - static_cast<SAME_SIZE_UNSIGNED<T>>(r.min);
|
||||
};
|
||||
|
||||
template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
|
||||
auto getRangeValue(const T& v, const RangeSpec<T>& r) {
|
||||
using VT = SAME_SIZE_UNSIGNED<T>;
|
||||
const VT maxUint = (static_cast<VT>(1) << r.bitsRequired) - 1;
|
||||
const auto ratio = (v - r.min) / (r.max - r.min);
|
||||
return static_cast<VT>(ratio * maxUint);
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user