mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 04:02:42 +01:00
Type hacks removed
This commit is contained in:
parent
2d512121f1
commit
949200cd3e
@ -3,54 +3,57 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
|
||||||
|
// 128-bit vector type and also se_storage<> storage type
|
||||||
union alignas(16) v128
|
union alignas(16) v128
|
||||||
{
|
{
|
||||||
char _bytes[16];
|
char _bytes[16];
|
||||||
|
|
||||||
template<typename T, std::size_t N, std::size_t M>
|
template <typename T, std::size_t N, std::size_t M>
|
||||||
struct masked_array_t // array type accessed as (index ^ M)
|
struct masked_array_t // array type accessed as (index ^ M)
|
||||||
{
|
{
|
||||||
T m_data[N];
|
T m_data[N];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
T& operator [](std::size_t index)
|
T& operator[](std::size_t index)
|
||||||
{
|
{
|
||||||
return m_data[index ^ M];
|
return m_data[index ^ M];
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& operator [](std::size_t index) const
|
const T& operator[](std::size_t index) const
|
||||||
{
|
{
|
||||||
return m_data[index ^ M];
|
return m_data[index ^ M];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if IS_LE_MACHINE == 1
|
#if IS_LE_MACHINE == 1
|
||||||
template<typename T, std::size_t N = 16 / sizeof(T)> using normal_array_t = masked_array_t<T, N, 0>;
|
template <typename T, std::size_t N = 16 / sizeof(T)>
|
||||||
template<typename T, std::size_t N = 16 / sizeof(T)> using reversed_array_t = masked_array_t<T, N, N - 1>;
|
using normal_array_t = masked_array_t<T, N, 0>;
|
||||||
|
template <typename T, std::size_t N = 16 / sizeof(T)>
|
||||||
|
using reversed_array_t = masked_array_t<T, N, N - 1>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
normal_array_t<u64> _u64;
|
normal_array_t<u64> _u64;
|
||||||
normal_array_t<s64> _s64;
|
normal_array_t<s64> _s64;
|
||||||
reversed_array_t<u64> u64r;
|
reversed_array_t<u64> u64r;
|
||||||
reversed_array_t<s64> s64r;
|
reversed_array_t<s64> s64r;
|
||||||
|
|
||||||
normal_array_t<u32> _u32;
|
normal_array_t<u32> _u32;
|
||||||
normal_array_t<s32> _s32;
|
normal_array_t<s32> _s32;
|
||||||
reversed_array_t<u32> u32r;
|
reversed_array_t<u32> u32r;
|
||||||
reversed_array_t<s32> s32r;
|
reversed_array_t<s32> s32r;
|
||||||
|
|
||||||
normal_array_t<u16> _u16;
|
normal_array_t<u16> _u16;
|
||||||
normal_array_t<s16> _s16;
|
normal_array_t<s16> _s16;
|
||||||
reversed_array_t<u16> u16r;
|
reversed_array_t<u16> u16r;
|
||||||
reversed_array_t<s16> s16r;
|
reversed_array_t<s16> s16r;
|
||||||
|
|
||||||
normal_array_t<u8> _u8;
|
normal_array_t<u8> _u8;
|
||||||
normal_array_t<s8> _s8;
|
normal_array_t<s8> _s8;
|
||||||
reversed_array_t<u8> u8r;
|
reversed_array_t<u8> u8r;
|
||||||
reversed_array_t<s8> s8r;
|
reversed_array_t<s8> s8r;
|
||||||
|
|
||||||
normal_array_t<f32> _f;
|
normal_array_t<f32> _f;
|
||||||
normal_array_t<f64> _d;
|
normal_array_t<f64> _d;
|
||||||
reversed_array_t<f32> fr;
|
reversed_array_t<f32> fr;
|
||||||
reversed_array_t<f64> dr;
|
reversed_array_t<f64> dr;
|
||||||
|
|
||||||
@ -80,7 +83,7 @@ union alignas(16) v128
|
|||||||
return (data & mask) != 0;
|
return (data & mask) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bit_element& operator =(const bool right)
|
bit_element& operator=(const bool right)
|
||||||
{
|
{
|
||||||
if (right)
|
if (right)
|
||||||
{
|
{
|
||||||
@ -93,7 +96,7 @@ union alignas(16) v128
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bit_element& operator =(const bit_element& right)
|
bit_element& operator=(const bit_element& right)
|
||||||
{
|
{
|
||||||
if (right)
|
if (right)
|
||||||
{
|
{
|
||||||
@ -108,7 +111,7 @@ union alignas(16) v128
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Index 0 returns the MSB and index 127 returns the LSB
|
// Index 0 returns the MSB and index 127 returns the LSB
|
||||||
bit_element operator [](u32 index)
|
bit_element operator[](u32 index)
|
||||||
{
|
{
|
||||||
#if IS_LE_MACHINE == 1
|
#if IS_LE_MACHINE == 1
|
||||||
return bit_element(m_data[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F));
|
return bit_element(m_data[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F));
|
||||||
@ -116,14 +119,13 @@ union alignas(16) v128
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Index 0 returns the MSB and index 127 returns the LSB
|
// Index 0 returns the MSB and index 127 returns the LSB
|
||||||
bool operator [](u32 index) const
|
bool operator[](u32 index) const
|
||||||
{
|
{
|
||||||
#if IS_LE_MACHINE == 1
|
#if IS_LE_MACHINE == 1
|
||||||
return (m_data[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
|
return (m_data[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
} _bit;
|
||||||
_bit;
|
|
||||||
|
|
||||||
static v128 from64(u64 _0, u64 _1 = 0)
|
static v128 from64(u64 _0, u64 _1 = 0)
|
||||||
{
|
{
|
||||||
@ -277,12 +279,12 @@ union alignas(16) v128
|
|||||||
return fromV(_mm_cmpeq_epi32(left.vi, right.vi));
|
return fromV(_mm_cmpeq_epi32(left.vi, right.vi));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator ==(const v128& right) const
|
bool operator==(const v128& right) const
|
||||||
{
|
{
|
||||||
return _u64[0] == right._u64[0] && _u64[1] == right._u64[1];
|
return _u64[0] == right._u64[0] && _u64[1] == right._u64[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator !=(const v128& right) const
|
bool operator!=(const v128& right) const
|
||||||
{
|
{
|
||||||
return _u64[0] != right._u64[0] || _u64[1] != right._u64[1];
|
return _u64[0] != right._u64[0] || _u64[1] != right._u64[1];
|
||||||
}
|
}
|
||||||
@ -300,30 +302,27 @@ union alignas(16) v128
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline v128 operator |(const v128& left, const v128& right)
|
inline v128 operator|(const v128& left, const v128& right)
|
||||||
{
|
{
|
||||||
return v128::fromV(_mm_or_si128(left.vi, right.vi));
|
return v128::fromV(_mm_or_si128(left.vi, right.vi));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline v128 operator &(const v128& left, const v128& right)
|
inline v128 operator&(const v128& left, const v128& right)
|
||||||
{
|
{
|
||||||
return v128::fromV(_mm_and_si128(left.vi, right.vi));
|
return v128::fromV(_mm_and_si128(left.vi, right.vi));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline v128 operator ^(const v128& left, const v128& right)
|
inline v128 operator^(const v128& left, const v128& right)
|
||||||
{
|
{
|
||||||
return v128::fromV(_mm_xor_si128(left.vi, right.vi));
|
return v128::fromV(_mm_xor_si128(left.vi, right.vi));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline v128 operator ~(const v128& other)
|
inline v128 operator~(const v128& other)
|
||||||
{
|
{
|
||||||
return v128::from64(~other._u64[0], ~other._u64[1]);
|
return v128::from64(~other._u64[0], ~other._u64[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IS_INTEGER(t) (std::is_integral<t>::value || std::is_enum<t>::value)
|
template <typename T, std::size_t Align, std::size_t Size>
|
||||||
#define IS_BINARY_COMPARABLE(t1, t2) (IS_INTEGER(t1) && IS_INTEGER(t2) && sizeof(t1) == sizeof(t2))
|
|
||||||
|
|
||||||
template<typename T, std::size_t Align, std::size_t Size>
|
|
||||||
struct se_storage
|
struct se_storage
|
||||||
{
|
{
|
||||||
using type = std::aligned_storage_t<Size, Align>;
|
using type = std::aligned_storage_t<Size, Align>;
|
||||||
@ -359,7 +358,7 @@ struct se_storage
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct se_storage<T, 2, 2>
|
struct se_storage<T, 2, 2>
|
||||||
{
|
{
|
||||||
using type = u16;
|
using type = u16;
|
||||||
@ -386,11 +385,11 @@ struct se_storage<T, 2, 2>
|
|||||||
|
|
||||||
static inline T copy(const T& src)
|
static inline T copy(const T& src)
|
||||||
{
|
{
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct se_storage<T, 4, 4>
|
struct se_storage<T, 4, 4>
|
||||||
{
|
{
|
||||||
using type = u32;
|
using type = u32;
|
||||||
@ -417,11 +416,11 @@ struct se_storage<T, 4, 4>
|
|||||||
|
|
||||||
static inline T copy(const T& src)
|
static inline T copy(const T& src)
|
||||||
{
|
{
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct se_storage<T, 8, 8>
|
struct se_storage<T, 8, 8>
|
||||||
{
|
{
|
||||||
using type = u64;
|
using type = u64;
|
||||||
@ -448,11 +447,11 @@ struct se_storage<T, 8, 8>
|
|||||||
|
|
||||||
static inline T copy(const T& src)
|
static inline T copy(const T& src)
|
||||||
{
|
{
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct se_storage<T, 16, 16>
|
struct se_storage<T, 16, 16>
|
||||||
{
|
{
|
||||||
using type = v128;
|
using type = v128;
|
||||||
@ -475,14 +474,12 @@ struct se_storage<T, 16, 16>
|
|||||||
|
|
||||||
static inline T copy(const T& src)
|
static inline T copy(const T& src)
|
||||||
{
|
{
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct se_raw_tag_t {} constexpr se_raw{};
|
|
||||||
|
|
||||||
// Switched endianness
|
// Switched endianness
|
||||||
template<typename T, std::size_t Align>
|
template <typename T, std::size_t Align>
|
||||||
class se_t<T, true, Align>
|
class se_t<T, true, Align>
|
||||||
{
|
{
|
||||||
using type = typename std::remove_cv<T>::type;
|
using type = typename std::remove_cv<T>::type;
|
||||||
@ -496,24 +493,6 @@ class se_t<T, true, Align>
|
|||||||
static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)");
|
static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)");
|
||||||
static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment");
|
static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment");
|
||||||
|
|
||||||
template<typename T2, typename = void>
|
|
||||||
struct bool_converter
|
|
||||||
{
|
|
||||||
static inline bool to_bool(const se_t<T2>& value)
|
|
||||||
{
|
|
||||||
return static_cast<bool>(value.value());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T2>
|
|
||||||
struct bool_converter<T2, std::enable_if_t<std::is_integral<T2>::value>>
|
|
||||||
{
|
|
||||||
static inline bool to_bool(const se_t<T2>& value)
|
|
||||||
{
|
|
||||||
return value.m_data != 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
se_t() = default;
|
se_t() = default;
|
||||||
|
|
||||||
@ -523,27 +502,15 @@ public:
|
|||||||
: m_data(storage::to(value))
|
: m_data(storage::to(value))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct directly from raw data (don't use)
|
|
||||||
constexpr se_t(const stype& raw_value, const se_raw_tag_t&)
|
|
||||||
: m_data(raw_value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
type value() const
|
type value() const
|
||||||
{
|
{
|
||||||
return storage::from(m_data);
|
return storage::from(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access underlying raw data (don't use)
|
se_t& operator=(const se_t&) = default;
|
||||||
constexpr const stype& raw_data() const noexcept
|
|
||||||
{
|
|
||||||
return m_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
se_t& operator =(const se_t&) = default;
|
|
||||||
|
|
||||||
se_t& operator =(type value)
|
se_t& operator=(type value)
|
||||||
{
|
{
|
||||||
return m_data = storage::to(value), *this;
|
return m_data = storage::to(value), *this;
|
||||||
}
|
}
|
||||||
@ -554,58 +521,10 @@ public:
|
|||||||
{
|
{
|
||||||
return storage::from(m_data);
|
return storage::from(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimization
|
|
||||||
explicit operator bool() const
|
|
||||||
{
|
|
||||||
return bool_converter<type>::to_bool(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T2>
|
|
||||||
std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator &=(const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return m_data &= right.raw_data(), *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename CT>
|
|
||||||
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator &=(CT right)
|
|
||||||
{
|
|
||||||
return m_data &= storage::to(right), *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T2>
|
|
||||||
std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator |=(const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return m_data |= right.raw_data(), *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename CT>
|
|
||||||
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator |=(CT right)
|
|
||||||
{
|
|
||||||
return m_data |= storage::to(right), *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T2>
|
|
||||||
std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator ^=(const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return m_data ^= right.raw_data(), *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename CT>
|
|
||||||
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator ^=(CT right)
|
|
||||||
{
|
|
||||||
return m_data ^= storage::to(right), *this;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Native endianness
|
// Native endianness
|
||||||
template<typename T, std::size_t Align>
|
template <typename T, std::size_t Align>
|
||||||
class se_t<T, false, Align>
|
class se_t<T, false, Align>
|
||||||
{
|
{
|
||||||
using type = typename std::remove_cv<T>::type;
|
using type = typename std::remove_cv<T>::type;
|
||||||
@ -627,26 +546,14 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct directly from raw data (don't use)
|
|
||||||
constexpr se_t(const stype& raw_value, const se_raw_tag_t&)
|
|
||||||
: m_data(raw_value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
type value() const
|
type value() const
|
||||||
{
|
{
|
||||||
return storage::copy(reinterpret_cast<const type&>(m_data));
|
return storage::copy(reinterpret_cast<const type&>(m_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access underlying raw data (don't use)
|
se_t& operator=(const se_t& value) = default;
|
||||||
constexpr const stype& raw_data() const noexcept
|
|
||||||
{
|
|
||||||
return m_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
se_t& operator =(const se_t& value) = default;
|
se_t& operator=(type value)
|
||||||
|
|
||||||
se_t& operator =(type value)
|
|
||||||
{
|
{
|
||||||
return m_data = reinterpret_cast<const stype&>(value), *this;
|
return m_data = reinterpret_cast<const stype&>(value), *this;
|
||||||
}
|
}
|
||||||
@ -657,80 +564,84 @@ public:
|
|||||||
{
|
{
|
||||||
return storage::copy(reinterpret_cast<const type&>(m_data));
|
return storage::copy(reinterpret_cast<const type&>(m_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename CT>
|
|
||||||
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator &=(const CT& right)
|
|
||||||
{
|
|
||||||
return m_data &= right, *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename CT>
|
|
||||||
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator |=(const CT& right)
|
|
||||||
{
|
|
||||||
return m_data |= right, *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename CT>
|
|
||||||
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator ^=(const CT& right)
|
|
||||||
{
|
|
||||||
return m_data ^= right, *this;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// se_t with native endianness (alias)
|
// se_t<> with native endianness
|
||||||
template<typename T, std::size_t Align = alignof(T)> using nse_t = se_t<T, false, Align>;
|
template <typename T, std::size_t Align = alignof(T)>
|
||||||
|
using nse_t = se_t<T, false, Align>;
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t Align, typename T1>
|
template <typename T, bool Se, std::size_t Align, typename T1>
|
||||||
inline se_t<T, Se, Align>& operator +=(se_t<T, Se, Align>& left, const T1& right)
|
inline se_t<T, Se, Align>& operator+=(se_t<T, Se, Align>& left, const T1& right)
|
||||||
{
|
{
|
||||||
auto value = left.value();
|
auto value = left.value();
|
||||||
return left = (value += right);
|
return left = (value += right);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t Align, typename T1>
|
template <typename T, bool Se, std::size_t Align, typename T1>
|
||||||
inline se_t<T, Se, Align>& operator -=(se_t<T, Se, Align>& left, const T1& right)
|
inline se_t<T, Se, Align>& operator-=(se_t<T, Se, Align>& left, const T1& right)
|
||||||
{
|
{
|
||||||
auto value = left.value();
|
auto value = left.value();
|
||||||
return left = (value -= right);
|
return left = (value -= right);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t Align, typename T1>
|
template <typename T, bool Se, std::size_t Align, typename T1>
|
||||||
inline se_t<T, Se, Align>& operator *=(se_t<T, Se, Align>& left, const T1& right)
|
inline se_t<T, Se, Align>& operator*=(se_t<T, Se, Align>& left, const T1& right)
|
||||||
{
|
{
|
||||||
auto value = left.value();
|
auto value = left.value();
|
||||||
return left = (value *= right);
|
return left = (value *= right);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t Align, typename T1>
|
template <typename T, bool Se, std::size_t Align, typename T1>
|
||||||
inline se_t<T, Se, Align>& operator /=(se_t<T, Se, Align>& left, const T1& right)
|
inline se_t<T, Se, Align>& operator/=(se_t<T, Se, Align>& left, const T1& right)
|
||||||
{
|
{
|
||||||
auto value = left.value();
|
auto value = left.value();
|
||||||
return left = (value /= right);
|
return left = (value /= right);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t Align, typename T1>
|
template <typename T, bool Se, std::size_t Align, typename T1>
|
||||||
inline se_t<T, Se, Align>& operator %=(se_t<T, Se, Align>& left, const T1& right)
|
inline se_t<T, Se, Align>& operator%=(se_t<T, Se, Align>& left, const T1& right)
|
||||||
{
|
{
|
||||||
auto value = left.value();
|
auto value = left.value();
|
||||||
return left = (value %= right);
|
return left = (value %= right);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t Align, typename T1>
|
template <typename T, bool Se, std::size_t Align, typename T1>
|
||||||
inline se_t<T, Se, Align>& operator <<=(se_t<T, Se, Align>& left, const T1& right)
|
inline se_t<T, Se, Align>& operator&=(se_t<T, Se, Align>& left, const T1& right)
|
||||||
|
{
|
||||||
|
auto value = left.value();
|
||||||
|
return left = (value &= right);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, bool Se, std::size_t Align, typename T1>
|
||||||
|
inline se_t<T, Se, Align>& operator|=(se_t<T, Se, Align>& left, const T1& right)
|
||||||
|
{
|
||||||
|
auto value = left.value();
|
||||||
|
return left = (value |= right);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, bool Se, std::size_t Align, typename T1>
|
||||||
|
inline se_t<T, Se, Align>& operator^=(se_t<T, Se, Align>& left, const T1& right)
|
||||||
|
{
|
||||||
|
auto value = left.value();
|
||||||
|
return left = (value ^= right);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, bool Se, std::size_t Align, typename T1>
|
||||||
|
inline se_t<T, Se, Align>& operator<<=(se_t<T, Se, Align>& left, const T1& right)
|
||||||
{
|
{
|
||||||
auto value = left.value();
|
auto value = left.value();
|
||||||
return left = (value <<= right);
|
return left = (value <<= right);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t Align, typename T1>
|
template <typename T, bool Se, std::size_t Align, typename T1>
|
||||||
inline se_t<T, Se, Align>& operator >>=(se_t<T, Se, Align>& left, const T1& right)
|
inline se_t<T, Se, Align>& operator>>=(se_t<T, Se, Align>& left, const T1& right)
|
||||||
{
|
{
|
||||||
auto value = left.value();
|
auto value = left.value();
|
||||||
return left = (value >>= right);
|
return left = (value >>= right);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t Align>
|
template <typename T, bool Se, std::size_t Align>
|
||||||
inline se_t<T, Se, Align> operator ++(se_t<T, Se, Align>& left, int)
|
inline se_t<T, Se, Align> operator++(se_t<T, Se, Align>& left, int)
|
||||||
{
|
{
|
||||||
auto value = left.value();
|
auto value = left.value();
|
||||||
auto result = value++;
|
auto result = value++;
|
||||||
@ -738,8 +649,8 @@ inline se_t<T, Se, Align> operator ++(se_t<T, Se, Align>& left, int)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t Align>
|
template <typename T, bool Se, std::size_t Align>
|
||||||
inline se_t<T, Se, Align> operator --(se_t<T, Se, Align>& left, int)
|
inline se_t<T, Se, Align> operator--(se_t<T, Se, Align>& left, int)
|
||||||
{
|
{
|
||||||
auto value = left.value();
|
auto value = left.value();
|
||||||
auto result = value--;
|
auto result = value--;
|
||||||
@ -747,148 +658,38 @@ inline se_t<T, Se, Align> operator --(se_t<T, Se, Align>& left, int)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t Align>
|
template <typename T, bool Se, std::size_t Align>
|
||||||
inline se_t<T, Se, Align>& operator ++(se_t<T, Se, Align>& right)
|
inline se_t<T, Se, Align>& operator++(se_t<T, Se, Align>& right)
|
||||||
{
|
{
|
||||||
auto value = right.value();
|
auto value = right.value();
|
||||||
return right = ++value;
|
return right = ++value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t Align>
|
template <typename T, bool Se, std::size_t Align>
|
||||||
inline se_t<T, Se, Align>& operator --(se_t<T, Se, Align>& right)
|
inline se_t<T, Se, Align>& operator--(se_t<T, Se, Align>& right)
|
||||||
{
|
{
|
||||||
auto value = right.value();
|
auto value = right.value();
|
||||||
return right = --value;
|
return right = --value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2), bool> operator ==(const se_t<T1>& left, const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return left.raw_data() == right.raw_data();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator ==(const se_t<T1>& left, T2 right)
|
|
||||||
{
|
|
||||||
return left.raw_data() == se_storage<T1>::to(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2), bool> operator ==(T1 left, const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return se_storage<T2>::to(left) == right.raw_data();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2), bool> operator !=(const se_t<T1>& left, const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return left.raw_data() != right.raw_data();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator !=(const se_t<T1>& left, T2 right)
|
|
||||||
{
|
|
||||||
return left.raw_data() != se_storage<T1>::to(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2), bool> operator !=(T1 left, const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return se_storage<T2>::to(left) != right.raw_data();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() & T2())>> operator &(const se_t<T1>& left, const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return{ left.raw_data() & right.raw_data(), se_raw };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() & T2())>> operator &(const se_t<T1>& left, T2 right)
|
|
||||||
{
|
|
||||||
return{ left.raw_data() & se_storage<T1>::to(right), se_raw };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() & T2())>> operator &(T1 left, const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return{ se_storage<T2>::to(left) & right.raw_data(), se_raw };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() | T2())>> operator |(const se_t<T1>& left, const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return{ left.raw_data() | right.raw_data(), se_raw };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() | T2())>> operator |(const se_t<T1>& left, T2 right)
|
|
||||||
{
|
|
||||||
return{ left.raw_data() | se_storage<T1>::to(right), se_raw };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() | T2())>> operator |(T1 left, const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return{ se_storage<T2>::to(left) | right.raw_data(), se_raw };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(const se_t<T1>& left, const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return{ left.raw_data() ^ right.raw_data(), se_raw };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(const se_t<T1>& left, T2 right)
|
|
||||||
{
|
|
||||||
return{ left.raw_data() ^ se_storage<T1>::to(right), se_raw };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(T1 left, const se_t<T2>& right)
|
|
||||||
{
|
|
||||||
return{ se_storage<T2>::to(left) ^ right.raw_data(), se_raw };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization
|
|
||||||
template<typename T>
|
|
||||||
inline std::enable_if_t<std::is_integral<T>::value && sizeof(T) >= 4, se_t<decltype(~T())>> operator ~(const se_t<T>& right)
|
|
||||||
{
|
|
||||||
return{ ~right.raw_data(), se_raw };
|
|
||||||
}
|
|
||||||
|
|
||||||
#if IS_LE_MACHINE == 1
|
#if IS_LE_MACHINE == 1
|
||||||
template<typename T, std::size_t Align = alignof(T)> using be_t = se_t<T, true, Align>;
|
template <typename T, std::size_t Align = alignof(T)>
|
||||||
template<typename T, std::size_t Align = alignof(T)> using le_t = se_t<T, false, Align>;
|
using be_t = se_t<T, true, Align>;
|
||||||
|
template <typename T, std::size_t Align = alignof(T)>
|
||||||
|
using le_t = se_t<T, false, Align>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type
|
// Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type
|
||||||
template<typename T, bool Se, typename = void>
|
template <typename T, bool Se, typename = void>
|
||||||
struct to_se
|
struct to_se
|
||||||
{
|
{
|
||||||
template<typename T2, typename = void>
|
template <typename T2, typename = void>
|
||||||
struct to_se_
|
struct to_se_
|
||||||
{
|
{
|
||||||
using type = T2;
|
using type = T2;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T2>
|
template <typename T2>
|
||||||
struct to_se_<T2, std::enable_if_t<std::is_arithmetic<T2>::value || std::is_enum<T2>::value>>
|
struct to_se_<T2, std::enable_if_t<std::is_arithmetic<T2>::value || std::is_enum<T2>::value>>
|
||||||
{
|
{
|
||||||
using type = se_t<T2, Se>;
|
using type = se_t<T2, Se>;
|
||||||
@ -898,34 +699,70 @@ struct to_se
|
|||||||
using type = typename to_se_<T>::type;
|
using type = typename to_se_<T>::type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<bool Se> struct to_se<v128, Se> { using type = se_t<v128, Se>; };
|
template <bool Se>
|
||||||
template<bool Se> struct to_se<bool, Se> { using type = bool; };
|
struct to_se<v128, Se>
|
||||||
template<bool Se> struct to_se<char, Se> { using type = char; };
|
{
|
||||||
template<bool Se> struct to_se<u8, Se> { using type = u8; };
|
using type = se_t<v128, Se>;
|
||||||
template<bool Se> struct to_se<s8, Se> { using type = s8; };
|
};
|
||||||
|
|
||||||
template<typename T, bool Se>
|
template <bool Se>
|
||||||
struct to_se<const T, Se, std::enable_if_t<!std::is_array<T>::value>>
|
struct to_se<u128, Se>
|
||||||
|
{
|
||||||
|
using type = se_t<u128, Se>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool Se>
|
||||||
|
struct to_se<s128, Se>
|
||||||
|
{
|
||||||
|
using type = se_t<s128, Se>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool Se>
|
||||||
|
struct to_se<bool, Se>
|
||||||
|
{
|
||||||
|
using type = bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool Se>
|
||||||
|
struct to_se<char, Se>
|
||||||
|
{
|
||||||
|
using type = char;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool Se>
|
||||||
|
struct to_se<u8, Se>
|
||||||
|
{
|
||||||
|
using type = u8;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool Se>
|
||||||
|
struct to_se<s8, Se>
|
||||||
|
{
|
||||||
|
using type = s8;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, bool Se>
|
||||||
|
struct to_se<const T, Se, std::enable_if_t<!std::is_array<T>::value>>
|
||||||
{
|
{
|
||||||
// Move const qualifier
|
// Move const qualifier
|
||||||
using type = const typename to_se<T, Se>::type;
|
using type = const typename to_se<T, Se>::type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, bool Se>
|
template <typename T, bool Se>
|
||||||
struct to_se<volatile T, Se, std::enable_if_t<!std::is_array<T>::value && !std::is_const<T>::value>>
|
struct to_se<volatile T, Se, std::enable_if_t<!std::is_array<T>::value && !std::is_const<T>::value>>
|
||||||
{
|
{
|
||||||
// Move volatile qualifier
|
// Move volatile qualifier
|
||||||
using type = volatile typename to_se<T, Se>::type;
|
using type = volatile typename to_se<T, Se>::type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, bool Se>
|
template <typename T, bool Se>
|
||||||
struct to_se<T[], Se>
|
struct to_se<T[], Se>
|
||||||
{
|
{
|
||||||
// Move array qualifier
|
// Move array qualifier
|
||||||
using type = typename to_se<T, Se>::type[];
|
using type = typename to_se<T, Se>::type[];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t N>
|
template <typename T, bool Se, std::size_t N>
|
||||||
struct to_se<T[N], Se>
|
struct to_se<T[N], Se>
|
||||||
{
|
{
|
||||||
// Move array qualifier
|
// Move array qualifier
|
||||||
@ -934,17 +771,21 @@ struct to_se<T[N], Se>
|
|||||||
|
|
||||||
// BE/LE aliases for to_se<>
|
// BE/LE aliases for to_se<>
|
||||||
#if IS_LE_MACHINE == 1
|
#if IS_LE_MACHINE == 1
|
||||||
template<typename T> using to_be_t = typename to_se<T, true>::type;
|
template <typename T>
|
||||||
template<typename T> using to_le_t = typename to_se<T, false>::type;
|
using to_be_t = typename to_se<T, true>::type;
|
||||||
|
template <typename T>
|
||||||
|
using to_le_t = typename to_se<T, false>::type;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// BE/LE aliases for atomic_t
|
// BE/LE aliases for atomic_t
|
||||||
#if IS_LE_MACHINE == 1
|
#if IS_LE_MACHINE == 1
|
||||||
template<typename T> using atomic_be_t = atomic_t<be_t<T>>;
|
template <typename T>
|
||||||
template<typename T> using atomic_le_t = atomic_t<le_t<T>>;
|
using atomic_be_t = atomic_t<be_t<T>>;
|
||||||
|
template <typename T>
|
||||||
|
using atomic_le_t = atomic_t<le_t<T>>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename T, bool Se, std::size_t Align>
|
template <typename T, bool Se, std::size_t Align>
|
||||||
struct fmt_unveil<se_t<T, Se, Align>, void>
|
struct fmt_unveil<se_t<T, Se, Align>, void>
|
||||||
{
|
{
|
||||||
using type = typename fmt_unveil<T>::type;
|
using type = typename fmt_unveil<T>::type;
|
||||||
@ -954,6 +795,3 @@ struct fmt_unveil<se_t<T, Se, Align>, void>
|
|||||||
return fmt_unveil<T>::get(arg);
|
return fmt_unveil<T>::get(arg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef IS_BINARY_COMPARABLE
|
|
||||||
#undef IS_INTEGER
|
|
||||||
|
@ -11,115 +11,109 @@ void fmt_class_string<const void*>::format(std::string& out, u64 arg)
|
|||||||
fmt::append(out, "%p", reinterpret_cast<const void*>(static_cast<std::uintptr_t>(arg)));
|
fmt::append(out, "%p", reinterpret_cast<const void*>(static_cast<std::uintptr_t>(arg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
|
||||||
void fmt_class_string<std::nullptr_t>::format(std::string& out, u64 arg)
|
|
||||||
{
|
|
||||||
fmt::append(out, "%p", reinterpret_cast<const void*>(static_cast<std::uintptr_t>(arg)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void fmt_class_string<const char*>::format(std::string& out, u64 arg)
|
void fmt_class_string<const char*>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
out += reinterpret_cast<const char*>(static_cast<std::uintptr_t>(arg));
|
out += reinterpret_cast<const char*>(static_cast<std::uintptr_t>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<std::string>::format(std::string& out, u64 arg)
|
void fmt_class_string<std::string>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
out += get_object(arg).c_str(); // TODO?
|
out += get_object(arg).c_str(); // TODO?
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<std::vector<char>>::format(std::string& out, u64 arg)
|
void fmt_class_string<std::vector<char>>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
const std::vector<char>& obj = get_object(arg);
|
const std::vector<char>& obj = get_object(arg);
|
||||||
out.append(obj.cbegin(), obj.cend());
|
out.append(obj.cbegin(), obj.cend());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<char>::format(std::string& out, u64 arg)
|
void fmt_class_string<char>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%#hhx", static_cast<char>(arg));
|
fmt::append(out, "%#hhx", static_cast<char>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<uchar>::format(std::string& out, u64 arg)
|
void fmt_class_string<uchar>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%#hhx", static_cast<uchar>(arg));
|
fmt::append(out, "%#hhx", static_cast<uchar>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<schar>::format(std::string& out, u64 arg)
|
void fmt_class_string<schar>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%#hhx", static_cast<schar>(arg));
|
fmt::append(out, "%#hhx", static_cast<schar>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<short>::format(std::string& out, u64 arg)
|
void fmt_class_string<short>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%#hx", static_cast<short>(arg));
|
fmt::append(out, "%#hx", static_cast<short>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<ushort>::format(std::string& out, u64 arg)
|
void fmt_class_string<ushort>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%#hx", static_cast<ushort>(arg));
|
fmt::append(out, "%#hx", static_cast<ushort>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<int>::format(std::string& out, u64 arg)
|
void fmt_class_string<int>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%#x", static_cast<int>(arg));
|
fmt::append(out, "%#x", static_cast<int>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<uint>::format(std::string& out, u64 arg)
|
void fmt_class_string<uint>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%#x", static_cast<uint>(arg));
|
fmt::append(out, "%#x", static_cast<uint>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<long>::format(std::string& out, u64 arg)
|
void fmt_class_string<long>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%#lx", static_cast<long>(arg));
|
fmt::append(out, "%#lx", static_cast<long>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<ulong>::format(std::string& out, u64 arg)
|
void fmt_class_string<ulong>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%#lx", static_cast<ulong>(arg));
|
fmt::append(out, "%#lx", static_cast<ulong>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<llong>::format(std::string& out, u64 arg)
|
void fmt_class_string<llong>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%#llx", static_cast<llong>(arg));
|
fmt::append(out, "%#llx", static_cast<llong>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<ullong>::format(std::string& out, u64 arg)
|
void fmt_class_string<ullong>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%#llx", static_cast<ullong>(arg));
|
fmt::append(out, "%#llx", static_cast<ullong>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<float>::format(std::string& out, u64 arg)
|
void fmt_class_string<float>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%gf", static_cast<float>(reinterpret_cast<f64&>(arg)));
|
fmt::append(out, "%gf", static_cast<float>(reinterpret_cast<f64&>(arg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<double>::format(std::string& out, u64 arg)
|
void fmt_class_string<double>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%g", reinterpret_cast<f64&>(arg));
|
fmt::append(out, "%g", reinterpret_cast<f64&>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<bool>::format(std::string& out, u64 arg)
|
void fmt_class_string<bool>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
out += arg ? "true" : "false";
|
out += arg ? "true" : "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
void fmt_class_string<v128>::format(std::string& out, u64 arg)
|
void fmt_class_string<v128>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
const v128& vec = get_object(arg);
|
const v128& vec = get_object(arg);
|
||||||
@ -130,21 +124,38 @@ namespace fmt
|
|||||||
{
|
{
|
||||||
void raw_error(const char* msg)
|
void raw_error(const char* msg)
|
||||||
{
|
{
|
||||||
std::string out;
|
std::string out{"Error"};
|
||||||
|
|
||||||
out += "Error: ";
|
out += ": ";
|
||||||
out += msg;
|
out += msg;
|
||||||
|
|
||||||
throw std::runtime_error(out);
|
throw std::runtime_error{out};
|
||||||
|
}
|
||||||
|
|
||||||
|
void raw_verify_error(const char* msg, uint position)
|
||||||
|
{
|
||||||
|
std::string out{"Verification failed"};
|
||||||
|
|
||||||
|
if (position)
|
||||||
|
{
|
||||||
|
out += " (+";
|
||||||
|
out += std::to_string(position);
|
||||||
|
out += ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
out += ": ";
|
||||||
|
out += msg;
|
||||||
|
|
||||||
|
throw std::runtime_error{out};
|
||||||
}
|
}
|
||||||
|
|
||||||
void raw_narrow_error(const char* msg, const fmt_type_info* sup, u64 arg)
|
void raw_narrow_error(const char* msg, const fmt_type_info* sup, u64 arg)
|
||||||
{
|
{
|
||||||
std::string out;
|
std::string out{"Narrow error"};
|
||||||
|
|
||||||
out += "Narrow error: (";
|
out += " (";
|
||||||
sup->fmt_string(out, arg); // Print value
|
sup->fmt_string(out, arg); // Print value
|
||||||
out += ")";
|
out += "): ";
|
||||||
|
|
||||||
if (msg)
|
if (msg)
|
||||||
{
|
{
|
||||||
@ -152,11 +163,11 @@ namespace fmt
|
|||||||
out += msg;
|
out += msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::range_error(out);
|
throw std::range_error{out};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hidden template
|
// Hidden template
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void raw_throw_exception(const char* fmt, const fmt_type_info* sup, const u64* args)
|
void raw_throw_exception(const char* fmt, const fmt_type_info* sup, const u64* args)
|
||||||
{
|
{
|
||||||
std::string out;
|
std::string out;
|
||||||
@ -193,7 +204,7 @@ struct fmt::cfmt_src
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T get(std::size_t index) const
|
T get(std::size_t index) const
|
||||||
{
|
{
|
||||||
return reinterpret_cast<const T&>(args[index]);
|
return reinterpret_cast<const T&>(args[index]);
|
||||||
@ -215,9 +226,9 @@ struct fmt::cfmt_src
|
|||||||
// Returns type size (0 if unknown, pointer, unsigned, assumed max)
|
// Returns type size (0 if unknown, pointer, unsigned, assumed max)
|
||||||
std::size_t type(std::size_t extra) const
|
std::size_t type(std::size_t extra) const
|
||||||
{
|
{
|
||||||
// Hack: use known function pointers to determine type
|
// Hack: use known function pointers to determine type
|
||||||
#define TYPE(type)\
|
#define TYPE(type) \
|
||||||
if (sup[extra].fmt_string == &fmt_class_string<type>::format) return sizeof(type);
|
if (sup[extra].fmt_string == &fmt_class_string<type>::format) return sizeof(type);
|
||||||
|
|
||||||
TYPE(int);
|
TYPE(int);
|
||||||
TYPE(llong);
|
TYPE(llong);
|
||||||
@ -249,7 +260,7 @@ std::string fmt::replace_first(const std::string& src, const std::string& from,
|
|||||||
return (pos ? src.substr(0, pos) + to : to) + std::string(src.c_str() + pos + from.length());
|
return (pos ? src.substr(0, pos) + to : to) + std::string(src.c_str() + pos + from.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string fmt::replace_all(const std::string &src, const std::string& from, const std::string& to)
|
std::string fmt::replace_all(const std::string& src, const std::string& from, const std::string& to)
|
||||||
{
|
{
|
||||||
std::string target = src;
|
std::string target = src;
|
||||||
for (auto pos = target.find(from); pos != std::string::npos; pos = target.find(from, pos + 1))
|
for (auto pos = target.find(from); pos != std::string::npos; pos = target.find(from, pos + 1))
|
||||||
@ -269,7 +280,7 @@ std::vector<std::string> fmt::split(const std::string& source, std::initializer_
|
|||||||
|
|
||||||
for (size_t cursor_end = 0; cursor_end < source.length(); ++cursor_end)
|
for (size_t cursor_end = 0; cursor_end < source.length(); ++cursor_end)
|
||||||
{
|
{
|
||||||
for (auto &separator : separators)
|
for (auto& separator : separators)
|
||||||
{
|
{
|
||||||
if (strncmp(source.c_str() + cursor_end, separator.c_str(), separator.length()) == 0)
|
if (strncmp(source.c_str() + cursor_end, separator.c_str(), separator.length()) == 0)
|
||||||
{
|
{
|
||||||
@ -278,7 +289,7 @@ std::vector<std::string> fmt::split(const std::string& source, std::initializer_
|
|||||||
result.push_back(candidate);
|
result.push_back(candidate);
|
||||||
|
|
||||||
cursor_begin = cursor_end + separator.length();
|
cursor_begin = cursor_end + separator.length();
|
||||||
cursor_end = cursor_begin - 1;
|
cursor_end = cursor_begin - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -297,7 +308,7 @@ std::string fmt::trim(const std::string& source, const std::string& values)
|
|||||||
std::size_t begin = source.find_first_not_of(values);
|
std::size_t begin = source.find_first_not_of(values);
|
||||||
|
|
||||||
if (begin == source.npos)
|
if (begin == source.npos)
|
||||||
return{};
|
return {};
|
||||||
|
|
||||||
return source.substr(begin, source.find_last_not_of(values) + 1);
|
return source.substr(begin, source.find_last_not_of(values) + 1);
|
||||||
}
|
}
|
||||||
@ -310,7 +321,7 @@ std::string fmt::to_upper(const std::string& string)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fmt::match(const std::string &source, const std::string &mask)
|
bool fmt::match(const std::string& source, const std::string& mask)
|
||||||
{
|
{
|
||||||
std::size_t source_position = 0, mask_position = 0;
|
std::size_t source_position = 0, mask_position = 0;
|
||||||
|
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
|
|
||||||
namespace fmt
|
namespace fmt
|
||||||
{
|
{
|
||||||
template<typename... Args>
|
template <typename... Args>
|
||||||
static std::string format(const char*, const Args&...);
|
static std::string format(const char*, const Args&...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename>
|
template <typename T, typename>
|
||||||
struct fmt_unveil
|
struct fmt_unveil
|
||||||
{
|
{
|
||||||
static_assert(sizeof(T) > 0, "fmt_unveil<>: cannot pass forward-declared object");
|
static_assert(sizeof(T) > 0, "fmt_unveil<>: cannot pass forward-declared object");
|
||||||
@ -43,7 +43,7 @@ struct fmt_unveil
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct fmt_unveil<T, std::enable_if_t<std::is_integral<T>::value && sizeof(T) <= 8 && alignof(T) <= 8>>
|
struct fmt_unveil<T, std::enable_if_t<std::is_integral<T>::value && sizeof(T) <= 8 && alignof(T) <= 8>>
|
||||||
{
|
{
|
||||||
using type = T;
|
using type = T;
|
||||||
@ -54,7 +54,7 @@ struct fmt_unveil<T, std::enable_if_t<std::is_integral<T>::value && sizeof(T) <=
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct fmt_unveil<T, std::enable_if_t<std::is_floating_point<T>::value && sizeof(T) <= 8 && alignof(T) <= 8>>
|
struct fmt_unveil<T, std::enable_if_t<std::is_floating_point<T>::value && sizeof(T) <= 8 && alignof(T) <= 8>>
|
||||||
{
|
{
|
||||||
using type = T;
|
using type = T;
|
||||||
@ -66,7 +66,7 @@ struct fmt_unveil<T, std::enable_if_t<std::is_floating_point<T>::value && sizeof
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct fmt_unveil<T, std::enable_if_t<std::is_enum<T>::value>>
|
struct fmt_unveil<T, std::enable_if_t<std::is_enum<T>::value>>
|
||||||
{
|
{
|
||||||
using type = T;
|
using type = T;
|
||||||
@ -77,7 +77,7 @@ struct fmt_unveil<T, std::enable_if_t<std::is_enum<T>::value>>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct fmt_unveil<T*, void>
|
struct fmt_unveil<T*, void>
|
||||||
{
|
{
|
||||||
using type = const T*;
|
using type = const T*;
|
||||||
@ -88,7 +88,7 @@ struct fmt_unveil<T*, void>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, std::size_t N>
|
template <typename T, std::size_t N>
|
||||||
struct fmt_unveil<T[N], void>
|
struct fmt_unveil<T[N], void>
|
||||||
{
|
{
|
||||||
using type = const T*;
|
using type = const T*;
|
||||||
@ -99,7 +99,7 @@ struct fmt_unveil<T[N], void>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
struct fmt_unveil<b8, void>
|
struct fmt_unveil<b8, void>
|
||||||
{
|
{
|
||||||
using type = bool;
|
using type = bool;
|
||||||
@ -111,7 +111,7 @@ struct fmt_unveil<b8, void>
|
|||||||
};
|
};
|
||||||
|
|
||||||
// String type format provider, also type classifier (format() called if an argument is formatted as "%s")
|
// String type format provider, also type classifier (format() called if an argument is formatted as "%s")
|
||||||
template<typename T, typename = void>
|
template <typename T, typename = void>
|
||||||
struct fmt_class_string
|
struct fmt_class_string
|
||||||
{
|
{
|
||||||
// Formatting function (must be explicitly specialized)
|
// Formatting function (must be explicitly specialized)
|
||||||
@ -127,7 +127,7 @@ struct fmt_class_string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function (safely converts arg to enum value)
|
// Helper function (safely converts arg to enum value)
|
||||||
static SAFE_BUFFERS FORCE_INLINE void format_enum(std::string& out, u64 arg, const char*(*get)(T value))
|
static SAFE_BUFFERS FORCE_INLINE void format_enum(std::string& out, u64 arg, const char* (*get)(T value))
|
||||||
{
|
{
|
||||||
const auto value = static_cast<std::underlying_type_t<T>>(arg);
|
const auto value = static_cast<std::underlying_type_t<T>>(arg);
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ struct fmt_class_string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function (bitset formatting)
|
// Helper function (bitset formatting)
|
||||||
static SAFE_BUFFERS FORCE_INLINE void format_bitset(std::string& out, u64 arg, const char* prefix, const char* delim, const char* suffix, void(*fmt)(std::string&, u64))
|
static SAFE_BUFFERS FORCE_INLINE void format_bitset(std::string& out, u64 arg, const char* prefix, const char* delim, const char* suffix, void (*fmt)(std::string&, u64))
|
||||||
{
|
{
|
||||||
// Start from raw value
|
// Start from raw value
|
||||||
fmt_class_string<u64>::format(out, arg);
|
fmt_class_string<u64>::format(out, arg);
|
||||||
@ -175,25 +175,25 @@ struct fmt_class_string
|
|||||||
static constexpr const char* unknown = nullptr;
|
static constexpr const char* unknown = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
struct fmt_class_string<const void*, void>
|
struct fmt_class_string<const void*, void>
|
||||||
{
|
{
|
||||||
static void format(std::string& out, u64 arg);
|
static void format(std::string& out, u64 arg);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct fmt_class_string<T*, void> : fmt_class_string<const void*, void>
|
struct fmt_class_string<T*, void> : fmt_class_string<const void*, void>
|
||||||
{
|
{
|
||||||
// Classify all pointers as const void*
|
// Classify all pointers as const void*
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
struct fmt_class_string<const char*, void>
|
struct fmt_class_string<const char*, void>
|
||||||
{
|
{
|
||||||
static void format(std::string& out, u64 arg);
|
static void format(std::string& out, u64 arg);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
struct fmt_class_string<char*, void> : fmt_class_string<const char*>
|
struct fmt_class_string<char*, void> : fmt_class_string<const char*>
|
||||||
{
|
{
|
||||||
// Classify char* as const char*
|
// Classify char* as const char*
|
||||||
@ -203,7 +203,7 @@ struct fmt_type_info
|
|||||||
{
|
{
|
||||||
decltype(&fmt_class_string<int>::format) fmt_string;
|
decltype(&fmt_class_string<int>::format) fmt_string;
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
static constexpr fmt_type_info make()
|
static constexpr fmt_type_info make()
|
||||||
{
|
{
|
||||||
return fmt_type_info
|
return fmt_type_info
|
||||||
@ -213,23 +213,20 @@ struct fmt_type_info
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Arg>
|
template <typename Arg>
|
||||||
using fmt_unveil_t = typename fmt_unveil<Arg>::type;
|
using fmt_unveil_t = typename fmt_unveil<Arg>::type;
|
||||||
|
|
||||||
// Argument array type (each element generated via fmt_unveil<>)
|
// Argument array type (each element generated via fmt_unveil<>)
|
||||||
template<typename... Args>
|
template <typename... Args>
|
||||||
using fmt_args_t = const u64(&&)[sizeof...(Args) + 1];
|
using fmt_args_t = const u64(&&)[sizeof...(Args) + 1];
|
||||||
|
|
||||||
namespace fmt
|
namespace fmt
|
||||||
{
|
{
|
||||||
template<typename... Args>
|
template <typename... Args>
|
||||||
const fmt_type_info* get_type_info()
|
SAFE_BUFFERS FORCE_INLINE const fmt_type_info* get_type_info()
|
||||||
{
|
{
|
||||||
// Constantly initialized null-terminated list of type-specific information
|
// Constantly initialized null-terminated list of type-specific information
|
||||||
static constexpr fmt_type_info result[sizeof...(Args) + 1]
|
static constexpr fmt_type_info result[sizeof...(Args) + 1]{fmt_type_info::make<Args>()...};
|
||||||
{
|
|
||||||
fmt_type_info::make<Args>()...
|
|
||||||
};
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -238,15 +235,15 @@ namespace fmt
|
|||||||
void raw_append(std::string& out, const char*, const fmt_type_info*, const u64*) noexcept;
|
void raw_append(std::string& out, const char*, const fmt_type_info*, const u64*) noexcept;
|
||||||
|
|
||||||
// Formatting function
|
// Formatting function
|
||||||
template<typename... Args>
|
template <typename... Args>
|
||||||
static SAFE_BUFFERS void append(std::string& out, const char* fmt, const Args&... args)
|
SAFE_BUFFERS FORCE_INLINE void append(std::string& out, const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
raw_append(out, fmt, fmt::get_type_info<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
raw_append(out, fmt, fmt::get_type_info<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formatting function
|
// Formatting function
|
||||||
template<typename... Args>
|
template <typename... Args>
|
||||||
static SAFE_BUFFERS std::string format(const char* fmt, const Args&... args)
|
SAFE_BUFFERS FORCE_INLINE std::string format(const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
append<Args...>(result, fmt, args...);
|
append<Args...>(result, fmt, args...);
|
||||||
@ -254,11 +251,11 @@ namespace fmt
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Internal exception message formatting template, must be explicitly specialized or instantiated in cpp to minimize code bloat
|
// Internal exception message formatting template, must be explicitly specialized or instantiated in cpp to minimize code bloat
|
||||||
template<typename T>
|
template <typename T>
|
||||||
[[noreturn]] void raw_throw_exception(const char*, const fmt_type_info*, const u64*);
|
[[noreturn]] void raw_throw_exception(const char*, const fmt_type_info*, const u64*);
|
||||||
|
|
||||||
// Throw exception with formatting
|
// Throw exception with formatting
|
||||||
template<typename T = std::runtime_error, typename... Args>
|
template <typename T = std::runtime_error, typename... Args>
|
||||||
[[noreturn]] SAFE_BUFFERS FORCE_INLINE void throw_exception(const char* fmt, const Args&... args)
|
[[noreturn]] SAFE_BUFFERS FORCE_INLINE void throw_exception(const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
raw_throw_exception<T>(fmt, fmt::get_type_info<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
raw_throw_exception<T>(fmt, fmt::get_type_info<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
// Copy null-terminated string from std::string to char array with truncation
|
// Copy null-terminated string from std::string to char array with truncation
|
||||||
template<std::size_t N>
|
template <std::size_t N>
|
||||||
inline void strcpy_trunc(char(&dst)[N], const std::string& src)
|
inline void strcpy_trunc(char (&dst)[N], const std::string& src)
|
||||||
{
|
{
|
||||||
const std::size_t count = src.size() >= N ? N - 1 : src.size();
|
const std::size_t count = src.size() >= N ? N - 1 : src.size();
|
||||||
std::memcpy(dst, src.c_str(), count);
|
std::memcpy(dst, src.c_str(), count);
|
||||||
@ -16,8 +16,8 @@ inline void strcpy_trunc(char(&dst)[N], const std::string& src)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy null-terminated string from char array to another char array with truncation
|
// Copy null-terminated string from char array to another char array with truncation
|
||||||
template<std::size_t N, std::size_t N2>
|
template <std::size_t N, std::size_t N2>
|
||||||
inline void strcpy_trunc(char(&dst)[N], const char(&src)[N2])
|
inline void strcpy_trunc(char (&dst)[N], const char (&src)[N2])
|
||||||
{
|
{
|
||||||
const std::size_t count = N2 >= N ? N - 1 : N2;
|
const std::size_t count = N2 >= N ? N - 1 : N2;
|
||||||
std::memcpy(dst, src, count);
|
std::memcpy(dst, src, count);
|
||||||
@ -27,10 +27,10 @@ inline void strcpy_trunc(char(&dst)[N], const char(&src)[N2])
|
|||||||
namespace fmt
|
namespace fmt
|
||||||
{
|
{
|
||||||
std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
|
std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
|
||||||
std::string replace_all(const std::string &src, const std::string& from, const std::string& to);
|
std::string replace_all(const std::string& src, const std::string& from, const std::string& to);
|
||||||
|
|
||||||
template<size_t list_size>
|
template <size_t list_size>
|
||||||
std::string replace_all(std::string src, const std::pair<std::string, std::string>(&list)[list_size])
|
std::string replace_all(std::string src, const std::pair<std::string, std::string> (&list)[list_size])
|
||||||
{
|
{
|
||||||
for (size_t pos = 0; pos < src.length(); ++pos)
|
for (size_t pos = 0; pos < src.length(); ++pos)
|
||||||
{
|
{
|
||||||
@ -53,8 +53,8 @@ namespace fmt
|
|||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t list_size>
|
template <size_t list_size>
|
||||||
std::string replace_all(std::string src, const std::pair<std::string, std::function<std::string()>>(&list)[list_size])
|
std::string replace_all(std::string src, const std::pair<std::string, std::function<std::string()>> (&list)[list_size])
|
||||||
{
|
{
|
||||||
for (size_t pos = 0; pos < src.length(); ++pos)
|
for (size_t pos = 0; pos < src.length(); ++pos)
|
||||||
{
|
{
|
||||||
@ -80,17 +80,17 @@ namespace fmt
|
|||||||
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true);
|
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true);
|
||||||
std::string trim(const std::string& source, const std::string& values = " \t");
|
std::string trim(const std::string& source, const std::string& values = " \t");
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
std::string merge(const T& source, const std::string& separator)
|
std::string merge(const T& source, const std::string& separator)
|
||||||
{
|
{
|
||||||
if (!source.size())
|
if (!source.size())
|
||||||
{
|
{
|
||||||
return{};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
auto it = source.begin();
|
auto it = source.begin();
|
||||||
auto end = source.end();
|
auto end = source.end();
|
||||||
for (--end; it != end; ++it)
|
for (--end; it != end; ++it)
|
||||||
{
|
{
|
||||||
@ -100,23 +100,23 @@ namespace fmt
|
|||||||
return result + source.back();
|
return result + source.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
std::string merge(std::initializer_list<T> sources, const std::string& separator)
|
std::string merge(std::initializer_list<T> sources, const std::string& separator)
|
||||||
{
|
{
|
||||||
if (!sources.size())
|
if (!sources.size())
|
||||||
{
|
{
|
||||||
return{};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string result;
|
std::string result;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
for (auto &v : sources)
|
for (auto& v : sources)
|
||||||
{
|
{
|
||||||
if (first)
|
if (first)
|
||||||
{
|
{
|
||||||
result = fmt::merge(v, separator);
|
result = fmt::merge(v, separator);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -129,5 +129,5 @@ namespace fmt
|
|||||||
|
|
||||||
std::string to_upper(const std::string& string);
|
std::string to_upper(const std::string& string);
|
||||||
|
|
||||||
bool match(const std::string &source, const std::string &mask);
|
bool match(const std::string& source, const std::string& mask);
|
||||||
}
|
}
|
||||||
|
@ -4,20 +4,20 @@
|
|||||||
#include <climits>
|
#include <climits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
using schar = signed char;
|
using schar = signed char;
|
||||||
using uchar = unsigned char;
|
using uchar = unsigned char;
|
||||||
using ushort = unsigned short;
|
using ushort = unsigned short;
|
||||||
using uint = unsigned int;
|
using uint = unsigned int;
|
||||||
using ulong = unsigned long;
|
using ulong = unsigned long;
|
||||||
using ullong = unsigned long long;
|
using ullong = unsigned long long;
|
||||||
using llong = long long;
|
using llong = long long;
|
||||||
|
|
||||||
using u8 = std::uint8_t;
|
using u8 = std::uint8_t;
|
||||||
using u16 = std::uint16_t;
|
using u16 = std::uint16_t;
|
||||||
using u32 = std::uint32_t;
|
using u32 = std::uint32_t;
|
||||||
using u64 = std::uint64_t;
|
using u64 = std::uint64_t;
|
||||||
|
|
||||||
using s8 = std::int8_t;
|
using s8 = std::int8_t;
|
||||||
using s16 = std::int16_t;
|
using s16 = std::int16_t;
|
||||||
using s32 = std::int32_t;
|
using s32 = std::int32_t;
|
||||||
using s64 = std::int64_t;
|
using s64 = std::int64_t;
|
||||||
@ -28,63 +28,63 @@ namespace gsl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Formatting helper, type-specific preprocessing for improving safety and functionality
|
// Formatting helper, type-specific preprocessing for improving safety and functionality
|
||||||
template<typename T, typename = void>
|
template <typename T, typename = void>
|
||||||
struct fmt_unveil;
|
struct fmt_unveil;
|
||||||
|
|
||||||
struct fmt_type_info;
|
struct fmt_type_info;
|
||||||
|
|
||||||
namespace fmt
|
namespace fmt
|
||||||
{
|
{
|
||||||
template<typename... Args>
|
template <typename... Args>
|
||||||
const fmt_type_info* get_type_info();
|
const fmt_type_info* get_type_info();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, std::size_t Align = alignof(T), std::size_t Size = sizeof(T)>
|
template <typename T, std::size_t Align = alignof(T), std::size_t Size = sizeof(T)>
|
||||||
struct se_storage;
|
struct se_storage;
|
||||||
|
|
||||||
template<typename T, bool Se = true, std::size_t Align = alignof(T)>
|
template <typename T, bool Se = true, std::size_t Align = alignof(T)>
|
||||||
class se_t;
|
class se_t;
|
||||||
|
|
||||||
template<typename T, std::size_t Size = sizeof(T)>
|
template <typename T, std::size_t Size = sizeof(T)>
|
||||||
struct atomic_storage;
|
struct atomic_storage;
|
||||||
|
|
||||||
template<typename T1, typename T2, typename = void>
|
template <typename T1, typename T2, typename = void>
|
||||||
struct atomic_add;
|
struct atomic_add;
|
||||||
|
|
||||||
template<typename T1, typename T2, typename = void>
|
template <typename T1, typename T2, typename = void>
|
||||||
struct atomic_sub;
|
struct atomic_sub;
|
||||||
|
|
||||||
template<typename T1, typename T2, typename = void>
|
template <typename T1, typename T2, typename = void>
|
||||||
struct atomic_and;
|
struct atomic_and;
|
||||||
|
|
||||||
template<typename T1, typename T2, typename = void>
|
template <typename T1, typename T2, typename = void>
|
||||||
struct atomic_or;
|
struct atomic_or;
|
||||||
|
|
||||||
template<typename T1, typename T2, typename = void>
|
template <typename T1, typename T2, typename = void>
|
||||||
struct atomic_xor;
|
struct atomic_xor;
|
||||||
|
|
||||||
template<typename T, typename = void>
|
template <typename T, typename = void>
|
||||||
struct atomic_pre_inc;
|
struct atomic_pre_inc;
|
||||||
|
|
||||||
template<typename T, typename = void>
|
template <typename T, typename = void>
|
||||||
struct atomic_post_inc;
|
struct atomic_post_inc;
|
||||||
|
|
||||||
template<typename T, typename = void>
|
template <typename T, typename = void>
|
||||||
struct atomic_pre_dec;
|
struct atomic_pre_dec;
|
||||||
|
|
||||||
template<typename T, typename = void>
|
template <typename T, typename = void>
|
||||||
struct atomic_post_dec;
|
struct atomic_post_dec;
|
||||||
|
|
||||||
template<typename T1, typename T2, typename = void>
|
template <typename T1, typename T2, typename = void>
|
||||||
struct atomic_test_and_set;
|
struct atomic_test_and_set;
|
||||||
|
|
||||||
template<typename T1, typename T2, typename = void>
|
template <typename T1, typename T2, typename = void>
|
||||||
struct atomic_test_and_reset;
|
struct atomic_test_and_reset;
|
||||||
|
|
||||||
template<typename T1, typename T2, typename = void>
|
template <typename T1, typename T2, typename = void>
|
||||||
struct atomic_test_and_complement;
|
struct atomic_test_and_complement;
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
class atomic_t;
|
class atomic_t;
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@ -92,30 +92,32 @@ using std::void_t;
|
|||||||
#else
|
#else
|
||||||
namespace void_details
|
namespace void_details
|
||||||
{
|
{
|
||||||
template<class... >
|
template <typename...>
|
||||||
struct make_void
|
struct make_void
|
||||||
{
|
{
|
||||||
using type = void;
|
using type = void;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class... T> using void_t = typename void_details::make_void<T...>::type;
|
template <typename... T>
|
||||||
|
using void_t = typename void_details::make_void<T...>::type;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Extract T::simple_type if available, remove cv qualifiers
|
// Extract T::simple_type if available, remove cv qualifiers
|
||||||
template<typename T, typename = void>
|
template <typename T, typename = void>
|
||||||
struct simple_type_helper
|
struct simple_type_helper
|
||||||
{
|
{
|
||||||
using type = typename std::remove_cv<T>::type;
|
using type = typename std::remove_cv<T>::type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct simple_type_helper<T, void_t<typename T::simple_type>>
|
struct simple_type_helper<T, void_t<typename T::simple_type>>
|
||||||
{
|
{
|
||||||
using type = typename T::simple_type;
|
using type = typename T::simple_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T> using simple_t = typename simple_type_helper<T>::type;
|
template <typename T>
|
||||||
|
using simple_t = typename simple_type_helper<T>::type;
|
||||||
|
|
||||||
// Bool type equivalent
|
// Bool type equivalent
|
||||||
class b8
|
class b8
|
||||||
@ -172,87 +174,87 @@ struct alignas(16) u128
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
friend u128 operator +(const u128& l, const u128& r)
|
friend u128 operator+(const u128& l, const u128& r)
|
||||||
{
|
{
|
||||||
u128 value;
|
u128 value;
|
||||||
_addcarry_u64(_addcarry_u64(0, r.lo, l.lo, &value.lo), r.hi, l.hi, &value.hi);
|
_addcarry_u64(_addcarry_u64(0, r.lo, l.lo, &value.lo), r.hi, l.hi, &value.hi);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend u128 operator +(const u128& l, u64 r)
|
friend u128 operator+(const u128& l, u64 r)
|
||||||
{
|
{
|
||||||
u128 value;
|
u128 value;
|
||||||
_addcarry_u64(_addcarry_u64(0, r, l.lo, &value.lo), l.hi, 0, &value.hi);
|
_addcarry_u64(_addcarry_u64(0, r, l.lo, &value.lo), l.hi, 0, &value.hi);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend u128 operator +(u64 l, const u128& r)
|
friend u128 operator+(u64 l, const u128& r)
|
||||||
{
|
{
|
||||||
u128 value;
|
u128 value;
|
||||||
_addcarry_u64(_addcarry_u64(0, r.lo, l, &value.lo), 0, r.hi, &value.hi);
|
_addcarry_u64(_addcarry_u64(0, r.lo, l, &value.lo), 0, r.hi, &value.hi);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend u128 operator -(const u128& l, const u128& r)
|
friend u128 operator-(const u128& l, const u128& r)
|
||||||
{
|
{
|
||||||
u128 value;
|
u128 value;
|
||||||
_subborrow_u64(_subborrow_u64(0, r.lo, l.lo, &value.lo), r.hi, l.hi, &value.hi);
|
_subborrow_u64(_subborrow_u64(0, r.lo, l.lo, &value.lo), r.hi, l.hi, &value.hi);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend u128 operator -(const u128& l, u64 r)
|
friend u128 operator-(const u128& l, u64 r)
|
||||||
{
|
{
|
||||||
u128 value;
|
u128 value;
|
||||||
_subborrow_u64(_subborrow_u64(0, r, l.lo, &value.lo), 0, l.hi, &value.hi);
|
_subborrow_u64(_subborrow_u64(0, r, l.lo, &value.lo), 0, l.hi, &value.hi);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend u128 operator -(u64 l, const u128& r)
|
friend u128 operator-(u64 l, const u128& r)
|
||||||
{
|
{
|
||||||
u128 value;
|
u128 value;
|
||||||
_subborrow_u64(_subborrow_u64(0, r.lo, l, &value.lo), r.hi, 0, &value.hi);
|
_subborrow_u64(_subborrow_u64(0, r.lo, l, &value.lo), r.hi, 0, &value.hi);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128 operator +() const
|
u128 operator+() const
|
||||||
{
|
{
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128 operator -() const
|
u128 operator-() const
|
||||||
{
|
{
|
||||||
u128 value;
|
u128 value;
|
||||||
_subborrow_u64(_subborrow_u64(0, lo, 0, &value.lo), hi, 0, &value.hi);
|
_subborrow_u64(_subborrow_u64(0, lo, 0, &value.lo), hi, 0, &value.hi);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128& operator ++()
|
u128& operator++()
|
||||||
{
|
{
|
||||||
_addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi);
|
_addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128 operator ++(int)
|
u128 operator++(int)
|
||||||
{
|
{
|
||||||
u128 value = *this;
|
u128 value = *this;
|
||||||
_addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi);
|
_addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128& operator --()
|
u128& operator--()
|
||||||
{
|
{
|
||||||
_subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi);
|
_subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128 operator --(int)
|
u128 operator--(int)
|
||||||
{
|
{
|
||||||
u128 value = *this;
|
u128 value = *this;
|
||||||
_subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi);
|
_subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128 operator ~() const
|
u128 operator~() const
|
||||||
{
|
{
|
||||||
u128 value;
|
u128 value;
|
||||||
value.lo = ~lo;
|
value.lo = ~lo;
|
||||||
@ -260,7 +262,7 @@ struct alignas(16) u128
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend u128 operator &(const u128& l, const u128& r)
|
friend u128 operator&(const u128& l, const u128& r)
|
||||||
{
|
{
|
||||||
u128 value;
|
u128 value;
|
||||||
value.lo = l.lo & r.lo;
|
value.lo = l.lo & r.lo;
|
||||||
@ -268,7 +270,7 @@ struct alignas(16) u128
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend u128 operator |(const u128& l, const u128& r)
|
friend u128 operator|(const u128& l, const u128& r)
|
||||||
{
|
{
|
||||||
u128 value;
|
u128 value;
|
||||||
value.lo = l.lo | r.lo;
|
value.lo = l.lo | r.lo;
|
||||||
@ -276,7 +278,7 @@ struct alignas(16) u128
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend u128 operator ^(const u128& l, const u128& r)
|
friend u128 operator^(const u128& l, const u128& r)
|
||||||
{
|
{
|
||||||
u128 value;
|
u128 value;
|
||||||
value.lo = l.lo ^ r.lo;
|
value.lo = l.lo ^ r.lo;
|
||||||
@ -284,33 +286,33 @@ struct alignas(16) u128
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128& operator +=(const u128& r)
|
u128& operator+=(const u128& r)
|
||||||
{
|
{
|
||||||
_addcarry_u64(_addcarry_u64(0, r.lo, lo, &lo), r.hi, hi, &hi);
|
_addcarry_u64(_addcarry_u64(0, r.lo, lo, &lo), r.hi, hi, &hi);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128& operator +=(uint64_t r)
|
u128& operator+=(uint64_t r)
|
||||||
{
|
{
|
||||||
_addcarry_u64(_addcarry_u64(0, r, lo, &lo), 0, hi, &hi);
|
_addcarry_u64(_addcarry_u64(0, r, lo, &lo), 0, hi, &hi);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128& operator &=(const u128& r)
|
u128& operator&=(const u128& r)
|
||||||
{
|
{
|
||||||
lo &= r.lo;
|
lo &= r.lo;
|
||||||
hi &= r.hi;
|
hi &= r.hi;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128& operator |=(const u128& r)
|
u128& operator|=(const u128& r)
|
||||||
{
|
{
|
||||||
lo |= r.lo;
|
lo |= r.lo;
|
||||||
hi |= r.hi;
|
hi |= r.hi;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128& operator ^=(const u128& r)
|
u128& operator^=(const u128& r)
|
||||||
{
|
{
|
||||||
lo ^= r.lo;
|
lo ^= r.lo;
|
||||||
hi ^= r.hi;
|
hi ^= r.hi;
|
||||||
@ -340,47 +342,8 @@ struct alignas(16) s128
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace std
|
static_assert(alignof(u128) == 16 && sizeof(u128) == 16, "Wrong u128 implementation");
|
||||||
{
|
static_assert(alignof(s128) == 16 && sizeof(s128) == 16, "Wrong s128 implementation");
|
||||||
/* Let's hack. */
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct is_integral<u128> : true_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct is_integral<s128> : true_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct make_unsigned<u128>
|
|
||||||
{
|
|
||||||
using type = u128;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct make_unsigned<s128>
|
|
||||||
{
|
|
||||||
using type = u128;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct make_signed<u128>
|
|
||||||
{
|
|
||||||
using type = s128;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct make_signed<s128>
|
|
||||||
{
|
|
||||||
using type = s128;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static_assert(std::is_arithmetic<u128>::value && std::is_integral<u128>::value && alignof(u128) == 16 && sizeof(u128) == 16, "Wrong u128 implementation");
|
|
||||||
static_assert(std::is_arithmetic<s128>::value && std::is_integral<s128>::value && alignof(s128) == 16 && sizeof(s128) == 16, "Wrong s128 implementation");
|
|
||||||
|
|
||||||
union alignas(2) f16
|
union alignas(2) f16
|
||||||
{
|
{
|
||||||
@ -396,9 +359,9 @@ union alignas(2) f16
|
|||||||
{
|
{
|
||||||
// See http://stackoverflow.com/a/26779139
|
// See http://stackoverflow.com/a/26779139
|
||||||
// The conversion doesn't handle NaN/Inf
|
// The conversion doesn't handle NaN/Inf
|
||||||
u32 raw = ((_u16 & 0x8000) << 16) | // Sign (just moved)
|
u32 raw = ((_u16 & 0x8000) << 16) | // Sign (just moved)
|
||||||
(((_u16 & 0x7c00) + 0x1C000) << 13) | // Exponent ( exp - 15 + 127)
|
(((_u16 & 0x7c00) + 0x1C000) << 13) | // Exponent ( exp - 15 + 127)
|
||||||
((_u16 & 0x03FF) << 13); // Mantissa
|
((_u16 & 0x03FF) << 13); // Mantissa
|
||||||
return (float&)raw;
|
return (float&)raw;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -408,13 +371,13 @@ using f64 = double;
|
|||||||
|
|
||||||
struct ignore
|
struct ignore
|
||||||
{
|
{
|
||||||
template<typename T>
|
template <typename T>
|
||||||
ignore(T)
|
ignore(T)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
|
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
|
||||||
constexpr T align(const T& value, std::uint64_t align)
|
constexpr T align(const T& value, std::uint64_t align)
|
||||||
{
|
{
|
||||||
return static_cast<T>((value + (align - 1)) & ~(align - 1));
|
return static_cast<T>((value + (align - 1)) & ~(align - 1));
|
||||||
@ -423,12 +386,74 @@ constexpr T align(const T& value, std::uint64_t align)
|
|||||||
namespace fmt
|
namespace fmt
|
||||||
{
|
{
|
||||||
[[noreturn]] void raw_error(const char* msg);
|
[[noreturn]] void raw_error(const char* msg);
|
||||||
|
[[noreturn]] void raw_verify_error(const char* msg, uint position);
|
||||||
[[noreturn]] void raw_narrow_error(const char* msg, const fmt_type_info* sup, u64 arg);
|
[[noreturn]] void raw_narrow_error(const char* msg, const fmt_type_info* sup, u64 arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct verify_func
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
bool operator()(T&& value) const
|
||||||
|
{
|
||||||
|
if (std::forward<T>(value))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <uint N>
|
||||||
|
struct verify_impl
|
||||||
|
{
|
||||||
|
const char* cause;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto operator,(T&& value) const
|
||||||
|
{
|
||||||
|
// Verification (can be safely disabled)
|
||||||
|
if (!verify_func()(std::forward<T>(value)))
|
||||||
|
{
|
||||||
|
fmt::raw_verify_error(cause, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
return verify_impl<N + 1>{cause};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verification helper, checks several conditions delimited with comma operator
|
||||||
|
inline auto verify(const char* cause)
|
||||||
|
{
|
||||||
|
return verify_impl<0>{cause};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verification helper (returns value or lvalue reference, may require to use verify_move instead)
|
||||||
|
template <typename F = verify_func, typename T>
|
||||||
|
inline T verify(T&& value, const char* cause, F&& func = F())
|
||||||
|
{
|
||||||
|
if (!func(std::forward<T>(value)))
|
||||||
|
{
|
||||||
|
fmt::raw_verify_error(cause, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::forward<T>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verification helper (must be used in return expression or in place of std::move)
|
||||||
|
template <typename F = verify_func, typename T>
|
||||||
|
inline std::remove_reference_t<T>&& verify_move(T&& value, const char* cause, F&& func = F())
|
||||||
|
{
|
||||||
|
if (!func(std::forward<T>(value)))
|
||||||
|
{
|
||||||
|
fmt::raw_verify_error(cause, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(value);
|
||||||
|
}
|
||||||
|
|
||||||
// Narrow cast (throws on failure)
|
// Narrow cast (throws on failure)
|
||||||
template<typename To = void, typename From, typename = decltype(static_cast<To>(std::declval<From>()))>
|
template <typename To = void, typename From, typename = decltype(static_cast<To>(std::declval<From>()))>
|
||||||
inline To narrow(const From& value, const char* msg = nullptr)
|
inline To narrow(const From& value, const char* msg = nullptr)
|
||||||
{
|
{
|
||||||
// Allow "narrowing to void" and ensure it always fails in this case
|
// Allow "narrowing to void" and ensure it always fails in this case
|
||||||
@ -443,32 +468,32 @@ inline To narrow(const From& value, const char* msg = nullptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns u32 size() for container
|
// Returns u32 size() for container
|
||||||
template<typename CT, typename = decltype(static_cast<u32>(std::declval<CT>().size()))>
|
template <typename CT, typename = decltype(static_cast<u32>(std::declval<CT>().size()))>
|
||||||
inline u32 size32(const CT& container, const char* msg = nullptr)
|
inline u32 size32(const CT& container, const char* msg = nullptr)
|
||||||
{
|
{
|
||||||
return narrow<u32>(container.size(), msg);
|
return narrow<u32>(container.size(), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns u32 size for an array
|
// Returns u32 size for an array
|
||||||
template<typename T, std::size_t Size>
|
template <typename T, std::size_t Size>
|
||||||
constexpr u32 size32(const T(&)[Size], const char* msg = nullptr)
|
constexpr u32 size32(const T (&)[Size], const char* msg = nullptr)
|
||||||
{
|
{
|
||||||
return static_cast<u32>(Size);
|
return static_cast<u32>(Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T1, typename = std::enable_if_t<std::is_integral<T1>::value>>
|
template <typename T1, typename = std::enable_if_t<std::is_integral<T1>::value>>
|
||||||
constexpr bool test(const T1& value)
|
constexpr bool test(const T1& value)
|
||||||
{
|
{
|
||||||
return value != 0;
|
return value != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T1, typename T2, typename = std::enable_if_t<std::is_integral<T1>::value && std::is_integral<T2>::value>>
|
template <typename T1, typename T2, typename = std::enable_if_t<std::is_integral<T1>::value && std::is_integral<T2>::value>>
|
||||||
constexpr bool test(const T1& lhs, const T2& rhs)
|
constexpr bool test(const T1& lhs, const T2& rhs)
|
||||||
{
|
{
|
||||||
return (lhs & rhs) != 0;
|
return (lhs & rhs) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename T2, typename = std::enable_if_t<std::is_integral<T>::value && std::is_integral<T2>::value>>
|
template <typename T, typename T2, typename = std::enable_if_t<std::is_integral<T>::value && std::is_integral<T2>::value>>
|
||||||
inline bool test_and_set(T& lhs, const T2& rhs)
|
inline bool test_and_set(T& lhs, const T2& rhs)
|
||||||
{
|
{
|
||||||
const bool result = (lhs & rhs) != 0;
|
const bool result = (lhs & rhs) != 0;
|
||||||
@ -476,7 +501,7 @@ inline bool test_and_set(T& lhs, const T2& rhs)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename T2, typename = std::enable_if_t<std::is_integral<T>::value && std::is_integral<T2>::value>>
|
template <typename T, typename T2, typename = std::enable_if_t<std::is_integral<T>::value && std::is_integral<T2>::value>>
|
||||||
inline bool test_and_reset(T& lhs, const T2& rhs)
|
inline bool test_and_reset(T& lhs, const T2& rhs)
|
||||||
{
|
{
|
||||||
const bool result = (lhs & rhs) != 0;
|
const bool result = (lhs & rhs) != 0;
|
||||||
@ -484,7 +509,7 @@ inline bool test_and_reset(T& lhs, const T2& rhs)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename T2, typename = std::enable_if_t<std::is_integral<T>::value && std::is_integral<T2>::value>>
|
template <typename T, typename T2, typename = std::enable_if_t<std::is_integral<T>::value && std::is_integral<T2>::value>>
|
||||||
inline bool test_and_complement(T& lhs, const T2& rhs)
|
inline bool test_and_complement(T& lhs, const T2& rhs)
|
||||||
{
|
{
|
||||||
const bool result = (lhs & rhs) != 0;
|
const bool result = (lhs & rhs) != 0;
|
||||||
@ -493,7 +518,7 @@ inline bool test_and_complement(T& lhs, const T2& rhs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Simplified hash algorithm for pointers. May be used in std::unordered_(map|set).
|
// Simplified hash algorithm for pointers. May be used in std::unordered_(map|set).
|
||||||
template<typename T, std::size_t Align = alignof(T)>
|
template <typename T, std::size_t Align = alignof(T)>
|
||||||
struct pointer_hash
|
struct pointer_hash
|
||||||
{
|
{
|
||||||
std::size_t operator()(T* ptr) const
|
std::size_t operator()(T* ptr) const
|
||||||
@ -502,7 +527,7 @@ struct pointer_hash
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, std::size_t Shift = 0>
|
template <typename T, std::size_t Shift = 0>
|
||||||
struct value_hash
|
struct value_hash
|
||||||
{
|
{
|
||||||
std::size_t operator()(T value) const
|
std::size_t operator()(T value) const
|
||||||
@ -513,26 +538,26 @@ struct value_hash
|
|||||||
|
|
||||||
// Contains value of any POD type with fixed size and alignment. TT<> is the type converter applied.
|
// Contains value of any POD type with fixed size and alignment. TT<> is the type converter applied.
|
||||||
// For example, `simple_t` may be used to remove endianness.
|
// For example, `simple_t` may be used to remove endianness.
|
||||||
template<template<typename> class TT, std::size_t S, std::size_t A = S>
|
template <template <typename> class TT, std::size_t S, std::size_t A = S>
|
||||||
struct alignas(A) any_pod
|
struct alignas(A) any_pod
|
||||||
{
|
{
|
||||||
std::aligned_storage_t<S, A> data;
|
std::aligned_storage_t<S, A> data;
|
||||||
|
|
||||||
any_pod() = default;
|
any_pod() = default;
|
||||||
|
|
||||||
template<typename T, typename T2 = TT<T>, typename = std::enable_if_t<std::is_pod<T2>::value && sizeof(T2) == S && alignof(T2) <= A>>
|
template <typename T, typename T2 = TT<T>, typename = std::enable_if_t<std::is_pod<T2>::value && sizeof(T2) == S && alignof(T2) <= A>>
|
||||||
any_pod(const T& value)
|
any_pod(const T& value)
|
||||||
{
|
{
|
||||||
reinterpret_cast<T2&>(data) = value;
|
reinterpret_cast<T2&>(data) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename T2 = TT<T>, typename = std::enable_if_t<std::is_pod<T2>::value && sizeof(T2) == S && alignof(T2) <= A>>
|
template <typename T, typename T2 = TT<T>, typename = std::enable_if_t<std::is_pod<T2>::value && sizeof(T2) == S && alignof(T2) <= A>>
|
||||||
T2& as()
|
T2& as()
|
||||||
{
|
{
|
||||||
return reinterpret_cast<T2&>(data);
|
return reinterpret_cast<T2&>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename T2 = TT<T>, typename = std::enable_if_t<std::is_pod<T2>::value && sizeof(T2) == S && alignof(T2) <= A>>
|
template <typename T, typename T2 = TT<T>, typename = std::enable_if_t<std::is_pod<T2>::value && sizeof(T2) == S && alignof(T2) <= A>>
|
||||||
const T2& as() const
|
const T2& as() const
|
||||||
{
|
{
|
||||||
return reinterpret_cast<const T2&>(data);
|
return reinterpret_cast<const T2&>(data);
|
||||||
@ -553,13 +578,13 @@ struct cmd64 : any64
|
|||||||
|
|
||||||
cmd64() = default;
|
cmd64() = default;
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
cmd64(const T& value)
|
cmd64(const T& value)
|
||||||
: any64(value)
|
: any64(value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T1, typename T2>
|
template <typename T1, typename T2>
|
||||||
cmd64(const T1& arg1, const T2& arg2)
|
cmd64(const T1& arg1, const T2& arg2)
|
||||||
: any64(pair_t{arg1, arg2})
|
: any64(pair_t{arg1, arg2})
|
||||||
{
|
{
|
||||||
@ -572,25 +597,25 @@ struct cmd64 : any64
|
|||||||
|
|
||||||
// TODO: compatibility with std::pair/std::tuple?
|
// TODO: compatibility with std::pair/std::tuple?
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
decltype(auto) arg1()
|
decltype(auto) arg1()
|
||||||
{
|
{
|
||||||
return as<pair_t>().arg1.as<T>();
|
return as<pair_t>().arg1.as<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
decltype(auto) arg1() const
|
decltype(auto) arg1() const
|
||||||
{
|
{
|
||||||
return as<const pair_t>().arg1.as<const T>();
|
return as<const pair_t>().arg1.as<const T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
decltype(auto) arg2()
|
decltype(auto) arg2()
|
||||||
{
|
{
|
||||||
return as<pair_t>().arg2.as<T>();
|
return as<pair_t>().arg2.as<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
decltype(auto) arg2() const
|
decltype(auto) arg2() const
|
||||||
{
|
{
|
||||||
return as<const pair_t>().arg2.as<const T>();
|
return as<const pair_t>().arg2.as<const T>();
|
||||||
@ -600,7 +625,7 @@ struct cmd64 : any64
|
|||||||
static_assert(sizeof(cmd64) == 8 && std::is_pod<cmd64>::value, "Incorrect cmd64 type");
|
static_assert(sizeof(cmd64) == 8 && std::is_pod<cmd64>::value, "Incorrect cmd64 type");
|
||||||
|
|
||||||
// Allows to define integer convertible to multiple types
|
// Allows to define integer convertible to multiple types
|
||||||
template<typename T, T Value, typename T1 = void, typename... Ts>
|
template <typename T, T Value, typename T1 = void, typename... Ts>
|
||||||
struct multicast : multicast<T, Value, Ts...>
|
struct multicast : multicast<T, Value, Ts...>
|
||||||
{
|
{
|
||||||
constexpr multicast() = default;
|
constexpr multicast() = default;
|
||||||
@ -613,11 +638,11 @@ struct multicast : multicast<T, Value, Ts...>
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Recursion terminator
|
// Recursion terminator
|
||||||
template<typename T, T Value>
|
template <typename T, T Value>
|
||||||
struct multicast<T, Value, void>
|
struct multicast<T, Value, void>
|
||||||
{
|
{
|
||||||
constexpr multicast() = default;
|
constexpr multicast() = default;
|
||||||
|
|
||||||
// Explicit conversion to base type
|
// Explicit conversion to base type
|
||||||
explicit constexpr operator T() const
|
explicit constexpr operator T() const
|
||||||
{
|
{
|
||||||
@ -626,23 +651,25 @@ struct multicast<T, Value, void>
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Tagged ID type
|
// Tagged ID type
|
||||||
template<typename T = void, typename ID = u32>
|
template <typename T = void, typename ID = u32>
|
||||||
class id_value
|
class id_value
|
||||||
{
|
{
|
||||||
// Initial value
|
// Initial value
|
||||||
mutable ID m_value{ static_cast<ID>(-1) };
|
mutable ID m_value{static_cast<ID>(-1)};
|
||||||
|
|
||||||
// Allow access for ID manager
|
// Allow access for ID manager
|
||||||
friend class idm;
|
friend class idm;
|
||||||
|
|
||||||
// Update ID
|
// Update ID
|
||||||
void operator =(const ID& value) const
|
void operator=(const ID& value) const
|
||||||
{
|
{
|
||||||
m_value = value;
|
m_value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr id_value() {}
|
constexpr id_value()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// Get the value
|
// Get the value
|
||||||
operator ID() const
|
operator ID() const
|
||||||
@ -651,7 +678,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename ID>
|
template <typename T, typename ID>
|
||||||
struct fmt_unveil<id_value<T, ID>>
|
struct fmt_unveil<id_value<T, ID>>
|
||||||
{
|
{
|
||||||
using type = typename fmt_unveil<ID>::type;
|
using type = typename fmt_unveil<ID>::type;
|
||||||
|
Loading…
Reference in New Issue
Block a user