150 lines
3.1 KiB
C++
150 lines
3.1 KiB
C++
#pragma once
|
|
|
|
#include <concepts>
|
|
#include <cstdint>
|
|
#include <type_traits>
|
|
|
|
namespace mp
|
|
{
|
|
|
|
//======================== DoubleWidthType =======================//
|
|
|
|
template <typename T>
|
|
struct DoubleWidth;
|
|
|
|
template <>
|
|
struct DoubleWidth<uint8_t>
|
|
{
|
|
using type = uint16_t;
|
|
};
|
|
|
|
template <>
|
|
struct DoubleWidth<uint16_t>
|
|
{
|
|
using type = uint32_t;
|
|
};
|
|
|
|
template <>
|
|
struct DoubleWidth<uint32_t>
|
|
{
|
|
using type = uint64_t;
|
|
};
|
|
|
|
#ifdef __SIZEOF_INT128__
|
|
template <>
|
|
struct DoubleWidth<uint64_t>
|
|
{
|
|
using type = __uint128_t;
|
|
};
|
|
#endif
|
|
|
|
template <typename T>
|
|
using DoubleWidthType = typename DoubleWidth<T>::type;
|
|
|
|
//======================== HalfWidthType =======================//
|
|
|
|
template <typename T>
|
|
struct HalfWidth;
|
|
|
|
template <>
|
|
struct HalfWidth<uint16_t>
|
|
{
|
|
using type = uint8_t;
|
|
};
|
|
|
|
template <>
|
|
struct HalfWidth<uint32_t>
|
|
{
|
|
using type = uint16_t;
|
|
};
|
|
|
|
template <>
|
|
struct HalfWidth<uint64_t>
|
|
{
|
|
using type = uint32_t;
|
|
};
|
|
|
|
template <typename T>
|
|
using HalfWidthType = typename HalfWidth<T>::type;
|
|
|
|
//======================== Concepts =======================//
|
|
|
|
template <typename T>
|
|
concept ElementSuitable = std::unsigned_integral<T>;
|
|
|
|
template <typename T, typename TElem = T::ElementType>
|
|
concept AnyInt = requires(T t, TElem a, size_t i) {
|
|
{ t[i] } -> std::convertible_to<TElem>;
|
|
{ t.set(i, a) };
|
|
{ t.try_set(i, a) } -> std::convertible_to<bool>;
|
|
{ t.get(i) } -> std::convertible_to<TElem>;
|
|
{ t.zero() };
|
|
{ t.size_elems() } -> std::convertible_to<size_t>;
|
|
{ T::MAX_BYTES } -> std::convertible_to<size_t>;
|
|
{ T::MAX_ELEMS } -> std::convertible_to<size_t>;
|
|
{ T::ELEMENT_BYTES } -> std::convertible_to<size_t>;
|
|
{ T::LAST_ELEM_MASK } -> std::convertible_to<TElem>;
|
|
};
|
|
|
|
//======================== Utils =======================//
|
|
|
|
#ifdef __SIZEOF_INT128__
|
|
using LongestElementSuitableType = uint64_t;
|
|
#else
|
|
using LongestElementSuitableType = HalfWidthType<size_t>;
|
|
#endif
|
|
|
|
template <AnyInt TA, AnyInt TB>
|
|
constexpr bool ElementTypesMatch = std::is_same_v<typename TA::ElementType, typename TB::ElementType>;
|
|
|
|
template <ElementSuitable TElem, size_t MaxBytes>
|
|
constexpr TElem calculate_last_elem_mask()
|
|
{
|
|
size_t last_elem_bytes = MaxBytes % sizeof(TElem);
|
|
TElem mask = 0;
|
|
|
|
if (last_elem_bytes == 0)
|
|
{
|
|
return ~mask;
|
|
}
|
|
|
|
for (size_t i = 0; i < last_elem_bytes; ++i)
|
|
{
|
|
mask <<= 8;
|
|
mask |= 0xFF;
|
|
}
|
|
return mask;
|
|
}
|
|
|
|
inline char hex_digit(uint8_t bits)
|
|
{
|
|
return bits > 9 ? 'a' + (bits - 10) : '0' + bits;
|
|
}
|
|
|
|
template <AnyInt T>
|
|
std::string to_hex_string(const T& number)
|
|
{
|
|
constexpr size_t ELEMENT_DIGITS = T::ELEMENT_BYTES * 2;
|
|
|
|
std::string str(number.size_elems() * ELEMENT_DIGITS, '-');
|
|
|
|
for (size_t elem = 0; elem < number.size_elems(); ++elem)
|
|
{
|
|
auto v = number[elem];
|
|
for (size_t digit = 0; digit < ELEMENT_DIGITS; ++digit)
|
|
{
|
|
str[str.size() - 1 - (elem * ELEMENT_DIGITS) - digit] = hex_digit((v >> (digit * 4)) & 0xF);
|
|
}
|
|
}
|
|
|
|
auto first = str.find_first_not_of('0');
|
|
if (first != std::string::npos)
|
|
{
|
|
return "0x" + str.substr(first);
|
|
}
|
|
|
|
return "0x0";
|
|
|
|
}
|
|
|
|
} |