140 lines
2.9 KiB
C++
140 lines
2.9 KiB
C++
#pragma once
|
|
|
|
#include <concepts>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <type_traits>
|
|
|
|
#ifdef __SIZEOF_INT128__
|
|
#define USE_UINT128
|
|
#endif
|
|
|
|
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 USE_UINT128
|
|
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 AnyMpInt = requires(T t, TElem a, size_t i, bool b) {
|
|
{ t[i] } -> std::convertible_to<TElem>;
|
|
{ t.zero() };
|
|
{ t.set(i, a) };
|
|
{ t.try_set(i, a) } -> std::convertible_to<bool>;
|
|
{ t.get(i) } -> std::convertible_to<TElem>;
|
|
{ t.size_elems() } -> std::convertible_to<size_t>;
|
|
{ t.set_negative(b) };
|
|
{ t.negative() } -> std::convertible_to<bool>;
|
|
{ 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>;
|
|
};
|
|
|
|
template <typename T>
|
|
concept AnyRegularInt = std::integral<T>;
|
|
|
|
template <typename T>
|
|
concept AnyInt = AnyRegularInt<T> || AnyMpInt<T>;
|
|
|
|
//======================== Utils =======================//
|
|
|
|
#ifdef USE_UINT128
|
|
using LongestElementSuitableType = uint64_t;
|
|
#else
|
|
using LongestElementSuitableType = HalfWidthType<size_t>;
|
|
#endif
|
|
|
|
template <AnyMpInt TA, AnyMpInt TB>
|
|
constexpr bool ElementTypesMatch = std::is_same_v<typename TA::ElementType, typename TB::ElementType>;
|
|
|
|
constexpr size_t calculate_max_elems(size_t max_bytes, size_t elem_bytes)
|
|
{
|
|
if (max_bytes % elem_bytes == 0)
|
|
return max_bytes / elem_bytes;
|
|
else
|
|
return (max_bytes / elem_bytes) + 1;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
} |