#pragma once #include #include "utils.hpp" #include "storage.hpp" namespace mp { template 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(*str - '0'); } number.set_negative(negative); } template class BasicInt { public: using ElementType = TElem; constexpr static size_t MAX_BYTES = MaxBytes; constexpr static size_t ELEMENT_BYTES = sizeof(TElem); constexpr static size_t MAX_ELEMS = calculate_max_elems(MAX_BYTES, ELEMENT_BYTES); constexpr static TElem LAST_ELEM_MASK = calculate_last_elem_mask(); BasicInt() = default; BasicInt(std::initializer_list init) { for (size_t i = 0; i < init.size(); ++i) { set(i, *(init.begin() + i)); } } BasicInt(const BasicInt& other) = default; BasicInt(BasicInt&& other) noexcept = default; BasicInt& operator=(const BasicInt& other) = default; BasicInt& operator=(BasicInt&& other) noexcept = default; template BasicInt(const T& other) { *this = other; } template BasicInt(T value) { *this = value; } BasicInt(const char* str) { *this = str; } template requires ElementTypesMatch 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 BasicInt& operator=(T value) { using UnsignedType = std::make_unsigned_t; UnsignedType uvalue; if (std::is_signed_v && value < 0) { uvalue = static_cast(-value); set_negative(true); } else { uvalue = static_cast(value); set_negative(false); } zero(); if constexpr (sizeof(UnsignedType) <= sizeof(TElem)) { set(0, static_cast(uvalue)); } else { constexpr UnsignedType ELEM_MASK = static_cast(std::numeric_limits::max()); size_t idx = 0; while (uvalue != 0) { set(idx, static_cast(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]; } const TElem& operator[](size_t index) const { return m_data[index]; } void resize(size_t new_size) { m_data.resize(new_size); } void zero() { m_data.clear(); } bool try_set(size_t idx, TElem value) { if (idx >= m_data.size()) { if (value == 0) { return true; } if (idx >= MAX_ELEMS) { return false; } m_data.resize(idx + 1); } m_data[idx] = value; if (idx == MAX_ELEMS - 1 && value > LAST_ELEM_MASK) { m_data[idx] &= LAST_ELEM_MASK; return false; } return true; } void set(size_t idx, TElem value) { if (!try_set(idx, value)) { throw std::out_of_range("Value exceeds maximum size"); } } TElem get(size_t idx) const { if (idx >= m_data.size()) { return TElem{0}; } return m_data[idx]; } void fix_leading_zeros() { size_t new_size = m_data.size(); while (new_size > 0 && m_data[new_size - 1] == TElem{0}) { new_size--; } m_data.resize(new_size); } //std::span data() { return m_data; } size_t size_elems() const { return m_data.size(); } bool negative() const { return m_negative; } void set_negative(bool neg) { m_negative = neg; } private: Container m_data; bool m_negative = false; }; template using Int = BasicInt; constexpr size_t UNLIMITED = std::numeric_limits::max(); using UnlimitedInt = BasicInt; } // namespace mp