Skip to content

Commit

Permalink
First cut at allowing move between mixed but related types.
Browse files Browse the repository at this point in the history
See #278.
  • Loading branch information
jzmaddock committed Dec 24, 2020
1 parent 4700c04 commit 691473c
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 12 deletions.
57 changes: 47 additions & 10 deletions include/boost/multiprecision/cpp_int.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class
struct cpp_int_base<MinBits, MaxBits, signed_magnitude, Checked, Allocator, false>
: private boost::empty_value<typename detail::rebind<limb_type, Allocator>::type>
{
template <unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, bool trivial2>
friend struct cpp_int_base;

typedef typename detail::rebind<limb_type, Allocator>::type allocator_type;
#ifdef BOOST_NO_CXX11_ALLOCATOR
typedef typename allocator_type::pointer limb_pointer;
Expand All @@ -194,9 +197,9 @@ struct cpp_int_base<MinBits, MaxBits, signed_magnitude, Checked, Allocator, fals
//
BOOST_STATIC_ASSERT(!is_void<Allocator>::value);

private:
typedef boost::empty_value<allocator_type> base_type;

private:
struct limb_data
{
unsigned capacity;
Expand Down Expand Up @@ -408,16 +411,16 @@ struct cpp_int_base<MinBits, MaxBits, signed_magnitude, Checked, Allocator, fals
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
cpp_int_base(cpp_int_base&& o)
: base_type(static_cast<base_type&&>(o)), m_limbs(o.m_limbs), m_sign(o.m_sign), m_internal(o.m_internal), m_alias(o.m_alias)
: base_type(static_cast<base_type&&>(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;
m_data.ld = o.m_data.ld;
o.m_limbs = 0;
o.m_internal = true;
}
}
Expand All @@ -426,22 +429,45 @@ struct cpp_int_base<MinBits, MaxBits, signed_magnitude, Checked, Allocator, fals
if (!m_internal && !m_alias)
allocator().deallocate(m_data.ld.data, m_data.ld.capacity);
*static_cast<base_type*>(this) = static_cast<base_type&&>(o);
m_limbs = o.m_limbs;
m_sign = o.m_sign;
m_internal = o.m_internal;
m_alias = o.m_alias;
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;
m_data.ld = o.m_data.ld;
o.m_limbs = 0;
o.m_internal = true;
}
return *this;
}
template <unsigned MinBits2, unsigned MaxBits2, cpp_int_check_type Checked2>
cpp_int_base& operator=(cpp_int_base<MinBits2, MaxBits2, signed_magnitude, Checked2, Allocator>&& o) BOOST_NOEXCEPT
{
if(o.m_internal)
{
m_sign = o.m_sign;
this->resize(o.size(), o.size());
std::memcpy(this->limbs(), o.limbs(), o.size() * sizeof((o.limbs())));
return *this;
}
if (!m_internal && !m_alias)
allocator().deallocate(m_data.ld.data, m_data.ld.capacity);
*static_cast<base_type*>(this) = static_cast<typename cpp_int_base<MinBits2, MaxBits2, signed_magnitude, Checked2, Allocator>::base_type&&>(o);
m_limbs = o.m_limbs;
m_sign = o.m_sign;
m_internal = o.m_internal;
m_alias = o.m_alias;
m_data.ld.capacity = o.m_data.ld.capacity;
m_data.ld.data = o.limbs();
o.m_limbs = 0;
o.m_internal = true;
return *this;
}
#endif
BOOST_MP_FORCEINLINE ~cpp_int_base() BOOST_NOEXCEPT
{
Expand Down Expand Up @@ -1360,6 +1386,11 @@ struct cpp_int_backend
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_backend(cpp_int_backend&& o) BOOST_NOEXCEPT
: base_type(static_cast<base_type&&>(o))
{}
template <unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2>
BOOST_MP_FORCEINLINE BOOST_CONSTEXPR cpp_int_backend(cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2>&& o, typename std::enable_if<is_implicit_cpp_int_conversion<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2>, self_type>::value>::type* = 0) BOOST_NOEXCEPT
{
*this = static_cast<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2>&&>(o);
}
#endif
//
// Direct construction from arithmetic type:
Expand Down Expand Up @@ -1480,6 +1511,12 @@ struct cpp_int_backend
*static_cast<base_type*>(this) = static_cast<base_type&&>(o);
return *this;
}
template <unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2>
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<((MaxBits2 <= MaxBits) || (MaxBits == 0)) && !boost::is_void<Allocator>::value, cpp_int_backend&>::type operator=(cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2>&& o) BOOST_NOEXCEPT
{
*static_cast<base_type*>(this) = static_cast<typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2>::base_type&&>(o);
return *this;
}
#endif
private:
template <class A>
Expand Down
25 changes: 24 additions & 1 deletion include/boost/multiprecision/cpp_int/multiply.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ setup_karatsuba(
unsigned sz = as + bs;
unsigned storage_size = karatsuba_storage_size(s);

if (sz * sizeof(limb_type) * CHAR_BIT <= MaxBits1)
if (!is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || (sz * sizeof(limb_type) * CHAR_BIT <= MaxBits1))
{
// Result is large enough for all the bits of the result, so we can use aliasing:
result.resize(sz, sz);
Expand All @@ -307,6 +307,29 @@ setup_karatsuba(
result = t;
}
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
inline typename enable_if_c<!is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_fixed_precision<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && !is_fixed_precision<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value>::type
setup_karatsuba(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b)
{
//
// Variable precision, mixed arguments, just alias and forward:
//
typedef cpp_int_backend<0, 0, signed_magnitude, unchecked, std::allocator<limb_type> > variable_precision_type;
variable_precision_type a_t(a.limbs(), 0, a.size()), b_t(b.limbs(), 0, b.size());
unsigned as = a.size();
unsigned bs = b.size();
unsigned s = as > bs ? as : bs;
unsigned sz = as + bs;
unsigned storage_size = karatsuba_storage_size(s);

result.resize(sz, sz);
variable_precision_type t(result.limbs(), 0, result.size());
typename variable_precision_type::scoped_shared_storage storage(t.allocator(), storage_size);
multiply_karatsuba(t, a_t, b_t, storage);
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
inline BOOST_MP_CXX14_CONSTEXPR void
Expand Down
37 changes: 36 additions & 1 deletion include/boost/multiprecision/number.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,15 @@ class number
m_backend = canonical_value(v);
return *this;
}
/*
template <class V>
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<is_convertible<V, self_type>::value && !boost::multiprecision::is_number_expression<V>::value && !boost::multiprecision::is_number<V>::value, number<Backend, ExpressionTemplates>&>::type
operator=(V&& v)
BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = canonical_value(std::declval<V>())))
{
m_backend = canonical_value(BOOST_MP_MOVE(v));
return *this;
}*/
template <class V>
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v)
BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
Expand Down Expand Up @@ -323,6 +332,19 @@ class number
m_backend = static_cast<Backend&&>(r.m_backend);
return *this;
}
template <class Other, expression_template_option ET>
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(number<Other, ET>&& val,
typename boost::enable_if_c<(boost::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = 0)
BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Other const&>())))
: m_backend(static_cast<number<Other, ET>&&>(val).backend()) {}
template <class Other, expression_template_option ET>
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<(boost::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value), number&>::type
operator=(number<Other, ET>&& val)
BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Other const&>())))
{
m_backend = std::move(val).backend();
return *this;
}
#endif

BOOST_MP_CXX14_CONSTEXPR number& operator+=(const self_type& val)
Expand Down Expand Up @@ -988,7 +1010,18 @@ class number
do_assign(e, tag());
}
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
BOOST_MP_CXX14_CONSTEXPR void do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const mpl::false_&)
BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<std::is_assignable<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>::type
do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const mpl::false_&)
{
// The result of the expression isn't the same type as this -
// create a temporary result and assign it to *this:
typedef typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type temp_type;
temp_type t(e);
*this = BOOST_MP_MOVE(t);
}
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
BOOST_MP_CXX14_CONSTEXPR typename boost::enable_if_c<!std::is_assignable<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>::type
do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const mpl::false_&)
{
// The result of the expression isn't the same type as this -
// create a temporary result and assign it to *this:
Expand Down Expand Up @@ -1989,6 +2022,8 @@ class number
static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& canonical_value(const self_type& v) BOOST_NOEXCEPT { return v.m_backend; }
template <class B2, expression_template_option ET>
static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const B2& canonical_value(const number<B2, ET>& v) BOOST_NOEXCEPT { return v.backend(); }
template <class B2, expression_template_option ET>
static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR B2&& canonical_value(number<B2, ET>&& v) BOOST_NOEXCEPT { return static_cast<number<B2, ET>&&>(v).backend(); }
template <class V>
static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR typename boost::disable_if<is_same<typename detail::canonical<V, Backend>::type, V>, typename detail::canonical<V, Backend>::type>::type
canonical_value(const V& v) BOOST_NOEXCEPT { return static_cast<typename detail::canonical<V, Backend>::type>(v); }
Expand Down
2 changes: 2 additions & 0 deletions test/test_mixed_cpp_int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ int main()
test<checked_int256_t, checked_int512_t>();
test<number<cpp_int_backend<64, 64, signed_magnitude, checked, void>, et_off>, checked_int128_t>();
test<boost::int64_t, checked_int128_t>();
test<number<cpp_int_backend<4096, 4096, signed_magnitude, checked, void>, et_off>, cpp_int>();
test<number<cpp_int_backend<4096> >, cpp_int>();

test<checked_uint512_t, checked_uint1024_t>();
test<checked_uint256_t, checked_uint512_t>();
Expand Down

0 comments on commit 691473c

Please sign in to comment.