summaryrefslogtreecommitdiff
path: root/boost/multiprecision/cpp_int.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/multiprecision/cpp_int.hpp')
-rw-r--r--boost/multiprecision/cpp_int.hpp195
1 files changed, 162 insertions, 33 deletions
diff --git a/boost/multiprecision/cpp_int.hpp b/boost/multiprecision/cpp_int.hpp
index d451567bb9..60ad87676c 100644
--- a/boost/multiprecision/cpp_int.hpp
+++ b/boost/multiprecision/cpp_int.hpp
@@ -16,6 +16,7 @@
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/multiprecision/cpp_int/cpp_int_config.hpp>
#include <boost/multiprecision/rational_adaptor.hpp>
+#include <boost/multiprecision/traits/is_byte_container.hpp>
#include <boost/detail/endian.hpp>
#include <boost/integer/static_min_max.hpp>
#include <boost/type_traits/common_type.hpp>
@@ -38,9 +39,20 @@ namespace backends{
#pragma warning(disable:4127 4351 4293 4996 4307 4702 6285)
#endif
-template <unsigned MinBits = 0, unsigned MaxBits = 0, cpp_integer_type SignType = signed_magnitude, cpp_int_check_type Checked = unchecked, class Allocator = typename mpl::if_c<MinBits && (MinBits == MaxBits), void, std::allocator<limb_type> >::type >
+template <unsigned MinBits = 0, unsigned MaxBits = 0, boost::multiprecision::cpp_integer_type SignType = signed_magnitude, cpp_int_check_type Checked = unchecked, class Allocator = typename mpl::if_c<MinBits && (MinBits == MaxBits), void, std::allocator<limb_type> >::type >
struct cpp_int_backend;
+} // namespace backends
+
+namespace detail {
+
+ template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
+ struct is_byte_container<backends::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> > : public boost::false_type {};
+
+} // namespace detail
+
+namespace backends{
+
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, bool trivial = false>
struct cpp_int_base;
//
@@ -944,7 +956,7 @@ public:
if(b)
negate();
}
- BOOST_MP_FORCEINLINE void resize(unsigned new_size, unsigned min_size)
+ BOOST_MP_FORCEINLINE void resize(unsigned, unsigned min_size)
{
detail::verify_new_size(2, min_size, checked_type());
}
@@ -1270,7 +1282,7 @@ private:
}
public:
template <class Arithmetic>
- BOOST_MP_FORCEINLINE cpp_int_backend& operator = (Arithmetic val) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<cpp_int_backend>().do_assign_arithmetic(std::declval<Arithmetic>(), trivial_tag())))
+ BOOST_MP_FORCEINLINE typename boost::enable_if_c<!boost::multiprecision::detail::is_byte_container<Arithmetic>::value, cpp_int_backend&>::type operator = (Arithmetic val) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<cpp_int_backend>().do_assign_arithmetic(std::declval<Arithmetic>(), trivial_tag())))
{
do_assign_arithmetic(val, trivial_tag());
return *this;
@@ -1355,43 +1367,97 @@ private:
n -= 1;
}
}
+ //
+ // Exception guarentee: create the result in stack variable "result"
+ // then do a swap at the end. In the event of a throw, *this will
+ // be left unchanged.
+ //
+ cpp_int_backend result;
if(n)
{
- if(radix == 8 || radix == 16)
+ if(radix == 16)
{
- unsigned shift = radix == 8 ? 3 : 4;
- unsigned block_count = base_type::limb_bits / shift;
- unsigned block_shift = shift * block_count;
- limb_type val, block;
+ while(*s == '0') ++s;
+ std::size_t bitcount = 4 * std::strlen(s);
+ limb_type val;
+ std::size_t limb, shift;
+ if(bitcount > 4)
+ bitcount -= 4;
+ else
+ bitcount = 0;
+ std::size_t newsize = bitcount / (sizeof(limb_type) * CHAR_BIT) + 1;
+ result.resize(static_cast<unsigned>(newsize), static_cast<unsigned>(newsize)); // will throw if this is a checked integer that cannot be resized
+ std::memset(result.limbs(), 0, result.size() * sizeof(limb_type));
while(*s)
{
- block = 0;
- for(unsigned i = 0; (i < block_count); ++i)
+ if(*s >= '0' && *s <= '9')
+ val = *s - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ val = 10 + *s - 'a';
+ else if(*s >= 'A' && *s <= 'F')
+ val = 10 + *s - 'A';
+ else
{
- if(*s >= '0' && *s <= '9')
- val = *s - '0';
- else if(*s >= 'a' && *s <= 'f')
- val = 10 + *s - 'a';
- else if(*s >= 'A' && *s <= 'F')
- val = 10 + *s - 'A';
- else
- val = base_type::max_limb_value;
- if(val >= radix)
- {
- BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected content found while parsing character string."));
- }
- block <<= shift;
- block |= val;
- if(!*++s)
+ BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected content found while parsing character string."));
+ }
+ limb = bitcount / (sizeof(limb_type) * CHAR_BIT);
+ shift = bitcount % (sizeof(limb_type) * CHAR_BIT);
+ val <<= shift;
+ if(result.size() > limb)
+ {
+ result.limbs()[limb] |= val;
+ }
+ ++s;
+ bitcount -= 4;
+ }
+ result.normalize();
+ }
+ else if(radix == 8)
+ {
+ while(*s == '0') ++s;
+ std::size_t bitcount = 3 * std::strlen(s);
+ limb_type val;
+ std::size_t limb, shift;
+ if(bitcount > 3)
+ bitcount -= 3;
+ else
+ bitcount = 0;
+ std::size_t newsize = bitcount / (sizeof(limb_type) * CHAR_BIT) + 1;
+ result.resize(static_cast<unsigned>(newsize), static_cast<unsigned>(newsize)); // will throw if this is a checked integer that cannot be resized
+ std::memset(result.limbs(), 0, result.size() * sizeof(limb_type));
+ while(*s)
+ {
+ if(*s >= '0' && *s <= '7')
+ val = *s - '0';
+ else
+ {
+ BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected content found while parsing character string."));
+ }
+ limb = bitcount / (sizeof(limb_type) * CHAR_BIT);
+ shift = bitcount % (sizeof(limb_type) * CHAR_BIT);
+ if(result.size() > limb)
+ {
+ result.limbs()[limb] |= (val << shift);
+ if(shift > sizeof(limb_type) * CHAR_BIT - 3)
{
- // final shift is different:
- block_shift = (i + 1) * shift;
- break;
+ // Deal with the bits in val that overflow into the next limb:
+ val >>= (sizeof(limb_type) * CHAR_BIT - shift);
+ if(val)
+ {
+ // If this is the most-significant-limb, we may need to allocate an extra one for the overflow:
+ if(limb + 1 == newsize)
+ result.resize(static_cast<unsigned>(newsize + 1), static_cast<unsigned>(newsize + 1));
+ if(result.size() > limb + 1)
+ {
+ result.limbs()[limb + 1] |= val;
+ }
+ }
}
}
- eval_left_shift(*this, block_shift);
- this->limbs()[0] |= block;
+ ++s;
+ bitcount -= 3;
}
+ result.normalize();
}
else
{
@@ -1416,13 +1482,14 @@ private:
break;
}
}
- eval_multiply(*this, block_mult);
- eval_add(*this, block);
+ eval_multiply(result, block_mult);
+ eval_add(result, block);
}
}
}
if(isneg)
- this->negate();
+ result.negate();
+ result.swap(*this);
}
public:
cpp_int_backend& operator = (const char* s)
@@ -1638,6 +1705,67 @@ public:
{
return do_get_string(f, trivial_tag());
}
+private:
+ template <class Container>
+ void construct_from_container(const Container& c, const mpl::false_&)
+ {
+ //
+ // We assume that c is a sequence of (unsigned) bytes with the most significant byte first:
+ //
+ unsigned newsize = static_cast<unsigned>(c.size() / sizeof(limb_type));
+ if(c.size() % sizeof(limb_type))
+ {
+ ++newsize;
+ }
+ if(newsize)
+ {
+ this->resize(newsize, newsize); // May throw
+ std::memset(this->limbs(), 0, this->size());
+ typename Container::const_iterator i(c.begin()), j(c.end());
+ unsigned byte_location = static_cast<unsigned>(c.size() - 1);
+ while(i != j)
+ {
+ unsigned limb = byte_location / sizeof(limb_type);
+ unsigned shift = (byte_location % sizeof(limb_type)) * CHAR_BIT;
+ if(this->size() > limb)
+ this->limbs()[limb] |= static_cast<limb_type>(static_cast<unsigned char>(*i)) << shift;
+ ++i;
+ --byte_location;
+ }
+ }
+ }
+ template <class Container>
+ void construct_from_container(const Container& c, const mpl::true_&)
+ {
+ //
+ // We assume that c is a sequence of (unsigned) bytes with the most significant byte first:
+ //
+ typedef typename base_type::local_limb_type local_limb_type;
+ *this->limbs() = 0;
+ if(c.size())
+ {
+ typename Container::const_iterator i(c.begin()), j(c.end());
+ unsigned byte_location = static_cast<unsigned>(c.size() - 1);
+ while(i != j)
+ {
+ unsigned limb = byte_location / sizeof(local_limb_type);
+ unsigned shift = (byte_location % sizeof(local_limb_type)) * CHAR_BIT;
+ if(limb == 0)
+ this->limbs()[0] |= static_cast<limb_type>(static_cast<unsigned char>(*i)) << shift;
+ ++i;
+ --byte_location;
+ }
+ }
+ }
+public:
+ template <class Container>
+ cpp_int_backend(const Container& c, typename boost::enable_if_c<boost::multiprecision::detail::is_byte_container<Container>::value>::type const* = 0)
+ {
+ //
+ // We assume that c is a sequence of (unsigned) bytes with the most significant byte first:
+ //
+ construct_from_container(c, trivial_tag());
+ }
template <unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
int compare_imp(const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o, const mpl::false_&, const mpl::false_&)const BOOST_NOEXCEPT
{
@@ -1811,5 +1939,6 @@ struct is_explicitly_convertible<cpp_int_backend<MinBits, MaxBits, SignType, Che
#include <boost/multiprecision/cpp_int/literals.hpp>
#endif
#include <boost/multiprecision/cpp_int/serialize.hpp>
+#include <boost/multiprecision/cpp_int/import_export.hpp>
#endif