/usr/include/boost/multiprecision
Edit: /usr/include/boost/multiprecision/cpp_int.hpp (97009B)
//////////////////3/////////////////////////////////////////////
// Copyright 2012 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_MP_CPP_INT_HPP
#define BOOST_MP_CPP_INT_HPP
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef BOOST_MP_USER_DEFINED_LITERALS
#include
#endif
namespace boost {
namespace multiprecision {
namespace backends {
using boost::enable_if;
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4307) // integral constant overflow (oveflow is in a branch not taken when it would overflow)
#pragma warning(disable : 4127) // conditional expression is constant
#pragma warning(disable : 4702) // Unreachable code (reachability depends on template params)
#endif
template >::type>
struct cpp_int_backend;
} // namespace backends
namespace detail {
template
struct is_byte_container > : public boost::false_type
{};
} // namespace detail
namespace backends {
template
struct cpp_int_base;
//
// Traits class determines the maximum and minimum precision values:
//
template
struct max_precision;
template
struct max_precision >
{
static const unsigned value = is_void::value ? static_unsigned_max::value
: (((MaxBits >= MinBits) && MaxBits) ? MaxBits : UINT_MAX);
};
template
struct min_precision;
template
struct min_precision >
{
static const unsigned value = (is_void::value ? static_unsigned_max::value : MinBits);
};
//
// Traits class determines whether the number of bits precision requested could fit in a native type,
// we call this a "trivial" cpp_int:
//
template
struct is_trivial_cpp_int
{
static const bool value = false;
};
template
struct is_trivial_cpp_int >
{
typedef cpp_int_backend self;
static const bool value = is_void::value && (max_precision::value <= (sizeof(double_limb_type) * CHAR_BIT) - (SignType == signed_packed ? 1 : 0));
};
template
struct is_trivial_cpp_int >
{
static const bool value = true;
};
} // namespace backends
//
// Traits class to determine whether a cpp_int_backend is signed or not:
//
template
struct is_unsigned_number >
: public mpl::bool_<(SignType == unsigned_magnitude) || (SignType == unsigned_packed)>
{};
namespace backends {
//
// Traits class determines whether T should be implicitly convertible to U, or
// whether the constructor should be made explicit. The latter happens if we
// are losing the sign, or have fewer digits precision in the target type:
//
template
struct is_implicit_cpp_int_conversion;
template
struct is_implicit_cpp_int_conversion, cpp_int_backend >
{
typedef cpp_int_backend t1;
typedef cpp_int_backend t2;
static const bool value =
(is_signed_number::value || !is_signed_number::value) && (max_precision::value <= max_precision::value);
};
//
// Traits class to determine whether operations on a cpp_int may throw:
//
template
struct is_non_throwing_cpp_int : public mpl::false_
{};
template
struct is_non_throwing_cpp_int > : public mpl::true_
{};
//
// Traits class, determines whether the cpp_int is fixed precision or not:
//
template
struct is_fixed_precision;
template
struct is_fixed_precision >
: public mpl::bool_ >::value != UINT_MAX>
{};
namespace detail {
inline BOOST_MP_CXX14_CONSTEXPR void verify_new_size(unsigned new_size, unsigned min_size, const mpl::int_&)
{
if (new_size < min_size)
BOOST_THROW_EXCEPTION(std::overflow_error("Unable to allocate sufficient storage for the value of the result: value overflows the maximum allowable magnitude."));
}
inline BOOST_MP_CXX14_CONSTEXPR void verify_new_size(unsigned /*new_size*/, unsigned /*min_size*/, const mpl::int_&) {}
template
inline BOOST_MP_CXX14_CONSTEXPR void verify_limb_mask(bool b, U limb, U mask, const mpl::int_&)
{
// When we mask out "limb" with "mask", do we loose bits? If so it's an overflow error:
if (b && (limb & ~mask))
BOOST_THROW_EXCEPTION(std::overflow_error("Overflow in cpp_int arithmetic: there is insufficient precision in the target type to hold all of the bits of the result."));
}
template
inline BOOST_MP_CXX14_CONSTEXPR void verify_limb_mask(bool /*b*/, U /*limb*/, U /*mask*/, const mpl::int_&) {}
} // namespace detail
//
// Now define the various data layouts that are possible as partial specializations of the base class,
// starting with the default arbitrary precision signed integer type:
//
template
struct cpp_int_base
: private boost::empty_value::type>
{
typedef typename detail::rebind::type allocator_type;
#ifdef BOOST_NO_CXX11_ALLOCATOR
typedef typename allocator_type::pointer limb_pointer;
typedef typename allocator_type::const_pointer const_limb_pointer;
#else
typedef typename std::allocator_traits::pointer limb_pointer;
typedef typename std::allocator_traits::const_pointer const_limb_pointer;
#endif
typedef mpl::int_ checked_type;
//
// Interface invariants:
//
BOOST_STATIC_ASSERT(!is_void::value);
private:
typedef boost::empty_value base_type;
struct limb_data
{
unsigned capacity;
limb_pointer data;
};
public:
BOOST_STATIC_CONSTANT(unsigned, limb_bits = sizeof(limb_type) * CHAR_BIT);
BOOST_STATIC_CONSTANT(limb_type, max_limb_value = ~static_cast(0u));
BOOST_STATIC_CONSTANT(limb_type, sign_bit_mask = static_cast(1u) << (limb_bits - 1));
BOOST_STATIC_CONSTANT(unsigned, internal_limb_count =
MinBits
? (MinBits / limb_bits + ((MinBits % limb_bits) ? 1 : 0))
: (sizeof(limb_data) / sizeof(limb_type)) > 1 ? (sizeof(limb_data) / sizeof(limb_type)) : 2);
private:
union data_type
{
limb_data ld;
limb_type la[internal_limb_count];
limb_type first;
double_limb_type double_first;
BOOST_CONSTEXPR data_type() BOOST_NOEXCEPT : first(0) {}
BOOST_CONSTEXPR data_type(limb_type i) BOOST_NOEXCEPT : first(i) {}
BOOST_CONSTEXPR data_type(signed_limb_type i) BOOST_NOEXCEPT : first(i < 0 ? static_cast(boost::multiprecision::detail::unsigned_abs(i)) : i) {}
#if BOOST_ENDIAN_LITTLE_BYTE
BOOST_CONSTEXPR data_type(double_limb_type i) BOOST_NOEXCEPT : double_first(i)
{}
BOOST_CONSTEXPR data_type(signed_double_limb_type i) BOOST_NOEXCEPT : double_first(i < 0 ? static_cast(boost::multiprecision::detail::unsigned_abs(i)) : i) {}
#endif
#if !defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) && !(defined(BOOST_MSVC) && (BOOST_MSVC < 1900))
BOOST_CONSTEXPR data_type(limb_type* limbs, unsigned len) BOOST_NOEXCEPT : ld{ len, limbs }
{}
#else
BOOST_CONSTEXPR data_type(limb_type* limbs, unsigned len) BOOST_NOEXCEPT
{
ld.capacity = len;
ld.data = limbs;
}
#endif
};
data_type m_data;
unsigned m_limbs;
bool m_sign, m_internal, m_alias;
public:
//
// Direct construction:
//
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(limb_type i) BOOST_NOEXCEPT
: m_data(i),
m_limbs(1),
m_sign(false),
m_internal(true),
m_alias(false) {}
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(signed_limb_type i) BOOST_NOEXCEPT
: m_data(i),
m_limbs(1),
m_sign(i < 0),
m_internal(true),
m_alias(false) {}
#if BOOST_ENDIAN_LITTLE_BYTE && !defined(BOOST_MP_TEST_NO_LE)
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(double_limb_type i) BOOST_NOEXCEPT
: m_data(i),
m_limbs(i > max_limb_value ? 2 : 1),
m_sign(false),
m_internal(true),
m_alias(false)
{}
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(signed_double_limb_type i) BOOST_NOEXCEPT
: m_data(i),
m_limbs(i < 0 ? (static_cast(boost::multiprecision::detail::unsigned_abs(i)) > static_cast(max_limb_value) ? 2 : 1) : (i > max_limb_value ? 2 : 1)),
m_sign(i < 0),
m_internal(true),
m_alias(false) {}
#endif
//
// Aliasing constructor aliases data:
//
struct scoped_shared_storage : private boost::empty_value
{
private:
limb_type* data;
unsigned capacity;
unsigned allocated;
bool is_alias;
allocator_type& allocator() BOOST_NOEXCEPT { return boost::empty_value::get(); }
public:
scoped_shared_storage(const allocator_type& a, unsigned len)
: boost::empty_value(boost::empty_init_t(), a), capacity(len), allocated(0), is_alias(false)
{
data = allocator().allocate(len);
}
scoped_shared_storage(limb_type* limbs, unsigned n) : data(limbs), capacity(n), allocated(0), is_alias(true) {}
~scoped_shared_storage()
{
if(!is_alias)
allocator().deallocate(data, capacity);
}
limb_type* allocate(unsigned n) BOOST_NOEXCEPT
{
limb_type* result = data + allocated;
allocated += n;
BOOST_ASSERT(allocated <= capacity);
return result;
}
void deallocate(unsigned n)
{
BOOST_ASSERT(n <= allocated);
allocated -= n;
}
};
explicit BOOST_CONSTEXPR cpp_int_base(limb_type* data, unsigned offset, unsigned len) BOOST_NOEXCEPT
: m_data(data + offset, len),
m_limbs(len),
m_sign(false),
m_internal(false),
m_alias(true) {}
// This next constructor is for constructing const objects from const limb_type*'s only.
// Unfortunately we appear to have no way to assert that within the language, and the const_cast
// is a side effect of that :(
explicit BOOST_CONSTEXPR cpp_int_base(const limb_type* data, unsigned offset, unsigned len) BOOST_NOEXCEPT
: m_data(const_cast(data) + offset, len),
m_limbs(len),
m_sign(false),
m_internal(false),
m_alias(true) {}
explicit BOOST_CONSTEXPR cpp_int_base(scoped_shared_storage& data, unsigned len) BOOST_NOEXCEPT
: m_data(data.allocate(len), len),
m_limbs(len),
m_sign(false),
m_internal(false),
m_alias(true) {}
//
// Helper functions for getting at our internal data, and manipulating storage:
//
BOOST_MP_FORCEINLINE allocator_type& allocator() BOOST_NOEXCEPT { return base_type::get(); }
BOOST_MP_FORCEINLINE const allocator_type& allocator() const BOOST_NOEXCEPT { return base_type::get(); }
BOOST_MP_FORCEINLINE unsigned size() const BOOST_NOEXCEPT { return m_limbs; }
BOOST_MP_FORCEINLINE limb_pointer limbs() BOOST_NOEXCEPT { return m_internal ? m_data.la : m_data.ld.data; }
BOOST_MP_FORCEINLINE const_limb_pointer limbs() const BOOST_NOEXCEPT { return m_internal ? m_data.la : m_data.ld.data; }
BOOST_MP_FORCEINLINE unsigned capacity() const BOOST_NOEXCEPT { return m_internal ? internal_limb_count : m_data.ld.capacity; }
BOOST_MP_FORCEINLINE bool sign() const BOOST_NOEXCEPT { return m_sign; }
void sign(bool b) BOOST_NOEXCEPT
{
m_sign = b;
// Check for zero value:
if (m_sign && (m_limbs == 1))
{
if (limbs()[0] == 0)
m_sign = false;
}
}
void resize(unsigned new_size, unsigned min_size)
{
static const unsigned max_limbs = MaxBits / (CHAR_BIT * sizeof(limb_type)) + ((MaxBits % (CHAR_BIT * sizeof(limb_type))) ? 1 : 0);
// We never resize beyond MaxSize:
if (new_size > max_limbs)
new_size = max_limbs;
detail::verify_new_size(new_size, min_size, checked_type());
// See if we have enough capacity already:
unsigned cap = capacity();
if (new_size > cap)
{
// We must not be an alias, memory allocation here defeats the whole point of aliasing:
BOOST_ASSERT(!m_alias);
// Allocate a new buffer and copy everything over:
cap = (std::min)((std::max)(cap * 4, new_size), max_limbs);
limb_pointer pl = allocator().allocate(cap);
std::memcpy(pl, limbs(), size() * sizeof(limbs()[0]));
if (!m_internal && !m_alias)
allocator().deallocate(limbs(), capacity());
else
m_internal = false;
m_limbs = new_size;
m_data.ld.capacity = cap;
m_data.ld.data = pl;
}
else
{
m_limbs = new_size;
}
}
BOOST_MP_FORCEINLINE void normalize() BOOST_NOEXCEPT
{
limb_pointer p = limbs();
while ((m_limbs - 1) && !p[m_limbs - 1])
--m_limbs;
}
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base() BOOST_NOEXCEPT : m_data(), m_limbs(1), m_sign(false), m_internal(true), m_alias(false){}
BOOST_MP_FORCEINLINE cpp_int_base(const cpp_int_base& o) : base_type(o), m_limbs(o.m_alias ? o.m_limbs : 0), m_sign(o.m_sign), m_internal(o.m_alias ? false : true), m_alias(o.m_alias)
{
if (m_alias)
{
m_data.ld = o.m_data.ld;
}
else
{
resize(o.size(), o.size());
std::memcpy(limbs(), o.limbs(), o.size() * sizeof(limbs()[0]));
}
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
cpp_int_base(cpp_int_base&& o)
: base_type(static_cast(o)), m_limbs(o.m_limbs), m_sign(o.m_sign), m_internal(o.m_internal), m_alias(o.m_alias)
{
if (m_internal)
{
std::memcpy(limbs(), o.limbs(), o.size() * sizeof(limbs()[0]));
}
else
{
m_data.ld = o.m_data.ld;
o.m_limbs = 0;
o.m_internal = true;
}
}
cpp_int_base& operator=(cpp_int_base&& o) BOOST_NOEXCEPT
{
if (!m_internal && !m_alias)
allocator().deallocate(m_data.ld.data, m_data.ld.capacity);
*static_cast(this) = static_cast(o);
m_limbs = o.m_limbs;
m_sign = o.m_sign;
m_internal = o.m_internal;
m_alias = o.m_alias;
if (m_internal)
{
std::memcpy(limbs(), o.limbs(), o.size() * sizeof(limbs()[0]));
}
else
{
m_data.ld = o.m_data.ld;
o.m_limbs = 0;
o.m_internal = true;
}
return *this;
}
#endif
BOOST_MP_FORCEINLINE ~cpp_int_base() BOOST_NOEXCEPT
{
if (!m_internal && !m_alias)
allocator().deallocate(limbs(), capacity());
}
void assign(const cpp_int_base& o)
{
if (this != &o)
{
static_cast(*this) = static_cast(o);
m_limbs = 0;
resize(o.size(), o.size());
std::memcpy(limbs(), o.limbs(), o.size() * sizeof(limbs()[0]));
m_sign = o.m_sign;
}
}
BOOST_MP_FORCEINLINE void negate() BOOST_NOEXCEPT
{
m_sign = !m_sign;
// Check for zero value:
if (m_sign && (m_limbs == 1))
{
if (limbs()[0] == 0)
m_sign = false;
}
}
BOOST_MP_FORCEINLINE bool isneg() const BOOST_NOEXCEPT
{
return m_sign;
}
BOOST_MP_FORCEINLINE void do_swap(cpp_int_base& o) BOOST_NOEXCEPT
{
std::swap(m_data, o.m_data);
std::swap(m_sign, o.m_sign);
std::swap(m_internal, o.m_internal);
std::swap(m_limbs, o.m_limbs);
}
protected:
template
void check_in_range(const A&) BOOST_NOEXCEPT {}
};
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
template
const unsigned cpp_int_base::limb_bits;
template
const limb_type cpp_int_base::max_limb_value;
template
const limb_type cpp_int_base::sign_bit_mask;
template
const unsigned cpp_int_base::internal_limb_count;
#endif
template
struct cpp_int_base
: private boost::empty_value::type>
{
//
// There is currently no support for unsigned arbitrary precision arithmetic, largely
// because it's not clear what subtraction should do:
//
BOOST_STATIC_ASSERT_MSG(((sizeof(Allocator) == 0) && !is_void::value), "There is curently no support for unsigned arbitrary precision integers.");
};
//
// Fixed precision (i.e. no allocator), signed-magnitude type with limb-usage count:
//
template
struct cpp_int_base
{
typedef limb_type* limb_pointer;
typedef const limb_type* const_limb_pointer;
typedef mpl::int_ checked_type;
struct scoped_shared_storage {};
//
// Interface invariants:
//
BOOST_STATIC_ASSERT_MSG(MinBits > sizeof(double_limb_type) * CHAR_BIT, "Template parameter MinBits is inconsistent with the parameter trivial - did you mistakingly try to override the trivial parameter?");
public:
BOOST_STATIC_CONSTANT(unsigned, limb_bits = sizeof(limb_type) * CHAR_BIT);
BOOST_STATIC_CONSTANT(limb_type, max_limb_value = ~static_cast(0u));
BOOST_STATIC_CONSTANT(limb_type, sign_bit_mask = static_cast(1u) << (limb_bits - 1));
BOOST_STATIC_CONSTANT(unsigned, internal_limb_count = MinBits / limb_bits + ((MinBits % limb_bits) ? 1 : 0));
BOOST_STATIC_CONSTANT(limb_type, upper_limb_mask = (MinBits % limb_bits) ? (limb_type(1) << (MinBits % limb_bits)) - 1 : (~limb_type(0)));
BOOST_STATIC_ASSERT_MSG(internal_limb_count >= 2, "A fixed precision integer type must have at least 2 limbs");
private:
union data_type
{
limb_type m_data[internal_limb_count];
limb_type m_first_limb;
double_limb_type m_double_first_limb;
BOOST_CONSTEXPR data_type()
#if defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) || defined(BOOST_NO_CXX14_CONSTEXPR)
: m_first_limb(0)
{}
#else
: m_data{0}
{}
#endif
BOOST_CONSTEXPR data_type(limb_type i)
#if defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) || defined(BOOST_NO_CXX14_CONSTEXPR)
: m_first_limb(i)
{}
#else
: m_data{i}
{}
#endif
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
BOOST_CONSTEXPR data_type(limb_type i, limb_type j) : m_data{i, j}
{}
#endif
BOOST_CONSTEXPR data_type(double_limb_type i) : m_double_first_limb(i)
{
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
if (BOOST_MP_IS_CONST_EVALUATED(m_double_first_limb))
{
data_type t(static_cast(i & max_limb_value), static_cast(i >> limb_bits));
*this = t;
}
#endif
}
#if defined(BOOST_MP_USER_DEFINED_LITERALS)
template
BOOST_CONSTEXPR data_type(literals::detail::value_pack) : m_data{VALUES...}
{}
#endif
} m_wrapper;
boost::uint16_t m_limbs;
bool m_sign;
public:
//
// Direct construction:
//
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(limb_type i) BOOST_NOEXCEPT
: m_wrapper(i),
m_limbs(1),
m_sign(false) {}
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(signed_limb_type i) BOOST_NOEXCEPT
: m_wrapper(limb_type(i < 0 ? static_cast(-static_cast(i)) : i)),
m_limbs(1),
m_sign(i < 0) {}
#if BOOST_ENDIAN_LITTLE_BYTE && !defined(BOOST_MP_TEST_NO_LE)
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(double_limb_type i) BOOST_NOEXCEPT
: m_wrapper(i),
m_limbs(i > max_limb_value ? 2 : 1),
m_sign(false)
{}
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(signed_double_limb_type i) BOOST_NOEXCEPT
: m_wrapper(double_limb_type(i < 0 ? static_cast(boost::multiprecision::detail::unsigned_abs(i)) : i)),
m_limbs(i < 0 ? (static_cast(boost::multiprecision::detail::unsigned_abs(i)) > max_limb_value ? 2 : 1) : (i > max_limb_value ? 2 : 1)),
m_sign(i < 0) {}
#endif
#if defined(BOOST_MP_USER_DEFINED_LITERALS)
template
BOOST_CONSTEXPR cpp_int_base(literals::detail::value_pack i)
: m_wrapper(i), m_limbs(sizeof...(VALUES)), m_sign(false)
{}
BOOST_CONSTEXPR cpp_int_base(literals::detail::value_pack<> i)
: m_wrapper(i), m_limbs(1), m_sign(false) {}
BOOST_CONSTEXPR cpp_int_base(const cpp_int_base& a, const literals::detail::negate_tag&)
: m_wrapper(a.m_wrapper), m_limbs(a.m_limbs), m_sign((a.m_limbs == 1) && (*a.limbs() == 0) ? false : !a.m_sign) {}
#endif
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
//
// These are deprecated in C++20 unless we make them explicit:
//
constexpr cpp_int_base& operator=(const cpp_int_base&) = default;
#endif
//
// Helper functions for getting at our internal data, and manipulating storage:
//
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR unsigned size() const BOOST_NOEXCEPT { return m_limbs; }
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR limb_pointer limbs() BOOST_NOEXCEPT { return m_wrapper.m_data; }
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const_limb_pointer limbs() const BOOST_NOEXCEPT { return m_wrapper.m_data; }
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool sign() const BOOST_NOEXCEPT { return m_sign; }
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void sign(bool b) BOOST_NOEXCEPT
{
m_sign = b;
// Check for zero value:
if (m_sign && (m_limbs == 1))
{
if (limbs()[0] == 0)
m_sign = false;
}
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void resize(unsigned new_size, unsigned min_size) BOOST_MP_NOEXCEPT_IF((Checked == unchecked))
{
m_limbs = static_cast((std::min)(new_size, internal_limb_count));
detail::verify_new_size(m_limbs, min_size, checked_type());
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void normalize() BOOST_MP_NOEXCEPT_IF((Checked == unchecked))
{
limb_pointer p = limbs();
detail::verify_limb_mask(m_limbs == internal_limb_count, p[internal_limb_count - 1], upper_limb_mask, checked_type());
p[internal_limb_count - 1] &= upper_limb_mask;
while ((m_limbs - 1) && !p[m_limbs - 1])
--m_limbs;
if ((m_limbs == 1) && (!*p))
m_sign = false; // zero is always unsigned
}
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base() BOOST_NOEXCEPT : m_wrapper(limb_type(0u)), m_limbs(1), m_sign(false) {}
// Not defaulted, it breaks constexpr support in the Intel compiler for some reason:
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(const cpp_int_base& o) BOOST_NOEXCEPT
: m_wrapper(o.m_wrapper),
m_limbs(o.m_limbs),
m_sign(o.m_sign) {}
// Defaulted functions:
//~cpp_int_base() BOOST_NOEXCEPT {}
void BOOST_MP_CXX14_CONSTEXPR assign(const cpp_int_base& o) BOOST_NOEXCEPT
{
if (this != &o)
{
m_limbs = o.m_limbs;
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
if (BOOST_MP_IS_CONST_EVALUATED(m_limbs))
{
for (unsigned i = 0; i < m_limbs; ++i)
limbs()[i] = o.limbs()[i];
}
else
#endif
std::memcpy(limbs(), o.limbs(), o.size() * sizeof(o.limbs()[0]));
m_sign = o.m_sign;
}
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void negate() BOOST_NOEXCEPT
{
m_sign = !m_sign;
// Check for zero value:
if (m_sign && (m_limbs == 1))
{
if (limbs()[0] == 0)
m_sign = false;
}
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool isneg() const BOOST_NOEXCEPT
{
return m_sign;
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void do_swap(cpp_int_base& o) BOOST_NOEXCEPT
{
for (unsigned i = 0; i < (std::max)(size(), o.size()); ++i)
std_constexpr::swap(m_wrapper.m_data[i], o.m_wrapper.m_data[i]);
std_constexpr::swap(m_sign, o.m_sign);
std_constexpr::swap(m_limbs, o.m_limbs);
}
protected:
template
BOOST_MP_CXX14_CONSTEXPR void check_in_range(const A&) BOOST_NOEXCEPT {}
};
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
template
const unsigned cpp_int_base::limb_bits;
template
const limb_type cpp_int_base::max_limb_value;
template
const limb_type cpp_int_base::sign_bit_mask;
template
const unsigned cpp_int_base::internal_limb_count;
#endif
//
// Fixed precision (i.e. no allocator), unsigned type with limb-usage count:
//
template
struct cpp_int_base
{
typedef limb_type* limb_pointer;
typedef const limb_type* const_limb_pointer;
typedef mpl::int_ checked_type;
struct scoped_shared_storage {};
//
// Interface invariants:
//
BOOST_STATIC_ASSERT_MSG(MinBits > sizeof(double_limb_type) * CHAR_BIT, "Template parameter MinBits is inconsistent with the parameter trivial - did you mistakingly try to override the trivial parameter?");
public:
BOOST_STATIC_CONSTANT(unsigned, limb_bits = sizeof(limb_type) * CHAR_BIT);
BOOST_STATIC_CONSTANT(limb_type, max_limb_value = ~static_cast(0u));
BOOST_STATIC_CONSTANT(limb_type, sign_bit_mask = static_cast(1u) << (limb_bits - 1));
BOOST_STATIC_CONSTANT(unsigned, internal_limb_count = MinBits / limb_bits + ((MinBits % limb_bits) ? 1 : 0));
BOOST_STATIC_CONSTANT(limb_type, upper_limb_mask = (MinBits % limb_bits) ? (limb_type(1) << (MinBits % limb_bits)) - 1 : (~limb_type(0)));
BOOST_STATIC_ASSERT_MSG(internal_limb_count >= 2, "A fixed precision integer type must have at least 2 limbs");
private:
union data_type
{
limb_type m_data[internal_limb_count];
limb_type m_first_limb;
double_limb_type m_double_first_limb;
BOOST_CONSTEXPR data_type()
#if defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) || defined(BOOST_NO_CXX14_CONSTEXPR)
: m_first_limb(0)
{}
#else
: m_data{0}
{}
#endif
BOOST_CONSTEXPR data_type(limb_type i)
#if defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) || defined(BOOST_NO_CXX14_CONSTEXPR)
: m_first_limb(i)
{}
#else
: m_data{i}
{}
#endif
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
BOOST_CONSTEXPR data_type(limb_type i, limb_type j) : m_data{i, j}
{}
#endif
BOOST_CONSTEXPR data_type(double_limb_type i) : m_double_first_limb(i)
{
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
if (BOOST_MP_IS_CONST_EVALUATED(m_double_first_limb))
{
data_type t(static_cast(i & max_limb_value), static_cast(i >> limb_bits));
*this = t;
}
#endif
}
#if defined(BOOST_MP_USER_DEFINED_LITERALS)
template
BOOST_CONSTEXPR data_type(literals::detail::value_pack) : m_data{VALUES...}
{}
#endif
} m_wrapper;
limb_type m_limbs;
public:
//
// Direct construction:
//
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(limb_type i) BOOST_NOEXCEPT
: m_wrapper(i),
m_limbs(1) {}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR cpp_int_base(signed_limb_type i) BOOST_MP_NOEXCEPT_IF((Checked == unchecked))
: m_wrapper(limb_type(i < 0 ? static_cast(-static_cast(i)) : i)), m_limbs(1)
{
if (i < 0)
negate();
}
#if BOOST_ENDIAN_LITTLE_BYTE && !defined(BOOST_MP_TEST_NO_LE)
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(double_limb_type i) BOOST_NOEXCEPT
: m_wrapper(i),
m_limbs(i > max_limb_value ? 2 : 1)
{}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR cpp_int_base(signed_double_limb_type i) BOOST_MP_NOEXCEPT_IF((Checked == unchecked))
: m_wrapper(double_limb_type(i < 0 ? static_cast(boost::multiprecision::detail::unsigned_abs(i)) : i)),
m_limbs(i < 0 ? (static_cast(boost::multiprecision::detail::unsigned_abs(i)) > max_limb_value ? 2 : 1) : (i > max_limb_value ? 2 : 1))
{
if (i < 0)
negate();
}
#endif
#if defined(BOOST_MP_USER_DEFINED_LITERALS)
template
BOOST_CONSTEXPR cpp_int_base(literals::detail::value_pack i)
: m_wrapper(i), m_limbs(sizeof...(VALUES))
{}
BOOST_CONSTEXPR cpp_int_base(literals::detail::value_pack<>)
: m_wrapper(static_cast(0u)), m_limbs(1) {}
#endif
//
// Helper functions for getting at our internal data, and manipulating storage:
//
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR unsigned size() const BOOST_NOEXCEPT { return m_limbs; }
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR limb_pointer limbs() BOOST_NOEXCEPT { return m_wrapper.m_data; }
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const_limb_pointer limbs() const BOOST_NOEXCEPT { return m_wrapper.m_data; }
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool sign() const BOOST_NOEXCEPT { return false; }
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void sign(bool b) BOOST_MP_NOEXCEPT_IF((Checked == unchecked))
{
if (b)
negate();
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void resize(unsigned new_size, unsigned min_size) BOOST_MP_NOEXCEPT_IF((Checked == unchecked))
{
m_limbs = (std::min)(new_size, internal_limb_count);
detail::verify_new_size(m_limbs, min_size, checked_type());
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void normalize() BOOST_MP_NOEXCEPT_IF((Checked == unchecked))
{
limb_pointer p = limbs();
detail::verify_limb_mask(m_limbs == internal_limb_count, p[internal_limb_count - 1], upper_limb_mask, checked_type());
p[internal_limb_count - 1] &= upper_limb_mask;
while ((m_limbs - 1) && !p[m_limbs - 1])
--m_limbs;
}
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base() BOOST_NOEXCEPT
: m_wrapper(limb_type(0u)),
m_limbs(1) {}
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(const cpp_int_base& o) BOOST_NOEXCEPT
: m_wrapper(o.m_wrapper),
m_limbs(o.m_limbs) {}
// Defaulted functions:
//~cpp_int_base() BOOST_NOEXCEPT {}
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
//
// These are deprecated in C++20 unless we make them explicit:
//
constexpr cpp_int_base& operator=(const cpp_int_base&) = default;
#endif
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void assign(const cpp_int_base& o) BOOST_NOEXCEPT
{
if (this != &o)
{
m_limbs = o.m_limbs;
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
if (BOOST_MP_IS_CONST_EVALUATED(m_limbs))
{
for (unsigned i = 0; i < m_limbs; ++i)
limbs()[i] = o.limbs()[i];
}
else
#endif
std::memcpy(limbs(), o.limbs(), o.size() * sizeof(limbs()[0]));
}
}
private:
void check_negate(const mpl::int_&)
{
BOOST_THROW_EXCEPTION(std::range_error("Attempt to negate an unsigned number."));
}
BOOST_MP_CXX14_CONSTEXPR void check_negate(const mpl::int_&) {}
public:
BOOST_MP_CXX14_CONSTEXPR void negate() BOOST_MP_NOEXCEPT_IF((Checked == unchecked))
{
// Not so much a negate as a complement - this gets called when subtraction
// would result in a "negative" number:
if ((m_limbs == 1) && (m_wrapper.m_data[0] == 0))
return; // negating zero is always zero, and always OK.
check_negate(checked_type());
unsigned i = m_limbs;
for (; i < internal_limb_count; ++i)
m_wrapper.m_data[i] = 0;
m_limbs = internal_limb_count;
for (i = 0; i < internal_limb_count; ++i)
m_wrapper.m_data[i] = ~m_wrapper.m_data[i];
normalize();
eval_increment(static_cast&>(*this));
}
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool isneg() const BOOST_NOEXCEPT
{
return false;
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void do_swap(cpp_int_base& o) BOOST_NOEXCEPT
{
for (unsigned i = 0; i < (std::max)(size(), o.size()); ++i)
std_constexpr::swap(m_wrapper.m_data[i], o.m_wrapper.m_data[i]);
std_constexpr::swap(m_limbs, o.m_limbs);
}
protected:
template
BOOST_MP_CXX14_CONSTEXPR void check_in_range(const A&) BOOST_NOEXCEPT {}
};
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
template
const unsigned cpp_int_base::limb_bits;
template
const limb_type cpp_int_base::max_limb_value;
template
const limb_type cpp_int_base::sign_bit_mask;
template
const unsigned cpp_int_base::internal_limb_count;
#endif
//
// Traits classes to figure out a native type with N bits, these vary from boost::uint_t only
// because some platforms have native integer types longer than boost::long_long_type, "really boost::long_long_type" anyone??
//
template
struct trivial_limb_type_imp
{
typedef double_limb_type type;
};
template
struct trivial_limb_type_imp
{
typedef typename boost::uint_t::least type;
};
template
struct trivial_limb_type : public trivial_limb_type_imp
{};
//
// Backend for fixed precision signed-magnitude type which will fit entirely inside a "double_limb_type":
//
template
struct cpp_int_base
{
typedef typename trivial_limb_type::type local_limb_type;
typedef local_limb_type* limb_pointer;
typedef const local_limb_type* const_limb_pointer;
typedef mpl::int_ checked_type;
struct scoped_shared_storage {};
protected:
BOOST_STATIC_CONSTANT(unsigned, limb_bits = sizeof(local_limb_type) * CHAR_BIT);
BOOST_STATIC_CONSTANT(local_limb_type, limb_mask = (MinBits < limb_bits) ? local_limb_type((local_limb_type(~local_limb_type(0))) >> (limb_bits - MinBits)) : local_limb_type(~local_limb_type(0)));
private:
local_limb_type m_data;
bool m_sign;
//
// Interface invariants:
//
BOOST_STATIC_ASSERT_MSG(MinBits <= sizeof(double_limb_type) * CHAR_BIT, "Template parameter MinBits is inconsistent with the parameter trivial - did you mistakingly try to override the trivial parameter?");
protected:
template
BOOST_MP_CXX14_CONSTEXPR typename boost::disable_if_c::value || (std::numeric_limits::is_specialized && (std::numeric_limits::digits <= (int)MinBits))>::type
check_in_range(T val, const mpl::int_&)
{
typedef typename common_type::type, local_limb_type>::type common_type;
if (static_cast(boost::multiprecision::detail::unsigned_abs(val)) > static_cast(limb_mask))
BOOST_THROW_EXCEPTION(std::range_error("The argument to a cpp_int constructor exceeded the largest value it can represent."));
}
template
BOOST_MP_CXX14_CONSTEXPR typename boost::disable_if_c::value || (std::numeric_limits::is_specialized && (std::numeric_limits::digits <= (int)MinBits))>::type
check_in_range(T val, const mpl::int_&)
{
using std::abs;
typedef typename common_type::type common_type;
if (static_cast(abs(val)) > static_cast(limb_mask))
BOOST_THROW_EXCEPTION(std::range_error("The argument to a cpp_int constructor exceeded the largest value it can represent."));
}
template
BOOST_MP_CXX14_CONSTEXPR void check_in_range(T, const mpl::int_&) BOOST_NOEXCEPT {}
template
BOOST_MP_CXX14_CONSTEXPR void check_in_range(T val) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval().check_in_range(std::declval(), checked_type())))
{
check_in_range(val, checked_type());
}
public:
//
// Direct construction:
//
template
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(SI i, typename boost::enable_if_c::value && (Checked == unchecked)>::type const* = 0) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval().check_in_range(std::declval())))
: m_data(i < 0 ? static_cast(static_cast::type>(boost::multiprecision::detail::unsigned_abs(i)) & limb_mask) : static_cast(i & limb_mask)), m_sign(i < 0) {}
template
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR cpp_int_base(SI i, typename boost::enable_if_c::value && (Checked == checked)>::type const* = 0) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval().check_in_range(std::declval())))
: m_data(i < 0 ? (static_cast(static_cast::type>(boost::multiprecision::detail::unsigned_abs(i)) & limb_mask)) : static_cast(i & limb_mask)), m_sign(i < 0)
{
check_in_range(i);
}
template
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(UI i, typename boost::enable_if_c::value && (Checked == unchecked)>::type const* = 0) BOOST_NOEXCEPT
: m_data(static_cast(i) & limb_mask),
m_sign(false) {}
template
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR cpp_int_base(UI i, typename boost::enable_if_c::value && (Checked == checked)>::type const* = 0) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval().check_in_range(std::declval())))
: m_data(static_cast(i) & limb_mask), m_sign(false) { check_in_range(i); }
template
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(F i, typename boost::enable_if_c::value && (Checked == unchecked)>::type const* = 0) BOOST_NOEXCEPT
: m_data(static_cast(std::fabs(i)) & limb_mask),
m_sign(i < 0) {}
template
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR cpp_int_base(F i, typename boost::enable_if_c::value && (Checked == checked)>::type const* = 0)
: m_data(static_cast(std::fabs(i)) & limb_mask), m_sign(i < 0) { check_in_range(i); }
#if defined(BOOST_MP_USER_DEFINED_LITERALS)
BOOST_CONSTEXPR cpp_int_base(literals::detail::value_pack<>) BOOST_NOEXCEPT
: m_data(static_cast(0u)),
m_sign(false)
{}
template
BOOST_CONSTEXPR cpp_int_base(literals::detail::value_pack) BOOST_NOEXCEPT
: m_data(static_cast(a)),
m_sign(false) {}
template
BOOST_CONSTEXPR cpp_int_base(literals::detail::value_pack) BOOST_NOEXCEPT
: m_data(static_cast(a) | (static_cast(b) << bits_per_limb)),
m_sign(false) {}
BOOST_CONSTEXPR cpp_int_base(const cpp_int_base& a, const literals::detail::negate_tag&) BOOST_NOEXCEPT
: m_data(a.m_data),
m_sign(a.m_data ? !a.m_sign : false) {}
#endif
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
//
// These are deprecated in C++20 unless we make them explicit:
//
constexpr cpp_int_base& operator=(const cpp_int_base&) = default;
#endif
//
// Helper functions for getting at our internal data, and manipulating storage:
//
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR unsigned size() const BOOST_NOEXCEPT { return 1; }
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR limb_pointer limbs() BOOST_NOEXCEPT { return &m_data; }
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const_limb_pointer limbs() const BOOST_NOEXCEPT { return &m_data; }
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool sign() const BOOST_NOEXCEPT { return m_sign; }
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void sign(bool b) BOOST_NOEXCEPT
{
m_sign = b;
// Check for zero value:
if (m_sign && !m_data)
{
m_sign = false;
}
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void resize(unsigned /* new_size */, unsigned min_size)
{
detail::verify_new_size(2, min_size, checked_type());
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void normalize() BOOST_MP_NOEXCEPT_IF((Checked == unchecked))
{
if (!m_data)
m_sign = false; // zero is always unsigned
detail::verify_limb_mask(true, m_data, limb_mask, checked_type());
m_data &= limb_mask;
}
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base() BOOST_NOEXCEPT : m_data(0), m_sign(false) {}
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(const cpp_int_base& o) BOOST_NOEXCEPT
: m_data(o.m_data),
m_sign(o.m_sign) {}
//~cpp_int_base() BOOST_NOEXCEPT {}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void assign(const cpp_int_base& o) BOOST_NOEXCEPT
{
m_data = o.m_data;
m_sign = o.m_sign;
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void negate() BOOST_NOEXCEPT
{
m_sign = !m_sign;
// Check for zero value:
if (m_data == 0)
{
m_sign = false;
}
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool isneg() const BOOST_NOEXCEPT
{
return m_sign;
}
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void do_swap(cpp_int_base& o) BOOST_NOEXCEPT
{
std_constexpr::swap(m_sign, o.m_sign);
std_constexpr::swap(m_data, o.m_data);
}
};
//
// Backend for unsigned fixed precision (i.e. no allocator) type which will fit entirely inside a "double_limb_type":
//
template
struct cpp_int_base
{
typedef typename trivial_limb_type::type local_limb_type;
typedef local_limb_type* limb_pointer;
typedef const local_limb_type* const_limb_pointer;
struct scoped_shared_storage {};
private:
BOOST_STATIC_CONSTANT(unsigned, limb_bits = sizeof(local_limb_type) * CHAR_BIT);
BOOST_STATIC_CONSTANT(local_limb_type, limb_mask = limb_bits != MinBits ? static_cast(static_cast(~local_limb_type(0)) >> (limb_bits - MinBits))
: static_cast(~local_limb_type(0)));
local_limb_type m_data;
typedef mpl::int_ checked_type;
//
// Interface invariants:
//
BOOST_STATIC_ASSERT_MSG(MinBits <= sizeof(double_limb_type) * CHAR_BIT, "Template parameter MinBits is inconsistent with the parameter trivial - did you mistakingly try to override the trivial parameter?");
protected:
template
BOOST_MP_CXX14_CONSTEXPR typename boost::disable_if_c::is_specialized && (std::numeric_limits::digits <= (int)MinBits)>::type
check_in_range(T val, const mpl::int_&, const boost::false_type&)
{
typedef typename common_type::type common_type;
if (static_cast(val) > limb_mask)
BOOST_THROW_EXCEPTION(std::range_error("The argument to a cpp_int constructor exceeded the largest value it can represent."));
}
template
BOOST_MP_CXX14_CONSTEXPR void check_in_range(T val, const mpl::int_&, const boost::true_type&)
{
typedef typename common_type::type common_type;
if (static_cast(val) > limb_mask)
BOOST_THROW_EXCEPTION(std::range_error("The argument to a cpp_int constructor exceeded the largest value it can represent."));
if (val < 0)
BOOST_THROW_EXCEPTION(std::range_error("The argument to an unsigned cpp_int constructor was negative."));
}
template
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void check_in_range(T, const mpl::int_&, const boost::integral_constant&) BOOST_NOEXCEPT {}
template
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void check_in_range(T val) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval().check_in_range(std::declval(), checked_type(), is_signed())))
{
check_in_range(val, checked_type(), is_signed());
}
public:
//
// Direct construction:
//
#ifdef __MSVC_RUNTIME_CHECKS
template
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_base(SI i, typename boost::enable_if_c::value && (Checked == unchecked)>::type const* = 0) BOOST_NOEXCEPT
: m_data(i < 0 ? (1 + ~static_cast(-i & limb_mask)) & limb_mask : static_cast(i & limb_mask))
{}
template