#pragma once #include #include #include #include #ifdef __SIZEOF_INT128__ #define USE_UINT128 #endif namespace mp { //======================== DoubleWidthType =======================// template struct DoubleWidth; template <> struct DoubleWidth { using type = uint16_t; }; template <> struct DoubleWidth { using type = uint32_t; }; template <> struct DoubleWidth { using type = uint64_t; }; #ifdef USE_UINT128 template <> struct DoubleWidth { using type = __uint128_t; }; #endif template using DoubleWidthType = typename DoubleWidth::type; //======================== HalfWidthType =======================// template struct HalfWidth; template <> struct HalfWidth { using type = uint8_t; }; template <> struct HalfWidth { using type = uint16_t; }; template <> struct HalfWidth { using type = uint32_t; }; template using HalfWidthType = typename HalfWidth::type; //======================== Concepts =======================// template concept ElementSuitable = std::unsigned_integral; template concept AnyConstMpInt = requires(T t, TElem a, size_t i) { { t[i] } -> std::convertible_to; { t.get(i) } -> std::convertible_to; { t.size_elems() } -> std::convertible_to; { t.negative() } -> std::convertible_to; { T::MAX_BYTES } -> std::convertible_to; { T::MAX_ELEMS } -> std::convertible_to; { T::ELEMENT_BYTES } -> std::convertible_to; { T::LAST_ELEM_MASK } -> std::convertible_to; }; template concept AnyMpInt = AnyConstMpInt && requires(T t, TElem a, size_t i, bool b) { { t.set(i, a) }; { t.try_set(i, a) } -> std::convertible_to; { t.set_negative(b) }; { t.zero() }; }; template concept AnyRegularInt = std::unsigned_integral; template concept AnyConstInt = AnyRegularInt || AnyConstMpInt; //======================== Utils =======================// #ifdef USE_UINT128 using LongestElementSuitableType = uint64_t; #else using LongestElementSuitableType = HalfWidthType; #endif template constexpr bool ElementTypesMatch = std::is_same_v; template 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; } }