#pragma once #include namespace Latte { class LATTEREG; }; template constexpr T bswap_impl(T i, std::index_sequence) { return ((((i >> (N * CHAR_BIT)) & (T)(uint8_t)(-1)) << ((sizeof(T) - 1 - N) * CHAR_BIT)) | ...); } template> constexpr T bswap(T i) { return (T)bswap_impl((U)i, std::make_index_sequence{}); } template constexpr T SwapEndian(T value) { if constexpr (boost::is_integral::value) { #ifdef _MSC_VER if constexpr (sizeof(T) == sizeof(uint32_t)) { return (T)_byteswap_ulong(value); } #endif return (T)bswap((std::make_unsigned_t)value); } else if constexpr (boost::is_floating_point::value) { if constexpr (sizeof(T) == sizeof(uint32_t)) { const auto tmp = bswap(*(uint32_t*)&value); return *(T*)&tmp; } if constexpr (sizeof(T) == sizeof(uint64_t)) { const auto tmp = bswap(*(uint64_t*)&value); return *(T*)&tmp; } } else if constexpr (boost::is_enum::value) { return (T)SwapEndian((std::underlying_type_t)value); } else if constexpr (boost::is_base_of::value) { const auto tmp = bswap(*(uint32_t*)&value); return *(T*)&tmp; } else { static_assert(boost::is_integral::value, "unsupported betype specialization!"); } return value; } #ifndef WIN32 //static_assert(false, "_BE and _LE need to be adjusted"); #endif // swap if native isn't big endian template constexpr T _BE(T value) { return SwapEndian(value); } // swap if native isn't little endian template constexpr T _LE(T value) { return value; } template class betype { public: constexpr betype() = default; // copy constexpr betype(T value) : m_value(SwapEndian(value)) {} constexpr betype(const betype& value) = default; // required for trivially_copyable //constexpr betype(const betype& value) // : m_value(value.m_value) {} template constexpr betype(const betype& value) : betype((T)value.value()) {} // assigns static betype from_bevalue(T value) { betype result; result.m_value = value; return result; } // returns LE value constexpr T value() const { return SwapEndian(m_value); } // returns BE value constexpr T bevalue() const { return m_value; } constexpr operator T() const { return value(); } betype& operator+=(const betype& v) { m_value = SwapEndian(T(value() + v.value())); return *this; } betype& operator-=(const betype& v) { m_value = SwapEndian(T(value() - v.value())); return *this; } betype& operator*=(const betype& v) { m_value = SwapEndian(T(value() * v.value())); return *this; } betype& operator/=(const betype& v) { m_value = SwapEndian(T(value() / v.value())); return *this; } betype& operator&=(const betype& v) requires (requires (T& x, const T& y) { x &= y; }) { m_value &= v.m_value; return *this; } betype& operator|=(const betype& v) requires (requires (T& x, const T& y) { x |= y; }) { m_value |= v.m_value; return *this; } betype& operator|(const betype& v) const requires (requires (T& x, const T& y) { x | y; }) { betype tmp(*this); tmp.m_value = tmp.m_value | v.m_value; return tmp; } betype operator|(const T& v) const requires (requires (T& x, const T& y) { x | y; }) { betype tmp(*this); tmp.m_value = tmp.m_value | SwapEndian(v); return tmp; } betype& operator^=(const betype& v) requires std::integral { m_value ^= v.m_value; return *this; } betype& operator>>=(std::size_t idx) requires std::integral { m_value = SwapEndian(T(value() >> idx)); return *this; } betype& operator<<=(std::size_t idx) requires std::integral { m_value = SwapEndian(T(value() << idx)); return *this; } betype operator~() const requires std::integral { return from_bevalue(T(~m_value)); } betype& operator++() requires std::integral { m_value = SwapEndian(T(value() + 1)); return *this; } betype& operator--() requires std::integral { m_value = SwapEndian(T(value() - 1)); return *this; } private: //T m_value{}; // before 1.26.2 T m_value; }; using uint64be = betype; using uint32be = betype; using uint16be = betype; using uint8be = betype; using sint64be = betype; using sint32be = betype; using sint16be = betype; using sint8be = betype; using float32be = betype; using float64be = betype; static_assert(sizeof(betype) == sizeof(uint64)); static_assert(sizeof(betype) == sizeof(uint32)); static_assert(sizeof(betype) == sizeof(uint16)); static_assert(sizeof(betype) == sizeof(uint8)); static_assert(sizeof(betype) == sizeof(float)); static_assert(sizeof(betype) == sizeof(double)); static_assert(std::is_trivially_copyable_v); static_assert(std::is_trivially_constructible_v); static_assert(std::is_copy_constructible_v); static_assert(std::is_move_constructible_v); static_assert(std::is_copy_assignable_v); static_assert(std::is_move_assignable_v);