[Gmp-commit] /var/hg/gmp: Initial C++11 support.

mercurial at gmplib.org mercurial at gmplib.org
Mon Jan 30 23:59:52 CET 2012


details:   /var/hg/gmp/rev/d7351c2ba64c
changeset: 14592:d7351c2ba64c
user:      Marc Glisse <marc.glisse at inria.fr>
date:      Mon Jan 30 23:59:39 2012 +0100
description:
Initial C++11 support.

diffstat:

 ChangeLog             |   11 +++
 gmpxx.h               |   51 ++++++++++++++++--
 tests/cxx/Makefile.am |    6 +-
 tests/cxx/t-cxx11.cc  |  139 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 199 insertions(+), 8 deletions(-)

diffs (truncated from 320 to 300 lines):

diff -r 2b74427c67b0 -r d7351c2ba64c ChangeLog
--- a/ChangeLog	Mon Jan 30 16:30:26 2012 +0100
+++ b/ChangeLog	Mon Jan 30 23:59:39 2012 +0100
@@ -1,3 +1,14 @@
+2012-02-01  Marc Glisse  <marc.glisse at inria.fr>
+
+	* gmpxx.h (__gmp_unary_expr): Make the constructor explicit.
+	(__gmp_expr(__gmp_expr&&)): New move constructors.
+	(__gmp_expr::operator=(__gmp_expr&&)): New move assignments.
+	(swap): Mark as noexcept.
+	(__GMPXX_USE_CXX11): New macro.
+	(__GMPXX_NOEXCEPT): New macro.
+	* tests/cxx/t-cxx11.cc: New file.
+	* tests/cxx/Makefile.am: Added t-cxx11.
+
 2012-01-30  Torbjorn Granlund  <tege at gmplib.org>
 
 	* tests/mpz/t-powm.c: Ensure all sizes are seen.
diff -r 2b74427c67b0 -r d7351c2ba64c gmpxx.h
--- a/gmpxx.h	Mon Jan 30 16:30:26 2012 +0100
+++ b/gmpxx.h	Mon Jan 30 23:59:39 2012 +0100
@@ -48,6 +48,18 @@
 #define __GMPXX_CONSTANT(X) false
 #endif
 
+// Use C++11 features
+#ifndef __GMPXX_USE_CXX11
+#if (__cplusplus >= 201103L) \
+    || (__GMP_GNUC_PREREQ(4, 6) && defined __GXX_EXPERIMENTAL_CXX0X__)
+#define __GMPXX_USE_CXX11 1
+#define __GMPXX_NOEXCEPT noexcept
+#else
+#define __GMPXX_USE_CXX11 0
+#define __GMPXX_NOEXCEPT
+#endif
+#endif
+
 // Max allocations for plain types when converted to mpz_t
 #define __GMPZ_DBL_LIMBS (2 + DBL_MAX_EXP / GMP_NUMB_BITS)
 
@@ -1412,6 +1424,10 @@
   __gmp_expr() { mpz_init(mp); }
 
   __gmp_expr(const __gmp_expr &z) { mpz_init_set(mp, z.mp); }
+#if __GMPXX_USE_CXX11
+  __gmp_expr(__gmp_expr &&z)
+  { *mp = *z.mp; mpz_init(z.mp); }
+#endif
   template <class T>
   __gmp_expr(const __gmp_expr<mpz_t, T> &expr)
   { mpz_init(mp); __gmp_set_expr(mp, expr); }
@@ -1456,11 +1472,15 @@
 
   ~__gmp_expr() { mpz_clear(mp); }
 
-  void swap(__gmp_expr& z) { std::swap(*mp, *z.mp); }
+  void swap(__gmp_expr& z) __GMPXX_NOEXCEPT { std::swap(*mp, *z.mp); }
 
   // assignment operators
   __gmp_expr & operator=(const __gmp_expr &z)
   { mpz_set(mp, z.mp); return *this; }
+#if __GMPXX_USE_CXX11
+  __gmp_expr & operator=(__gmp_expr &&z) noexcept
+  { swap(z); return *this; }
+#endif
   template <class T, class U>
   __gmp_expr<value_type, value_type> & operator=(const __gmp_expr<T, U> &expr)
   { __gmp_set_expr(mp, expr); return *this; }
@@ -1573,6 +1593,10 @@
     mpz_init_set(mpq_numref(mp), mpq_numref(q.mp));
     mpz_init_set(mpq_denref(mp), mpq_denref(q.mp));
   }
+#if __GMPXX_USE_CXX11
+  __gmp_expr(__gmp_expr &&q)
+  { *mp = *q.mp; mpq_init(q.mp); }
+#endif
   template <class T>
   __gmp_expr(const __gmp_expr<mpz_t, T> &expr)
   { mpq_init(mp); __gmp_set_expr(mp, expr); }
@@ -1631,11 +1655,17 @@
 
   ~__gmp_expr() { mpq_clear(mp); }
 
-  void swap(__gmp_expr& q) { std::swap(*mp, *q.mp); }
+  void swap(__gmp_expr& q) __GMPXX_NOEXCEPT { std::swap(*mp, *q.mp); }
 
   // assignment operators
   __gmp_expr & operator=(const __gmp_expr &q)
   { mpq_set(mp, q.mp); return *this; }
+#if __GMPXX_USE_CXX11
+  __gmp_expr & operator=(__gmp_expr &&q) noexcept
+  { swap(q); return *this; }
+  __gmp_expr & operator=(mpz_class &&z) noexcept
+  { get_num() = std::move(z); get_den() = 1u; return *this; }
+#endif
   template <class T, class U>
   __gmp_expr<value_type, value_type> & operator=(const __gmp_expr<T, U> &expr)
   { __gmp_set_expr(mp, expr); return *this; }
@@ -1749,6 +1779,10 @@
 
   __gmp_expr(const __gmp_expr &f)
   { mpf_init2(mp, f.get_prec()); mpf_set(mp, f.mp); }
+#if __GMPXX_USE_CXX11
+  __gmp_expr(__gmp_expr &&f)
+  { *mp = *f.mp; mpf_init2(f.mp, get_prec()); }
+#endif
   __gmp_expr(const __gmp_expr &f, mp_bitcnt_t prec)
   { mpf_init2(mp, prec); mpf_set(mp, f.mp); }
   template <class T, class U>
@@ -1838,11 +1872,15 @@
 
   ~__gmp_expr() { mpf_clear(mp); }
 
-  void swap(__gmp_expr& f) { std::swap(*mp, *f.mp); }
+  void swap(__gmp_expr& f) __GMPXX_NOEXCEPT { std::swap(*mp, *f.mp); }
 
   // assignment operators
   __gmp_expr & operator=(const __gmp_expr &f)
   { mpf_set(mp, f.mp); return *this; }
+#if __GMPXX_USE_CXX11
+  __gmp_expr & operator=(__gmp_expr &&f) noexcept
+  { swap(f); return *this; }
+#endif
   template <class T, class U>
   __gmp_expr<value_type, value_type> & operator=(const __gmp_expr<T, U> &expr)
   { __gmp_set_expr(mp, expr); return *this; }
@@ -2065,7 +2103,7 @@
 
   __gmp_unary_expr<val_type, Op> expr;
 public:
-  __gmp_expr(const val_type &val) : expr(val) { }
+  explicit __gmp_expr(const val_type &val) : expr(val) { }
   void eval(typename __gmp_resolve_expr<T>::ptr_type p,
 	    mp_bitcnt_t = 0) const
   { Op::eval(p, expr.val.__get_mp()); }
@@ -2084,7 +2122,7 @@
 
   __gmp_unary_expr<val_type, Op> expr;
 public:
-  __gmp_expr(const val_type &val) : expr(val) { }
+  explicit __gmp_expr(const val_type &val) : expr(val) { }
   void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
   { expr.val.eval(p); Op::eval(p, p); }
   void eval(typename __gmp_resolve_expr<T>::ptr_type p,
@@ -3008,7 +3046,8 @@
 __GMP_DEFINE_BINARY_TYPE_FUNCTION(int, cmp, __gmp_cmp_function)
 
 template <class T>
-void swap(__gmp_expr<T, T>& x, __gmp_expr<T, T>& y) { x.swap(y); }
+void swap(__gmp_expr<T, T>& x, __gmp_expr<T, T>& y) __GMPXX_NOEXCEPT
+{ x.swap(y); }
 
 // member operators for mpz_class
 
diff -r 2b74427c67b0 -r d7351c2ba64c tests/cxx/Makefile.am
--- a/tests/cxx/Makefile.am	Mon Jan 30 16:30:26 2012 +0100
+++ b/tests/cxx/Makefile.am	Mon Jan 30 23:59:39 2012 +0100
@@ -30,8 +30,9 @@
   $(top_builddir)/libgmp.la
 
 if WANT_CXX
-check_PROGRAMS = t-assign t-binary t-cast t-constr t-headers t-iostream \
-  t-istream t-locale t-misc t-mix t-ops t-ops2 t-ops3 t-ostream t-prec \
+check_PROGRAMS = t-assign t-binary t-cast t-constr t-cxx11 \
+  t-headers t-iostream t-istream t-locale t-misc t-mix \
+  t-ops t-ops2 t-ops3 t-ostream t-prec \
   t-rand t-ternary t-unary
 TESTS = $(check_PROGRAMS)
 endif
@@ -40,6 +41,7 @@
 t_binary_SOURCES  = t-binary.cc
 t_cast_SOURCES    = t-cast.cc
 t_constr_SOURCES  = t-constr.cc
+t_cxx11_SOURCES   = t-cxx11.cc
 t_headers_SOURCES = t-headers.cc
 t_iostream_SOURCES= t-iostream.cc
 t_istream_SOURCES = t-istream.cc
diff -r 2b74427c67b0 -r d7351c2ba64c tests/cxx/t-cxx11.cc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cxx/t-cxx11.cc	Mon Jan 30 23:59:39 2012 +0100
@@ -0,0 +1,139 @@
+/* Test C++11 features
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include "gmp.h"
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if __GMPXX_USE_CXX11
+
+#include <utility>
+#include <type_traits>
+
+void check_noexcept ()
+{
+  mpz_class z1, z2;
+  mpq_class q1, q2;
+  mpf_class f1, f2;
+  // gcc 4.6 is missing noexcept on std::move
+  static_assert(noexcept(z1 = static_cast<mpz_class&&>(z2)), "sorry");
+  static_assert(noexcept(q1 = static_cast<mpq_class&&>(q2)), "sorry");
+  static_assert(noexcept(f1 = static_cast<mpf_class&&>(f2)), "sorry");
+  static_assert(noexcept(q1 = static_cast<mpz_class&&>(z1)), "sorry");
+}
+
+void check_common_type ()
+{
+#define CHECK_COMMON_TYPE(T, U, Res) \
+  static_assert(std::is_same<std::common_type<T, U>::type, Res>::value, "sorry")
+  CHECK_COMMON_TYPE (mpz_class, mpq_class, mpq_class);
+  CHECK_COMMON_TYPE (mpz_class, mpf_class, mpf_class);
+  CHECK_COMMON_TYPE (mpf_class, mpq_class, mpf_class);
+
+  mpz_class z; mpq_class q; mpf_class f;
+
+  CHECK_COMMON_TYPE (decltype(-z), mpz_class, mpz_class);
+  CHECK_COMMON_TYPE (decltype(-q), mpq_class, mpq_class);
+  CHECK_COMMON_TYPE (decltype(-f), mpf_class, mpf_class);
+
+  CHECK_COMMON_TYPE (decltype(-z), mpq_class, mpq_class);
+  CHECK_COMMON_TYPE (decltype(-z), mpf_class, mpf_class);
+  CHECK_COMMON_TYPE (decltype(-q), mpf_class, mpf_class);
+
+  /* Not currently supported
+  CHECK_COMMON_TYPE (decltype(-q), mpz_class, mpq_class);
+  CHECK_COMMON_TYPE (decltype(-f), mpz_class, mpf_class);
+  CHECK_COMMON_TYPE (decltype(-f), mpq_class, mpf_class);
+
+  CHECK_COMMON_TYPE (decltype(-z), decltype(-q), mpq_class);
+  CHECK_COMMON_TYPE (decltype(-z), decltype(-f), mpq_class);
+  CHECK_COMMON_TYPE (decltype(-q), decltype(-f), mpq_class);
+  */
+}
+
+template<class T, class U = T>
+void check_move_init ()
+{
+  {
+    // Delete moved-from x1
+    T x1 = 3;
+    U x2 = std::move(x1);
+    ASSERT_ALWAYS (x2 == 3);
+  }
+  {
+    // Assign to moved-from x1
+    T x1 = 2;
+    U x2 = std::move(x1);
+    x1 = -7;
+    ASSERT_ALWAYS (x1 == -7);
+    ASSERT_ALWAYS (x2 == 2);
+  }
+}
+
+template<class T, class U = T>
+void check_move_assign ()
+{
+  {
+    // Delete moved-from x1
+    T x1 = 3; U x2;
+    x2 = std::move(x1);
+    ASSERT_ALWAYS (x2 == 3);
+  }
+  {
+    // Assign to moved-from x1
+    T x1 = 2; U x2;
+    x2 = std::move(x1);
+    x1 = -7;
+    ASSERT_ALWAYS (x1 == -7);
+    ASSERT_ALWAYS (x2 == 2);
+  }
+  {
+    // Self move-assign (not necessary, but it happens to work...)
+    T x = 4;
+    x = std::move(x);
+    ASSERT_ALWAYS (x == 4);
+  }
+}
+
+int
+main (void)
+{


More information about the gmp-commit mailing list