range implementation complete

This commit is contained in:
fraillt
2017-02-17 15:51:34 +02:00
parent 5d2d547330
commit 08cd2b3dfa
9 changed files with 287 additions and 125 deletions

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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);
};