#pragma once #include #include #include 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 __SIZEOF_INT128__ 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::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) { { t.set(i, a) }; { t.try_set(i, a) } -> std::convertible_to; { t.zero() }; }; template concept AnyRegularInt = std::unsigned_integral; template concept AnyConstInt = AnyRegularInt || AnyConstMpInt; //======================== Utils =======================// #ifdef __SIZEOF_INT128__ 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; } inline char hex_digit(uint8_t bits) { return bits > 9 ? 'a' + (bits - 10) : '0' + bits; } template 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"; } }