cpp_mp/mp/utils.hpp

130 lines
2.7 KiB
C++

#pragma once
#include <concepts>
#include <cstddef>
#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;
};
#if 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 AnyConstMpInt = requires(T t, TElem a, size_t i) {
{ t[i] } -> std::convertible_to<TElem>;
{ t.get(i) } -> std::convertible_to<TElem>;
{ 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>;
};
template <typename T, typename TElem = T::ElementType>
concept AnyMpInt = AnyConstMpInt<T> && requires(T t, TElem a, size_t i) {
{ t.set(i, a) };
{ t.try_set(i, a) } -> std::convertible_to<bool>;
{ t.zero() };
};
template <typename T>
concept AnyRegularInt = std::unsigned_integral<T>;
template <typename T>
concept AnyConstInt = AnyRegularInt<T> || AnyConstMpInt<T>;
//======================== Utils =======================//
#ifdef USE_UINT128
using LongestElementSuitableType = uint64_t;
#else
using LongestElementSuitableType = HalfWidthType<size_t>;
#endif
template <AnyConstMpInt TA, AnyConstMpInt 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;
}
}