Various stuff
This commit is contained in:
parent
707fb74250
commit
a7e07bb41d
114
main.cpp
114
main.cpp
@ -1,11 +1,7 @@
|
|||||||
#include <algorithm>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
//#include "mp.hpp"
|
#include "mp/mp.hpp"
|
||||||
#include "mp/int.hpp"
|
|
||||||
#include "mp/math.hpp"
|
|
||||||
#include "mp/lib.hpp"
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
static void PrintInt(const char* name, const T& val)
|
static void PrintInt(const char* name, const T& val)
|
||||||
@ -25,9 +21,18 @@ static void display_op(const char* desc, const MyInt& a, const MyInt& b, std::fu
|
|||||||
std::cout << "op: " << mp::to_string(a) << ' ' << desc << ' ' << mp::to_string(b) << " = " << mp::to_string(op(a, b)) << std::endl;
|
std::cout << "op: " << mp::to_string(a) << ' ' << desc << ' ' << mp::to_string(b) << " = " << mp::to_string(op(a, b)) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <char... Cs>
|
||||||
|
constexpr static auto operator""_mpi()
|
||||||
|
{
|
||||||
|
constexpr char str[] = {Cs..., '\0'};
|
||||||
|
return mp::from_string<128>(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
1000000_mpi;
|
||||||
|
|
||||||
// mp::Int a{0xDEADBEEFDEADF154, 0x0123456789ABCDEF, 0x1111222233334444};
|
// mp::Int a{0xDEADBEEFDEADF154, 0x0123456789ABCDEF, 0x1111222233334444};
|
||||||
mp::Int<32> a{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
|
mp::Int<32> a{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
|
||||||
mp::Int<1> b{0x55};
|
mp::Int<1> b{0x55};
|
||||||
@ -73,7 +78,7 @@ int main()
|
|||||||
std::cout << sizeof(mp::Int<150>) << std::endl;
|
std::cout << sizeof(mp::Int<150>) << std::endl;
|
||||||
std::cout << sizeof(mp::Int<160>) << std::endl;
|
std::cout << sizeof(mp::Int<160>) << std::endl;
|
||||||
|
|
||||||
|
// auto x = 12345678901234567890123456789012345678901234567890123456789012345678901234567890_mpi;
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// mp::Int<1024> acc{1};
|
// mp::Int<1024> acc{1};
|
||||||
@ -133,12 +138,10 @@ int main()
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
{
|
{
|
||||||
mp::Int<32> a;
|
mp::Int<32> a = "690000100000000000000000000000000000";
|
||||||
mp::Int<16> b;
|
mp::Int<16> b{"10690010000000000000000"};
|
||||||
mp::Int<32> c;
|
mp::Int<32> c;
|
||||||
|
|
||||||
mp::parse_string("690000100000000000000000000000000000", a);
|
|
||||||
mp::parse_string("10690010000000000000000", b);
|
|
||||||
c = a / b;
|
c = a / b;
|
||||||
PrintDec("a", a);
|
PrintDec("a", a);
|
||||||
PrintDec("b", b);
|
PrintDec("b", b);
|
||||||
@ -146,75 +149,20 @@ int main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
display_op("+",
|
display_op("+", 123456789012345678901234567890_mpi, 987654321098765432109876543210_mpi, std::plus<>{});
|
||||||
mp::from_string<32>("123456789012345678901234567890"),
|
display_op("+", 987654321098765432109876543210_mpi, -123456789012345678901234567890_mpi, std::plus<>{});
|
||||||
mp::from_string<32>("987654321098765432109876543210"),
|
display_op("+", "-123456789012345678901234567890", "-987654321098765432109876543210", std::plus<>{});
|
||||||
std::plus<>{});
|
display_op("+", "123456789012345678901234567890", "-987654321098765432109876543210", std::plus<>{});
|
||||||
|
display_op("-", "987654321098765432109876543210", "123456789012345678901234567890", std::minus<>{});
|
||||||
display_op("+",
|
display_op("-", "123456789012345678901234567890", "987654321098765432109876543210", std::minus<>{});
|
||||||
mp::from_string<32>("987654321098765432109876543210"),
|
display_op("-", "-123456789012345678901234567890", "-987654321098765432109876543210", std::minus<>{});
|
||||||
mp::from_string<32>("-123456789012345678901234567890"),
|
display_op("-", "987654321098765432109876543210", "-123456789012345678901234567890", std::minus<>{});
|
||||||
std::plus<>{});
|
display_op("*", "12345678901234567890", "98765432109876543210", std::multiplies<>{});
|
||||||
|
display_op("*", "-12345678901234567890", "98765432109876543210", std::multiplies<>{});
|
||||||
display_op("+",
|
display_op("*", "-12345678901234567890", "-98765432109876543210", std::multiplies<>{});
|
||||||
mp::from_string<32>("-123456789012345678901234567890"),
|
display_op("/", "1219326311370217952237463801111263526900", "12345678901234567890", std::divides<>{});
|
||||||
mp::from_string<32>("-987654321098765432109876543210"),
|
display_op("/", "-1219326311370217952237463801111263526900", "12345678901234567890", std::divides<>{});
|
||||||
std::plus<>{});
|
display_op("/", "-1219326311370217952237463801111263526900", "-12345678901234567890", std::divides<>{});
|
||||||
|
|
||||||
display_op("+",
|
|
||||||
mp::from_string<32>("123456789012345678901234567890"),
|
|
||||||
mp::from_string<32>("-987654321098765432109876543210"),
|
|
||||||
std::plus<>{});
|
|
||||||
|
|
||||||
display_op("-",
|
|
||||||
mp::from_string<32>("987654321098765432109876543210"),
|
|
||||||
mp::from_string<32>("123456789012345678901234567890"),
|
|
||||||
std::minus<>{});
|
|
||||||
|
|
||||||
display_op("-",
|
|
||||||
mp::from_string<32>("123456789012345678901234567890"),
|
|
||||||
mp::from_string<32>("987654321098765432109876543210"),
|
|
||||||
std::minus<>{});
|
|
||||||
|
|
||||||
display_op("-",
|
|
||||||
mp::from_string<32>("-123456789012345678901234567890"),
|
|
||||||
mp::from_string<32>("-987654321098765432109876543210"),
|
|
||||||
std::minus<>{});
|
|
||||||
|
|
||||||
display_op("-",
|
|
||||||
mp::from_string<32>("987654321098765432109876543210"),
|
|
||||||
mp::from_string<32>("-123456789012345678901234567890"),
|
|
||||||
std::minus<>{});
|
|
||||||
|
|
||||||
display_op("*",
|
|
||||||
mp::from_string<32>("12345678901234567890"),
|
|
||||||
mp::from_string<32>("98765432109876543210"),
|
|
||||||
std::multiplies<>{});
|
|
||||||
|
|
||||||
display_op("*",
|
|
||||||
mp::from_string<32>("-12345678901234567890"),
|
|
||||||
mp::from_string<32>("98765432109876543210"),
|
|
||||||
std::multiplies<>{});
|
|
||||||
|
|
||||||
display_op("*",
|
|
||||||
mp::from_string<32>("-12345678901234567890"),
|
|
||||||
mp::from_string<32>("-98765432109876543210"),
|
|
||||||
std::multiplies<>{});
|
|
||||||
|
|
||||||
display_op("/",
|
|
||||||
mp::from_string<32>("1219326311370217952237463801111263506900"),
|
|
||||||
mp::from_string<32>("12345678901234567890"),
|
|
||||||
std::divides<>{});
|
|
||||||
|
|
||||||
display_op("/",
|
|
||||||
mp::from_string<32>("-1219326311370217952237463801111263506900"),
|
|
||||||
mp::from_string<32>("12345678901234567890"),
|
|
||||||
std::divides<>{});
|
|
||||||
|
|
||||||
display_op("/",
|
|
||||||
mp::from_string<32>("-1219326311370217952237463801111263506900"),
|
|
||||||
mp::from_string<32>("-12345678901234567890"),
|
|
||||||
std::divides<>{});
|
|
||||||
|
|
||||||
auto a = mp::from_string<32>("12345678901234567890");
|
auto a = mp::from_string<32>("12345678901234567890");
|
||||||
auto b = mp::from_string<32>("98765432109876543210");
|
auto b = mp::from_string<32>("98765432109876543210");
|
||||||
@ -225,8 +173,12 @@ int main()
|
|||||||
b,
|
b,
|
||||||
std::multiplies<>{});
|
std::multiplies<>{});
|
||||||
|
|
||||||
|
for (mp::UnlimitedInt i = "10000000000000000000000000000000000000000000";
|
||||||
|
i > mp::UnlimitedInt("-20000000000000000000000000000000000000000000");
|
||||||
|
i -= mp::UnlimitedInt("1000000000000000000000000000000000000000000"))
|
||||||
|
{
|
||||||
|
PrintDec("i", i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
119
mp/int.hpp
119
mp/int.hpp
@ -1,11 +1,39 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include "storage.hpp"
|
#include "storage.hpp"
|
||||||
|
|
||||||
namespace mp
|
namespace mp
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template <AnyMpInt T>
|
||||||
|
inline void parse_string(const char* str, T& number)
|
||||||
|
{
|
||||||
|
number.zero();
|
||||||
|
|
||||||
|
bool negative = false;
|
||||||
|
|
||||||
|
if (*str == '-')
|
||||||
|
{
|
||||||
|
negative = true;
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; *str; ++str)
|
||||||
|
{
|
||||||
|
if (*str < '0' || *str > '9')
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Invalid character in input string");
|
||||||
|
}
|
||||||
|
|
||||||
|
number = number * 10U + static_cast<typename T::ElementType>(*str - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
number.set_negative(negative);
|
||||||
|
}
|
||||||
|
|
||||||
template <ElementSuitable TElem, size_t MaxBytes>
|
template <ElementSuitable TElem, size_t MaxBytes>
|
||||||
class BasicInt
|
class BasicInt
|
||||||
{
|
{
|
||||||
@ -13,7 +41,7 @@ class BasicInt
|
|||||||
using ElementType = TElem;
|
using ElementType = TElem;
|
||||||
constexpr static size_t MAX_BYTES = MaxBytes;
|
constexpr static size_t MAX_BYTES = MaxBytes;
|
||||||
constexpr static size_t ELEMENT_BYTES = sizeof(TElem);
|
constexpr static size_t ELEMENT_BYTES = sizeof(TElem);
|
||||||
constexpr static size_t MAX_ELEMS = (MAX_BYTES + ELEMENT_BYTES - 1) / ELEMENT_BYTES;
|
constexpr static size_t MAX_ELEMS = calculate_max_elems(MAX_BYTES, ELEMENT_BYTES);
|
||||||
constexpr static TElem LAST_ELEM_MASK = calculate_last_elem_mask<TElem, MAX_BYTES>();
|
constexpr static TElem LAST_ELEM_MASK = calculate_last_elem_mask<TElem, MAX_BYTES>();
|
||||||
|
|
||||||
BasicInt() = default;
|
BasicInt() = default;
|
||||||
@ -31,6 +59,92 @@ class BasicInt
|
|||||||
BasicInt& operator=(const BasicInt& other) = default;
|
BasicInt& operator=(const BasicInt& other) = default;
|
||||||
BasicInt& operator=(BasicInt&& other) noexcept = default;
|
BasicInt& operator=(BasicInt&& other) noexcept = default;
|
||||||
|
|
||||||
|
template <AnyMpInt T>
|
||||||
|
BasicInt(const T& other)
|
||||||
|
{
|
||||||
|
*this = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <AnyRegularInt T>
|
||||||
|
BasicInt(T value)
|
||||||
|
{
|
||||||
|
*this = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicInt(const char* str)
|
||||||
|
{
|
||||||
|
*this = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <AnyMpInt T>
|
||||||
|
requires ElementTypesMatch<T, BasicInt>
|
||||||
|
BasicInt& operator=(const T& other)
|
||||||
|
{
|
||||||
|
size_t other_size = other.size_elems();
|
||||||
|
for (size_t i = 0; i < other_size; ++i)
|
||||||
|
{
|
||||||
|
set(i, other.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size_elems() > other_size)
|
||||||
|
resize(other_size);
|
||||||
|
|
||||||
|
set_negative(other.negative());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <AnyRegularInt T>
|
||||||
|
BasicInt& operator=(T value)
|
||||||
|
{
|
||||||
|
using UnsignedType = std::make_unsigned_t<T>;
|
||||||
|
UnsignedType uvalue;
|
||||||
|
|
||||||
|
if (std::is_signed_v<T> && value < 0)
|
||||||
|
{
|
||||||
|
uvalue = static_cast<UnsignedType>(-value);
|
||||||
|
set_negative(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uvalue = static_cast<UnsignedType>(value);
|
||||||
|
set_negative(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
zero();
|
||||||
|
|
||||||
|
if constexpr (sizeof(UnsignedType) <= sizeof(TElem))
|
||||||
|
{
|
||||||
|
set(0, static_cast<TElem>(uvalue));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
constexpr UnsignedType ELEM_MASK = static_cast<UnsignedType>(std::numeric_limits<TElem>::max());
|
||||||
|
size_t idx = 0;
|
||||||
|
|
||||||
|
while (uvalue != 0)
|
||||||
|
{
|
||||||
|
set(idx, static_cast<TElem>(uvalue & ELEM_MASK));
|
||||||
|
uvalue >>= (sizeof(TElem) * 8);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicInt& operator=(const char* str)
|
||||||
|
{
|
||||||
|
parse_string(str, *this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicInt operator-() const
|
||||||
|
{
|
||||||
|
BasicInt res = *this;
|
||||||
|
res.set_negative(!res.negative());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
TElem& operator[](size_t index) { return m_data[index]; }
|
TElem& operator[](size_t index) { return m_data[index]; }
|
||||||
const TElem& operator[](size_t index) const { return m_data[index]; }
|
const TElem& operator[](size_t index) const { return m_data[index]; }
|
||||||
|
|
||||||
@ -112,4 +226,7 @@ class BasicInt
|
|||||||
template<size_t MaxBytes>
|
template<size_t MaxBytes>
|
||||||
using Int = BasicInt<LongestElementSuitableType, MaxBytes>;
|
using Int = BasicInt<LongestElementSuitableType, MaxBytes>;
|
||||||
|
|
||||||
|
constexpr size_t UNLIMITED = std::numeric_limits<size_t>::max();
|
||||||
|
using UnlimitedInt = BasicInt<LongestElementSuitableType, UNLIMITED>;
|
||||||
|
|
||||||
} // namespace mp
|
} // namespace mp
|
||||||
51
mp/lib.hpp
51
mp/lib.hpp
@ -15,7 +15,7 @@ inline char hex_digit(uint8_t bits)
|
|||||||
return bits > 9 ? 'a' + (bits - 10) : '0' + bits;
|
return bits > 9 ? 'a' + (bits - 10) : '0' + bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyConstMpInt T>
|
template <AnyMpInt T>
|
||||||
inline std::string to_hex_string(const T& number)
|
inline std::string to_hex_string(const T& number)
|
||||||
{
|
{
|
||||||
constexpr size_t ELEMENT_DIGITS = T::ELEMENT_BYTES * 2;
|
constexpr size_t ELEMENT_DIGITS = T::ELEMENT_BYTES * 2;
|
||||||
@ -59,7 +59,7 @@ inline typename T::ElementType div_mod(T& value, const typename T::ElementType d
|
|||||||
return remainder;
|
return remainder;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyConstMpInt T>
|
template <AnyMpInt T>
|
||||||
inline std::string to_string(const T& number)
|
inline std::string to_string(const T& number)
|
||||||
{
|
{
|
||||||
std::string str;
|
std::string str;
|
||||||
@ -76,33 +76,7 @@ inline std::string to_string(const T& number)
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyMpInt T>
|
template <AnyInt T>
|
||||||
inline void parse_string(const char* str, T& number)
|
|
||||||
{
|
|
||||||
number.zero();
|
|
||||||
|
|
||||||
bool negative = false;
|
|
||||||
|
|
||||||
if (*str == '-')
|
|
||||||
{
|
|
||||||
negative = true;
|
|
||||||
++str;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; *str; ++str)
|
|
||||||
{
|
|
||||||
if (*str < '0' || *str > '9')
|
|
||||||
{
|
|
||||||
throw std::invalid_argument("Invalid character in input string");
|
|
||||||
}
|
|
||||||
|
|
||||||
number = number * 10U + static_cast<typename T::ElementType>(*str - '0');
|
|
||||||
}
|
|
||||||
|
|
||||||
number.set_negative(negative);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <AnyConstInt T>
|
|
||||||
inline T from_string(const char* str)
|
inline T from_string(const char* str)
|
||||||
{
|
{
|
||||||
T number;
|
T number;
|
||||||
@ -118,8 +92,25 @@ inline Int<N> from_string(const char* str)
|
|||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <AnyInt T>
|
||||||
|
inline T factorial(const T& n)
|
||||||
|
{
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Factorial is not defined for negative numbers");
|
||||||
|
}
|
||||||
|
|
||||||
// template <AnyConstInt T>
|
T result = 1;
|
||||||
|
for (T i = 2; i <= n; ++i)
|
||||||
|
{
|
||||||
|
result *= i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// template <AnyInt T>
|
||||||
// inline T parse_string(const char* str)
|
// inline T parse_string(const char* str)
|
||||||
// {
|
// {
|
||||||
// T number;
|
// T number;
|
||||||
|
|||||||
147
mp/math.hpp
147
mp/math.hpp
@ -9,10 +9,10 @@ namespace mp
|
|||||||
template <size_t SizeA, size_t SizeB>
|
template <size_t SizeA, size_t SizeB>
|
||||||
constexpr size_t ResultMaxSize = std::max(SizeA, SizeB);
|
constexpr size_t ResultMaxSize = std::max(SizeA, SizeB);
|
||||||
|
|
||||||
template <AnyConstMpInt TL, AnyConstInt TR>
|
template <AnyMpInt TL, AnyInt TR>
|
||||||
struct OpResult;
|
struct OpResult;
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstMpInt TRhs>
|
template <AnyMpInt TLhs, AnyMpInt TRhs>
|
||||||
requires ElementTypesMatch<TLhs, TRhs>
|
requires ElementTypesMatch<TLhs, TRhs>
|
||||||
struct OpResult<TLhs, TRhs>
|
struct OpResult<TLhs, TRhs>
|
||||||
|
|
||||||
@ -20,17 +20,17 @@ struct OpResult<TLhs, TRhs>
|
|||||||
using type = BasicInt<typename TLhs::ElementType, ResultMaxSize<TLhs::MAX_BYTES, TRhs::MAX_BYTES>>;
|
using type = BasicInt<typename TLhs::ElementType, ResultMaxSize<TLhs::MAX_BYTES, TRhs::MAX_BYTES>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyRegularInt TRhs>
|
template <AnyMpInt TLhs, AnyRegularInt TRhs>
|
||||||
struct OpResult<TLhs, TRhs>
|
struct OpResult<TLhs, TRhs>
|
||||||
{
|
{
|
||||||
//using type = BasicInt<typename TLhs::ElementType, ResultMaxSize<TLhs::MAX_BYTES, sizeof(TRhs)>>;
|
//using type = BasicInt<typename TLhs::ElementType, ResultMaxSize<TLhs::MAX_BYTES, sizeof(TRhs)>>;
|
||||||
using type = TLhs; // keep the same size as TLhs when operating with regular ints
|
using type = TLhs; // keep the same size as TLhs when operating with regular ints
|
||||||
};
|
};
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstInt TRhs>
|
template <AnyMpInt TLhs, AnyInt TRhs>
|
||||||
using OpResultType = typename OpResult<TLhs, TRhs>::type;
|
using OpResultType = typename OpResult<TLhs, TRhs>::type;
|
||||||
|
|
||||||
template <AnyConstMpInt T>
|
template <AnyMpInt T>
|
||||||
class OverflowError : public std::runtime_error
|
class OverflowError : public std::runtime_error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -42,7 +42,7 @@ class OverflowError : public std::runtime_error
|
|||||||
T m_value;
|
T m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstInt TRhs>
|
template <AnyMpInt TLhs, AnyInt TRhs>
|
||||||
using OverflowErrorOf = OverflowError<OpResultType<TLhs, TRhs>>;
|
using OverflowErrorOf = OverflowError<OpResultType<TLhs, TRhs>>;
|
||||||
|
|
||||||
// Regular int to mp int
|
// Regular int to mp int
|
||||||
@ -50,84 +50,107 @@ template <ElementSuitable TElem, AnyRegularInt TR>
|
|||||||
BasicInt<TElem, sizeof(TR)> to_mp_int(TR value)
|
BasicInt<TElem, sizeof(TR)> to_mp_int(TR value)
|
||||||
{
|
{
|
||||||
BasicInt<TElem, sizeof(TR)> res;
|
BasicInt<TElem, sizeof(TR)> res;
|
||||||
if constexpr (sizeof(TR) <= sizeof(TElem))
|
res = value;
|
||||||
{
|
|
||||||
res.set(0, static_cast<TElem>(value));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
constexpr TR ELEM_MASK = static_cast<TR>(std::numeric_limits<TElem>::max());
|
|
||||||
size_t idx = 0;
|
|
||||||
while (value != 0)
|
|
||||||
{
|
|
||||||
res.set(idx, static_cast<TElem>(value & ELEM_MASK));
|
|
||||||
value >>= (sizeof(TElem) * 8);
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// no-op
|
// no-op
|
||||||
template <ElementSuitable TElem, AnyConstMpInt TR>
|
template <ElementSuitable TElem, AnyMpInt TR>
|
||||||
requires std::is_same_v<typename TR::ElementType, TElem>
|
requires std::is_same_v<typename TR::ElementType, TElem>
|
||||||
const TR& to_mp_int(const TR& value)
|
const TR& to_mp_int(const TR& value)
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstMpInt TRhs>
|
template <AnyMpInt TLhs, AnyMpInt TRhs>
|
||||||
requires ElementTypesMatch<TLhs, TRhs>
|
requires ElementTypesMatch<TLhs, TRhs>
|
||||||
auto operator<=>(const TLhs& lhs, const TRhs& rhs)
|
auto operator<=>(const TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
//auto size_comp = lhs.size_elems() <=> rhs.size_elems();
|
const bool lhs_neg = lhs.negative();
|
||||||
//if (size_comp != std::strong_ordering::equal)
|
const bool rhs_neg = rhs.negative();
|
||||||
//{
|
|
||||||
// return size_comp;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//for (size_t i = lhs.size_elems(); i-- > 0;)
|
std::strong_ordering res = std::strong_ordering::equal;
|
||||||
//{
|
bool nonzero = false;
|
||||||
// auto elem_comp = lhs.get(i) <=> rhs.get(i);
|
|
||||||
// if (elem_comp != std::strong_ordering::equal)
|
|
||||||
// {
|
|
||||||
// return elem_comp;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
size_t max_size = std::max(lhs.size_elems(), rhs.size_elems());
|
size_t max_size = std::max(lhs.size_elems(), rhs.size_elems());
|
||||||
for (size_t i = max_size; i-- > 0;)
|
for (size_t i = max_size; i-- > 0;)
|
||||||
{
|
{
|
||||||
auto elem_comp = lhs.get(i) <=> rhs.get(i);
|
auto l = lhs.get(i);
|
||||||
|
auto r = rhs.get(i);
|
||||||
|
|
||||||
|
auto elem_comp = l <=> r;
|
||||||
if (elem_comp != std::strong_ordering::equal)
|
if (elem_comp != std::strong_ordering::equal)
|
||||||
{
|
{
|
||||||
return elem_comp;
|
res = elem_comp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (l != 0)
|
||||||
|
nonzero = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::strong_ordering::equal;
|
// both zero => ignore sign
|
||||||
|
if (res == std::strong_ordering::equal && !nonzero)
|
||||||
|
{
|
||||||
|
return std::strong_ordering::equal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// different sign, non-zero
|
||||||
|
if (lhs_neg != rhs_neg)
|
||||||
|
{
|
||||||
|
return lhs_neg ? std::strong_ordering::less : std::strong_ordering::greater;
|
||||||
|
}
|
||||||
|
|
||||||
|
// flip for negative
|
||||||
|
if (lhs_neg)
|
||||||
|
{
|
||||||
|
res = (res == std::strong_ordering::less) ? std::strong_ordering::greater : std::strong_ordering::less;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyRegularInt TRhs>
|
template <AnyMpInt TLhs, AnyRegularInt TRhs>
|
||||||
auto operator<=>(const TLhs& lhs, TRhs rhs)
|
auto operator<=>(const TLhs& lhs, TRhs rhs)
|
||||||
{
|
{
|
||||||
return lhs <=> to_mp_int<typename TLhs::ElementType>(rhs);
|
return lhs <=> to_mp_int<typename TLhs::ElementType>(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstInt TRhs>
|
template <AnyMpInt TLhs, AnyInt TRhs>
|
||||||
bool operator==(const TLhs& lhs, const TRhs& rhs)
|
bool operator==(const TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
return (lhs <=> rhs) == std::strong_ordering::equal;
|
return (lhs <=> rhs) == std::strong_ordering::equal;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstInt TRhs>
|
template <AnyMpInt TLhs, AnyInt TRhs>
|
||||||
bool operator!=(const TLhs& lhs, const TRhs& rhs)
|
bool operator!=(const TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstMpInt TRhs, AnyMpInt TRes>
|
template <AnyMpInt TLhs, AnyMpInt TRhs>
|
||||||
|
requires ElementTypesMatch<TLhs, TRhs>
|
||||||
|
inline bool less_ignore_sign(const TLhs& lhs, const TRhs& rhs)
|
||||||
|
{
|
||||||
|
size_t max_size = std::max(lhs.size_elems(), rhs.size_elems());
|
||||||
|
|
||||||
|
for (size_t i = max_size; i-- > 0; )
|
||||||
|
{
|
||||||
|
auto l = lhs.get(i);
|
||||||
|
auto r = rhs.get(i);
|
||||||
|
|
||||||
|
if (l < r)
|
||||||
|
return true;
|
||||||
|
else if (l > r)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <AnyMpInt TLhs, AnyMpInt TRhs, AnyMpInt TRes>
|
||||||
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
||||||
inline void sub_ignore_underflow(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
inline void sub_ignore_underflow(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
||||||
{
|
{
|
||||||
@ -154,11 +177,11 @@ inline void sub_ignore_underflow(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstMpInt TRhs, AnyMpInt TRes>
|
template <AnyMpInt TLhs, AnyMpInt TRhs, AnyMpInt TRes>
|
||||||
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
||||||
inline void sub_ignore_sign(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
inline void sub_ignore_sign(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
||||||
{
|
{
|
||||||
if (lhs < rhs)
|
if (less_ignore_sign(lhs, rhs))
|
||||||
{
|
{
|
||||||
sub_ignore_underflow(rhs, lhs, res);
|
sub_ignore_underflow(rhs, lhs, res);
|
||||||
res.set_negative(true);
|
res.set_negative(true);
|
||||||
@ -170,7 +193,7 @@ inline void sub_ignore_sign(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstMpInt TRhs, AnyMpInt TRes>
|
template <AnyMpInt TLhs, AnyMpInt TRhs, AnyMpInt TRes>
|
||||||
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
||||||
inline void add_ignore_sign(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
inline void add_ignore_sign(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
||||||
{
|
{
|
||||||
@ -200,7 +223,7 @@ inline void add_ignore_sign(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
|||||||
|
|
||||||
struct Addition
|
struct Addition
|
||||||
{
|
{
|
||||||
template <AnyConstMpInt TLhs, AnyConstMpInt TRhs, AnyMpInt TRes>
|
template <AnyMpInt TLhs, AnyMpInt TRhs, AnyMpInt TRes>
|
||||||
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
||||||
static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
||||||
{
|
{
|
||||||
@ -227,7 +250,7 @@ struct Addition
|
|||||||
|
|
||||||
struct Subtraction
|
struct Subtraction
|
||||||
{
|
{
|
||||||
template <AnyConstMpInt TLhs, AnyConstMpInt TRhs, AnyMpInt TRes>
|
template <AnyMpInt TLhs, AnyMpInt TRhs, AnyMpInt TRes>
|
||||||
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
||||||
static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
||||||
{
|
{
|
||||||
@ -250,7 +273,7 @@ struct Subtraction
|
|||||||
add_ignore_sign(lhs, rhs, res);
|
add_ignore_sign(lhs, rhs, res);
|
||||||
res.set_negative(true);
|
res.set_negative(true);
|
||||||
}
|
}
|
||||||
else // if (!lhs_neg && rhs_neg)
|
else
|
||||||
{
|
{
|
||||||
// a - (-b) == a + b
|
// a - (-b) == a + b
|
||||||
add_ignore_sign(lhs, rhs, res);
|
add_ignore_sign(lhs, rhs, res);
|
||||||
@ -263,7 +286,7 @@ struct Subtraction
|
|||||||
|
|
||||||
struct Multiplication
|
struct Multiplication
|
||||||
{
|
{
|
||||||
template <AnyConstMpInt TLhs, AnyConstMpInt TRhs, AnyMpInt TRes>
|
template <AnyMpInt TLhs, AnyMpInt TRhs, AnyMpInt TRes>
|
||||||
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
||||||
static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
||||||
{
|
{
|
||||||
@ -302,7 +325,7 @@ struct Multiplication
|
|||||||
|
|
||||||
struct Division
|
struct Division
|
||||||
{
|
{
|
||||||
template <AnyConstMpInt TLhs, AnyConstMpInt TRhs, AnyMpInt TRes>
|
template <AnyMpInt TLhs, AnyMpInt TRhs, AnyMpInt TRes>
|
||||||
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
||||||
static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
||||||
{
|
{
|
||||||
@ -456,7 +479,7 @@ struct Division
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Binary operation
|
// Binary operation
|
||||||
template <typename TOp, AnyConstMpInt TLhs, AnyConstInt TRhs>
|
template <typename TOp, AnyMpInt TLhs, AnyInt TRhs>
|
||||||
OpResultType<TLhs, TRhs> binary_op(const TLhs& lhs, const TRhs& rhs)
|
OpResultType<TLhs, TRhs> binary_op(const TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
OpResultType<TLhs, TRhs> res{};
|
OpResultType<TLhs, TRhs> res{};
|
||||||
@ -474,7 +497,7 @@ OpResultType<TLhs, TRhs> binary_op(const TLhs& lhs, const TRhs& rhs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compound assignment binary operation
|
// Compound assignment binary operation
|
||||||
template <typename TOp, AnyMpInt TLhs, AnyConstInt TRhs>
|
template <typename TOp, AnyMpInt TLhs, AnyInt TRhs>
|
||||||
TLhs& ca_binary_op(TLhs& lhs, const TRhs& rhs)
|
TLhs& ca_binary_op(TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
TLhs res{};
|
TLhs res{};
|
||||||
@ -494,13 +517,13 @@ TLhs& ca_binary_op(TLhs& lhs, const TRhs& rhs)
|
|||||||
|
|
||||||
// Addition operators
|
// Addition operators
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstInt TRhs>
|
template <AnyMpInt TLhs, AnyInt TRhs>
|
||||||
OpResultType<TLhs, TRhs> operator+(const TLhs& lhs, const TRhs& rhs)
|
OpResultType<TLhs, TRhs> operator+(const TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
return binary_op<Addition>(lhs, rhs);
|
return binary_op<Addition>(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyMpInt TLhs, AnyConstInt TRhs>
|
template <AnyMpInt TLhs, AnyInt TRhs>
|
||||||
TLhs& operator+=(TLhs& lhs, const TRhs& rhs)
|
TLhs& operator+=(TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
return ca_binary_op<Addition>(lhs, rhs);
|
return ca_binary_op<Addition>(lhs, rhs);
|
||||||
@ -508,13 +531,13 @@ TLhs& operator+=(TLhs& lhs, const TRhs& rhs)
|
|||||||
|
|
||||||
// Subtraction operators
|
// Subtraction operators
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstInt TRhs>
|
template <AnyMpInt TLhs, AnyInt TRhs>
|
||||||
OpResultType<TLhs, TRhs> operator-(const TLhs& lhs, const TRhs& rhs)
|
OpResultType<TLhs, TRhs> operator-(const TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
return binary_op<Subtraction>(lhs, rhs);
|
return binary_op<Subtraction>(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyMpInt TLhs, AnyConstInt TRhs>
|
template <AnyMpInt TLhs, AnyInt TRhs>
|
||||||
TLhs& operator-=(TLhs& lhs, const TRhs& rhs)
|
TLhs& operator-=(TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
return ca_binary_op<Subtraction>(lhs, rhs);
|
return ca_binary_op<Subtraction>(lhs, rhs);
|
||||||
@ -522,13 +545,13 @@ TLhs& operator-=(TLhs& lhs, const TRhs& rhs)
|
|||||||
|
|
||||||
// Multiplication operators
|
// Multiplication operators
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstInt TRhs>
|
template <AnyMpInt TLhs, AnyInt TRhs>
|
||||||
OpResultType<TLhs, TRhs> operator*(const TLhs& lhs, const TRhs& rhs)
|
OpResultType<TLhs, TRhs> operator*(const TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
return binary_op<Multiplication>(lhs, rhs);
|
return binary_op<Multiplication>(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyMpInt TLhs, AnyConstInt TRhs>
|
template <AnyMpInt TLhs, AnyInt TRhs>
|
||||||
TLhs& operator*=(TLhs& lhs, const TRhs& rhs)
|
TLhs& operator*=(TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
return ca_binary_op<Multiplication>(lhs, rhs);
|
return ca_binary_op<Multiplication>(lhs, rhs);
|
||||||
@ -536,13 +559,13 @@ TLhs& operator*=(TLhs& lhs, const TRhs& rhs)
|
|||||||
|
|
||||||
// Division operators
|
// Division operators
|
||||||
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstInt TRhs>
|
template <AnyMpInt TLhs, AnyInt TRhs>
|
||||||
OpResultType<TLhs, TRhs> operator/(const TLhs& lhs, const TRhs& rhs)
|
OpResultType<TLhs, TRhs> operator/(const TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
return binary_op<Division>(lhs, rhs);
|
return binary_op<Division>(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <AnyMpInt TLhs, AnyConstInt TRhs>
|
template <AnyMpInt TLhs, AnyInt TRhs>
|
||||||
TLhs& operator/=(TLhs& lhs, const TRhs& rhs)
|
TLhs& operator/=(TLhs& lhs, const TRhs& rhs)
|
||||||
{
|
{
|
||||||
return ca_binary_op<Division>(lhs, rhs);
|
return ca_binary_op<Division>(lhs, rhs);
|
||||||
|
|||||||
5
mp/mp.hpp
Normal file
5
mp/mp.hpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "int.hpp"
|
||||||
|
#include "math.hpp"
|
||||||
|
#include "lib.hpp"
|
||||||
@ -65,6 +65,6 @@ constexpr size_t MAX_ARRAY_BYTES = 128;
|
|||||||
|
|
||||||
template <typename TElem, size_t MaxSize>
|
template <typename TElem, size_t MaxSize>
|
||||||
using Container =
|
using Container =
|
||||||
std::conditional_t<(sizeof(TElem) * MaxSize > MAX_ARRAY_BYTES), VectorContainer<TElem, MaxSize>, ArrayContainer<TElem, MaxSize>>;
|
std::conditional_t<(MaxSize > MAX_ARRAY_BYTES / sizeof(TElem)), VectorContainer<TElem, MaxSize>, ArrayContainer<TElem, MaxSize>>;
|
||||||
|
|
||||||
} // namespace mp
|
} // namespace mp
|
||||||
30
mp/utils.hpp
30
mp/utils.hpp
@ -78,10 +78,14 @@ template <typename T>
|
|||||||
concept ElementSuitable = std::unsigned_integral<T>;
|
concept ElementSuitable = std::unsigned_integral<T>;
|
||||||
|
|
||||||
template <typename T, typename TElem = T::ElementType>
|
template <typename T, typename TElem = T::ElementType>
|
||||||
concept AnyConstMpInt = requires(T t, TElem a, size_t i) {
|
concept AnyMpInt = requires(T t, TElem a, size_t i, bool b) {
|
||||||
{ t[i] } -> std::convertible_to<TElem>;
|
{ 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.get(i) } -> std::convertible_to<TElem>;
|
||||||
{ t.size_elems() } -> std::convertible_to<size_t>;
|
{ t.size_elems() } -> std::convertible_to<size_t>;
|
||||||
|
{ t.set_negative(b) };
|
||||||
{ t.negative() } -> std::convertible_to<bool>;
|
{ t.negative() } -> std::convertible_to<bool>;
|
||||||
{ T::MAX_BYTES } -> std::convertible_to<size_t>;
|
{ T::MAX_BYTES } -> std::convertible_to<size_t>;
|
||||||
{ T::MAX_ELEMS } -> std::convertible_to<size_t>;
|
{ T::MAX_ELEMS } -> std::convertible_to<size_t>;
|
||||||
@ -89,19 +93,11 @@ concept AnyConstMpInt = requires(T t, TElem a, size_t i) {
|
|||||||
{ T::LAST_ELEM_MASK } -> std::convertible_to<TElem>;
|
{ T::LAST_ELEM_MASK } -> std::convertible_to<TElem>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename TElem = T::ElementType>
|
template <typename T>
|
||||||
concept AnyMpInt = AnyConstMpInt<T> && requires(T t, TElem a, size_t i, bool b) {
|
concept AnyRegularInt = std::integral<T>;
|
||||||
{ t.set(i, a) };
|
|
||||||
{ t.try_set(i, a) } -> std::convertible_to<bool>;
|
|
||||||
{ t.set_negative(b) };
|
|
||||||
{ t.zero() };
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept AnyRegularInt = std::unsigned_integral<T>;
|
concept AnyInt = AnyRegularInt<T> || AnyMpInt<T>;
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept AnyConstInt = AnyRegularInt<T> || AnyConstMpInt<T>;
|
|
||||||
|
|
||||||
//======================== Utils =======================//
|
//======================== Utils =======================//
|
||||||
|
|
||||||
@ -111,9 +107,17 @@ using LongestElementSuitableType = uint64_t;
|
|||||||
using LongestElementSuitableType = HalfWidthType<size_t>;
|
using LongestElementSuitableType = HalfWidthType<size_t>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <AnyConstMpInt TA, AnyConstMpInt TB>
|
template <AnyMpInt TA, AnyMpInt TB>
|
||||||
constexpr bool ElementTypesMatch = std::is_same_v<typename TA::ElementType, typename TB::ElementType>;
|
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>
|
template <ElementSuitable TElem, size_t MaxBytes>
|
||||||
constexpr TElem calculate_last_elem_mask()
|
constexpr TElem calculate_last_elem_mask()
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user