Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r80083 - in sandbox/big_number: boost/multiprecision libs/multiprecision/test libs/multiprecision/test/compile_fail
From: john_at_[hidden]
Date: 2012-08-19 12:39:25


Author: johnmaddock
Date: 2012-08-19 12:39:24 EDT (Sun, 19 Aug 2012)
New Revision: 80083
URL: http://svn.boost.org/trac/boost/changeset/80083

Log:
Make some gmp constructors explicit.
Add tests to verify that explicit conversions fail.
Fix failures inside number.hpp.
Added:
   sandbox/big_number/libs/multiprecision/test/compile_fail/conv_fail_45.cpp (contents, props changed)
   sandbox/big_number/libs/multiprecision/test/compile_fail/conv_fail_46.cpp (contents, props changed)
   sandbox/big_number/libs/multiprecision/test/compile_fail/conv_fail_47.cpp (contents, props changed)
   sandbox/big_number/libs/multiprecision/test/compile_fail/conv_fail_48.cpp (contents, props changed)
Text files modified:
   sandbox/big_number/boost/multiprecision/gmp.hpp | 80 ++++++++++++++++++++++++++++++---------
   sandbox/big_number/boost/multiprecision/number.hpp | 55 ++++++++++++++++-----------
   sandbox/big_number/libs/multiprecision/test/Jamfile.v2 | 5 ++
   sandbox/big_number/libs/multiprecision/test/test_gmp_conversions.cpp | 23 ++++++++++-
   4 files changed, 119 insertions(+), 44 deletions(-)

Modified: sandbox/big_number/boost/multiprecision/gmp.hpp
==============================================================================
--- sandbox/big_number/boost/multiprecision/gmp.hpp (original)
+++ sandbox/big_number/boost/multiprecision/gmp.hpp 2012-08-19 12:39:24 EDT (Sun, 19 Aug 2012)
@@ -369,20 +369,22 @@
    }
    gmp_float(const gmp_float& o) : detail::gmp_float_imp<digits10>(o) {}
    template <unsigned D>
- gmp_float(const gmp_float<D>& o);
+ gmp_float(const gmp_float<D>& o, typename enable_if_c<D <= digits10>::type* = 0);
+ template <unsigned D>
+ explicit gmp_float(const gmp_float<D>& o, typename disable_if_c<D <= digits10>::type* = 0);
    gmp_float(const gmp_int& o);
    gmp_float(const gmp_rational& o);
- gmp_float(mpf_t val)
+ gmp_float(const mpf_t val)
    {
       mpf_init2(this->m_data, ((digits10 + 1) * 1000L) / 301L);
       mpf_set(this->m_data, val);
    }
- gmp_float(mpz_t val)
+ gmp_float(const mpz_t val)
    {
       mpf_init2(this->m_data, ((digits10 + 1) * 1000L) / 301L);
       mpf_set_z(this->m_data, val);
    }
- gmp_float(mpq_t val)
+ gmp_float(const mpq_t val)
    {
       mpf_init2(this->m_data, ((digits10 + 1) * 1000L) / 301L);
       mpf_set_q(this->m_data, val);
@@ -442,17 +444,17 @@
    {
       mpf_init2(this->m_data, ((get_default_precision() + 1) * 1000L) / 301L);
    }
- gmp_float(mpf_t val)
+ gmp_float(const mpf_t val)
    {
       mpf_init2(this->m_data, ((get_default_precision() + 1) * 1000L) / 301L);
       mpf_set(this->m_data, val);
    }
- gmp_float(mpz_t val)
+ gmp_float(const mpz_t val)
    {
       mpf_init2(this->m_data, ((get_default_precision() + 1) * 1000L) / 301L);
       mpf_set_z(this->m_data, val);
    }
- gmp_float(mpq_t val)
+ gmp_float(const mpq_t val)
    {
       mpf_init2(this->m_data, ((get_default_precision() + 1) * 1000L) / 301L);
       mpf_set_q(this->m_data, val);
@@ -461,7 +463,7 @@
    template <unsigned D>
    gmp_float(const gmp_float<D>& o)
    {
- mpf_init2(this->m_data, ((get_default_precision() + 1) * 1000L) / 301L);
+ mpf_init2(this->m_data, mpf_get_prec(o.data()));
       mpf_set(this->m_data, o.data());
    }
 #ifndef BOOST_NO_RVALUE_REFERENCES
@@ -491,7 +493,13 @@
    gmp_float& operator=(const gmp_float<D>& o)
    {
       if(this->m_data[0]._mp_d == 0)
- mpf_init2(this->m_data, ((get_default_precision() + 1) * 1000L) / 301L);
+ {
+ mpf_init2(this->m_data, mpf_get_prec(o.data()));
+ }
+ else
+ {
+ mpf_set_prec(this->m_data, mpf_get_prec(o.data()));
+ }
       mpf_set(this->m_data, o.data());
       return *this;
    }
@@ -534,11 +542,11 @@
    }
    unsigned precision()const BOOST_NOEXCEPT
    {
- return mpf_get_prec(this->m_data) * 301L / 1000 - 1;
+ return (mpf_get_prec(this->m_data) * 301L) / 1000 - 1;
    }
    void precision(unsigned digits10) BOOST_NOEXCEPT
    {
- mpf_set_prec(this->m_data, (digits10 + 1) * 1000L / 301);
+ mpf_set_prec(this->m_data, ((digits10 + 1) * 1000L) / 301);
    }
 };
 
@@ -977,27 +985,27 @@
       o.m_data[0]._mp_d = 0;
    }
 #endif
- gmp_int(mpf_t val)
+ explicit gmp_int(const mpf_t val)
    {
       mpz_init(this->m_data);
       mpz_set_f(this->m_data, val);
    }
- gmp_int(mpz_t val)
+ gmp_int(const mpz_t val)
    {
       mpz_init_set(this->m_data, val);
    }
- gmp_int(mpq_t val)
+ explicit gmp_int(const mpq_t val)
    {
       mpz_init(this->m_data);
       mpz_set_q(this->m_data, val);
    }
    template <unsigned Digits10>
- gmp_int(const gmp_float<Digits10>& o)
+ explicit gmp_int(const gmp_float<Digits10>& o)
    {
       mpz_init(this->m_data);
       mpz_set_f(this->m_data, o.data());
    }
- gmp_int(const gmp_rational& o);
+ explicit gmp_int(const gmp_rational& o);
    gmp_int& operator = (const gmp_int& o)
    {
       if(o.m_data[0]._mp_d)
@@ -1659,12 +1667,12 @@
       o.m_data[0]._mp_den._mp_d = 0;
    }
 #endif
- gmp_rational(mpq_t o)
+ gmp_rational(const mpq_t o)
    {
       mpq_init(m_data);
       mpq_set(m_data, o);
    }
- gmp_rational(mpz_t o)
+ gmp_rational(const mpz_t o)
    {
       mpq_init(m_data);
       mpq_set_z(m_data, o);
@@ -1998,7 +2006,14 @@
 //
 template <unsigned Digits10>
 template <unsigned D>
-inline gmp_float<Digits10>::gmp_float(const gmp_float<D>& o)
+inline gmp_float<Digits10>::gmp_float(const gmp_float<D>& o, typename enable_if_c<D <= Digits10>::type*)
+{
+ mpf_init2(this->m_data, (((Digits10 ? Digits10 : this->get_default_precision()) + 1) * 1000L) / 301L);
+ mpf_set(this->m_data, o.data());
+}
+template <unsigned Digits10>
+template <unsigned D>
+inline gmp_float<Digits10>::gmp_float(const gmp_float<D>& o, typename disable_if_c<D <= Digits10>::type*)
 {
    mpf_init2(this->m_data, (((Digits10 ? Digits10 : this->get_default_precision()) + 1) * 1000L) / 301L);
    mpf_set(this->m_data, o.data());
@@ -2089,6 +2104,33 @@
    typedef number<gmp_int> type;
 };
 
+#ifdef BOOST_NO_SFINAE_EXPR
+
+namespace detail{
+
+template<>
+struct is_explicitly_convertible<typename canonical<mpf_t, gmp_int>::type, gmp_int> : public mpl::true_ {};
+template<>
+struct is_explicitly_convertible<typename canonical<mpq_t, gmp_int>::type, gmp_int> : public mpl::true_ {};
+template<unsigned Digits10>
+struct is_explicitly_convertible<gmp_float<Digits10>, gmp_int> : public mpl::true_ {};
+template<>
+struct is_explicitly_convertible<gmp_rational, gmp_int> : public mpl::true_ {};
+template<unsigned D1, unsigned D2>
+struct is_explicitly_convertible<gmp_float<D1>, gmp_float<D2> > : public mpl::true_ {};
+
+}
+
+#endif
+
+template<>
+struct number_category<typename detail::canonical<mpz_t, gmp_int>::type> : public mpl::int_<number_kind_integer>{};
+template<>
+struct number_category<typename detail::canonical<mpq_t, gmp_rational>::type> : public mpl::int_<number_kind_rational>{};
+template<>
+struct number_category<typename detail::canonical<mpf_t, gmp_float<0> >::type> : public mpl::int_<number_kind_floating_point>{};
+
+
 typedef number<gmp_float<50> > mpf_float_50;
 typedef number<gmp_float<100> > mpf_float_100;
 typedef number<gmp_float<500> > mpf_float_500;

Modified: sandbox/big_number/boost/multiprecision/number.hpp
==============================================================================
--- sandbox/big_number/boost/multiprecision/number.hpp (original)
+++ sandbox/big_number/boost/multiprecision/number.hpp 2012-08-19 12:39:24 EDT (Sun, 19 Aug 2012)
@@ -43,7 +43,7 @@
    BOOST_FORCEINLINE BOOST_CONSTEXPR number() BOOST_NOEXCEPT_IF(noexcept(Backend())) {}
    BOOST_FORCEINLINE BOOST_CONSTEXPR number(const number& e) BOOST_NOEXCEPT_IF(noexcept(Backend(static_cast<const Backend&>(std::declval<Backend>())))) : m_backend(e.m_backend){}
    template <class V>
- BOOST_FORCEINLINE number(V v, typename enable_if_c<
+ BOOST_FORCEINLINE number(const V& v, typename enable_if_c<
             (boost::is_arithmetic<V>::value || is_same<std::string, V>::value || is_convertible<V, const char*>::value)
             && !is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
             && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
@@ -52,28 +52,29 @@
       m_backend = canonical_value(v);
    }
    template <class V>
- BOOST_FORCEINLINE BOOST_CONSTEXPR number(V v, typename enable_if_c<
- (boost::is_arithmetic<V>::value || is_same<std::string, V>::value || is_convertible<V, const char*>::value)
- && is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
+ BOOST_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename enable_if_c<
+ /*(boost::is_arithmetic<V>::value || is_same<std::string, V>::value || is_convertible<V, const char*>::value)
+ &&*/ is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
             && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
>::type* = 0)
       : m_backend(canonical_value(v)) {}
    BOOST_FORCEINLINE BOOST_CONSTEXPR number(const number& e, unsigned digits10)
       : m_backend(e.m_backend, digits10){}
    template <class V>
- explicit BOOST_FORCEINLINE number(V v, typename enable_if_c<
+ explicit BOOST_FORCEINLINE number(const V& v, typename enable_if_c<
             (boost::is_arithmetic<V>::value || is_same<std::string, V>::value || is_convertible<V, const char*>::value)
- && !is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
+ && !detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
             && detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
>::type* = 0)
    {
       m_backend = canonical_value(v);
    }
    template <class V>
- explicit BOOST_FORCEINLINE BOOST_CONSTEXPR number(V v, typename enable_if_c<
- (boost::is_arithmetic<V>::value || is_same<std::string, V>::value || is_convertible<V, const char*>::value)
- && is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
- && detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
+ explicit BOOST_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename enable_if_c<
+ /*(boost::is_arithmetic<V>::value || is_same<std::string, V>::value || is_convertible<V, const char*>::value)
+ &&*/ detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
+ && (detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
+ || !is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value)
>::type* = 0)
       : m_backend(canonical_value(v)) {}
    /*
@@ -92,12 +93,16 @@
    BOOST_FORCEINLINE BOOST_CONSTEXPR number(const number<Backend, ET>& val) BOOST_NOEXCEPT_IF(noexcept(Backend(static_cast<const Backend&>(std::declval<Backend>())))) : m_backend(val.m_backend) {}
 
    template <class Other, bool ET>
- BOOST_FORCEINLINE number(const number<Other, ET>& val, typename enable_if_c<(boost::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = 0) BOOST_NOEXCEPT_IF(noexcept(std::declval<Backend>() = std::declval<Other>()))
- {
- m_backend = val.backend();
- }
+ BOOST_FORCEINLINE number(const number<Other, ET>& val,
+ typename enable_if_c<(boost::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = 0)
+ BOOST_NOEXCEPT_IF(noexcept(std::declval<Backend>() = std::declval<Other>()))
+ : m_backend(val.backend()) {}
+
    template <class Other, bool ET>
- number(const number<Other, ET>& val, typename enable_if_c<(!boost::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = 0)
+ number(const number<Other, ET>& val, typename enable_if_c<
+ (!detail::is_explicitly_convertible<Other, Backend>::value
+ && !detail::is_restricted_conversion<Other, Backend>::value)
+ >::type* = 0)
    {
       //
       // Attempt a generic interconvertion:
@@ -105,12 +110,17 @@
       detail::generic_interconvert(backend(), val.backend(), number_category<Backend>(), number_category<Other>());
    }
    template <class Other, bool ET>
- explicit BOOST_FORCEINLINE number(const number<Other, ET>& val, typename enable_if_c<(boost::is_convertible<Other, Backend>::value && detail::is_restricted_conversion<Other, Backend>::value)>::type* = 0) BOOST_NOEXCEPT_IF(noexcept(std::declval<Backend>() = std::declval<Other>()))
- {
- m_backend = val.backend();
- }
+ explicit BOOST_FORCEINLINE number(const number<Other, ET>& val, typename enable_if_c<
+ (detail::is_explicitly_convertible<Other, Backend>::value
+ && (detail::is_restricted_conversion<Other, Backend>::value || !boost::is_convertible<Other, Backend>::value))
+ >::type* = 0) BOOST_NOEXCEPT_IF(noexcept(std::declval<Backend>() = std::declval<Other>()))
+ : m_backend(val.backend()) {}
+
    template <class Other, bool ET>
- explicit number(const number<Other, ET>& val, typename enable_if_c<(!boost::is_convertible<Other, Backend>::value && detail::is_restricted_conversion<Other, Backend>::value)>::type* = 0)
+ explicit number(const number<Other, ET>& val, typename enable_if_c<
+ (!detail::is_explicitly_convertible<Other, Backend>::value
+ && detail::is_restricted_conversion<Other, Backend>::value)
+ >::type* = 0)
    {
       //
       // Attempt a generic interconvertion:
@@ -130,11 +140,12 @@
       assign_components(m_backend, v1.backend(), v2.backend());
    }
 
+ /*
    template <class V>
    BOOST_FORCEINLINE BOOST_CONSTEXPR number(V v, typename enable_if<mpl::and_<is_convertible<V, Backend>, mpl::not_<mpl::or_<boost::is_arithmetic<V>, is_same<std::string, V>, is_convertible<V, const char*> > > > >::type* = 0)
       BOOST_NOEXCEPT_IF(noexcept(Backend(static_cast<const V&>(std::declval<V>()))))
       : m_backend(v){}
-
+ */
    template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
    typename enable_if<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>, number&>::type operator=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
    {
@@ -201,7 +212,7 @@
    */
 
    template <class Other>
- typename disable_if<is_convertible<Other, Backend>, number<Backend, ExpressionTemplates>& >::type
+ typename disable_if<detail::is_explicitly_convertible<Other, Backend>, number<Backend, ExpressionTemplates>& >::type
       operator=(const number<Other>& v)
    {
       //

Modified: sandbox/big_number/libs/multiprecision/test/Jamfile.v2
==============================================================================
--- sandbox/big_number/libs/multiprecision/test/Jamfile.v2 (original)
+++ sandbox/big_number/libs/multiprecision/test/Jamfile.v2 2012-08-19 12:39:24 EDT (Sun, 19 Aug 2012)
@@ -802,7 +802,10 @@
 
 for local source in [ glob compile_fail/*.cpp ]
 {
- compile-fail $(source) ;
+ compile-fail $(source)
+ :
+ [ check-target-builds ../config//has_gmp : <define>TEST_GMP : ]
+ ;
 }
 
 if ! $(disable-concepts)

Added: sandbox/big_number/libs/multiprecision/test/compile_fail/conv_fail_45.cpp
==============================================================================
--- (empty file)
+++ sandbox/big_number/libs/multiprecision/test/compile_fail/conv_fail_45.cpp 2012-08-19 12:39:24 EDT (Sun, 19 Aug 2012)
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2012 John Maddock. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifdef TEST_GMP
+
+#include <boost/multiprecision/gmp.hpp>
+
+using namespace boost::multiprecision;
+
+void foo(mpz_int i);
+
+int main()
+{
+ mpf_t f
+ foo(f);
+}
+
+#else
+
+#error "Nothing to test without GMP!"
+
+#endif

Added: sandbox/big_number/libs/multiprecision/test/compile_fail/conv_fail_46.cpp
==============================================================================
--- (empty file)
+++ sandbox/big_number/libs/multiprecision/test/compile_fail/conv_fail_46.cpp 2012-08-19 12:39:24 EDT (Sun, 19 Aug 2012)
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2012 John Maddock. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifdef TEST_GMP
+
+#include <boost/multiprecision/gmp.hpp>
+
+using namespace boost::multiprecision;
+
+int main()
+{
+ mpf_t f;
+ mpz_int i;
+ i = f;
+}
+
+#else
+
+#error "Nothing to test without GMP!"
+
+#endif

Added: sandbox/big_number/libs/multiprecision/test/compile_fail/conv_fail_47.cpp
==============================================================================
--- (empty file)
+++ sandbox/big_number/libs/multiprecision/test/compile_fail/conv_fail_47.cpp 2012-08-19 12:39:24 EDT (Sun, 19 Aug 2012)
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2012 John Maddock. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifdef TEST_GMP
+
+#include <boost/multiprecision/gmp.hpp>
+
+using namespace boost::multiprecision;
+
+void foo(mpf_float_50);
+
+int main()
+{
+ mpf_float_100 f(2);
+ foo(f);
+}
+
+#else
+
+#error "Nothing to test without GMP!"
+
+#endif

Added: sandbox/big_number/libs/multiprecision/test/compile_fail/conv_fail_48.cpp
==============================================================================
--- (empty file)
+++ sandbox/big_number/libs/multiprecision/test/compile_fail/conv_fail_48.cpp 2012-08-19 12:39:24 EDT (Sun, 19 Aug 2012)
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2012 John Maddock. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifdef TEST_GMP
+
+#include <boost/multiprecision/gmp.hpp>
+
+using namespace boost::multiprecision;
+
+int main()
+{
+ mpf_float_100 f(2);
+ mpf_float_50 f2;
+ f2 = f;
+}
+
+#else
+
+#error "Nothing to test without GMP!"
+
+#endif

Modified: sandbox/big_number/libs/multiprecision/test/test_gmp_conversions.cpp
==============================================================================
--- sandbox/big_number/libs/multiprecision/test/test_gmp_conversions.cpp (original)
+++ sandbox/big_number/libs/multiprecision/test/test_gmp_conversions.cpp 2012-08-19 12:39:24 EDT (Sun, 19 Aug 2012)
@@ -86,16 +86,17 @@
    BOOST_TEST(mpz_int(mpz) == 2);
    BOOST_TEST(mpz_int(mpq) == 2);
    iz = 3;
- iz = mpf;
+ iz = mpz_int(mpf); // explicit conversion only
    BOOST_TEST(iz == 2);
    iz = 3;
    iz = mpz;
    BOOST_TEST(iz == 2);
    iz = 4;
- iz = mpq;
+ iz = mpz_int(mpq); // explicit conversion only
    BOOST_TEST(iz == 2);
    f0 = 2;
    f50 = 2;
+
    BOOST_TEST(mpz_int(f0) == 2);
    BOOST_TEST(mpz_int(f50) == 2);
    rat = 2;
@@ -128,6 +129,24 @@
    iz = denominator(rat);
    BOOST_TEST(iz == 1);
 
+ //
+ // Conversions involving precision only,
+ // note that mpf_t precisions are only approximate:
+ //
+ mpf_float::default_precision(30);
+ f50 = 2;
+ mpf_float_100 f100(3);
+ mpf_float f0a(4);
+ mpf_float f0b(f100);
+ BOOST_TEST(f0a.precision() >= 30);
+ BOOST_TEST(f0b.precision() >= 100);
+ f0a = f100;
+ BOOST_TEST(f0a == 3);
+ BOOST_TEST(f0a.precision() >= 100);
+
+ f100 = f50;
+ BOOST_TEST(f100 == 2);
+
    return boost::report_errors();
 }
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk