C++11

Marc Glisse marc.glisse at inria.fr
Sun Sep 25 20:00:19 CEST 2011


Hello,

I am thinking of committing something like the attached patch, for C++11. 
I already added simple swap functions, so move constructors and assignment 
operators look like the low-hanging fruits.

Thanks to the earlier change to make some conversions explicit, 
std::common_type should work automatically without specializations for 
mp*_class (I'll add tests of course). It will likely require 
specializations if we want it to work on expressions though (not sure yet 
if that's needed).

More functions could be marked as noexcept at some point (like 
mpz_class::get_mpz_t), but it doesn't seem so useful. operator=(unsigned) 
(and others like it) are not marked noexcept, for the same reason that 
mpz_set_ui is not __GMP_NOTHROW.

The test on C++11 should probably move to gmp.h (and __GMP_NOTHROW become 
noexcept in that case (not that it would likely change anything)), be 
renamed to GMP_USE_CXX11 and be documented.

If you have comments on the approach, or on other C++11 features that 
would help... (note that there are still many improvements possible 
without using new C++ features, which have a higher priority)


-- 
Marc Glisse
-------------- next part --------------
diff -r 02b32281da81 gmpxx.h
--- a/gmpxx.h	Wed Sep 21 15:05:45 2011 +0200
+++ b/gmpxx.h	Thu Sep 22 16:09:10 2011 +0200
@@ -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)
 
@@ -1407,6 +1419,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); }
@@ -1451,11 +1467,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; }
@@ -1568,6 +1588,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); }
@@ -1626,11 +1650,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; }
@@ -1744,6 +1774,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>
@@ -1833,11 +1867,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; }
@@ -2971,7 +3009,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 02b32281da81 tests/cxx/Makefile.am
--- a/tests/cxx/Makefile.am	Wed Sep 21 15:05:45 2011 +0200
+++ b/tests/cxx/Makefile.am	Thu Sep 22 16:09:10 2011 +0200
@@ -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 02b32281da81 tests/cxx/t-cxx11.cc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cxx/t-cxx11.cc	Thu Sep 22 16:09:10 2011 +0200
@@ -0,0 +1,108 @@
+/* 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>
+
+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");
+}
+
+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)
+{
+  tests_start();
+
+  check_noexcept();
+  check_move_init<mpz_class>();
+  check_move_init<mpq_class>();
+  check_move_init<mpf_class>();
+  check_move_assign<mpz_class>();
+  check_move_assign<mpq_class>();
+  check_move_assign<mpf_class>();
+  check_move_init<mpz_class,mpq_class>();
+  check_move_assign<mpz_class,mpq_class>();
+
+  tests_end();
+  return 0;
+}
+
+#else
+int main () { return 0; }
+#endif


More information about the gmp-discuss mailing list