diff options
Diffstat (limited to 'boost/multiprecision/cpp_int.hpp')
-rw-r--r-- | boost/multiprecision/cpp_int.hpp | 195 |
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 |