$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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();
 }