cpp_mp/mp/utils.hpp
2025-12-04 10:03:30 +01:00

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