diff options
author | Marc Glisse <marc.glisse@inria.fr> | 2012-01-30 23:59:39 +0100 |
---|---|---|
committer | Marc Glisse <marc.glisse@inria.fr> | 2012-01-30 23:59:39 +0100 |
commit | a423d2db41e026280cd883e31a20975fa814cb7e (patch) | |
tree | a4f574758ec3c64c0df39e5a3684fb72b0e9d385 | |
parent | 8d49dafc7c996ee3cb08195521e7b8bc49a90b7d (diff) | |
download | gmp-a423d2db41e026280cd883e31a20975fa814cb7e.tar.gz |
Initial C++11 support.
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | gmpxx.h | 51 | ||||
-rw-r--r-- | tests/cxx/Makefile.am | 6 | ||||
-rw-r--r-- | tests/cxx/t-cxx11.cc | 139 |
4 files changed, 199 insertions, 8 deletions
@@ -1,3 +1,14 @@ +2012-02-01 Marc Glisse <marc.glisse@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@gmplib.org> * tests/mpz/t-powm.c: Ensure all sizes are seen. @@ -48,6 +48,18 @@ along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ #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 @@ public: __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 @@ public: ~__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 @@ public: 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 @@ public: ~__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 @@ public: __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 @@ public: ~__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 @@ private: __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 @@ private: __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_UNARY_TYPE_FUNCTION(int, sgn, __gmp_sgn_function) __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 --git a/tests/cxx/Makefile.am b/tests/cxx/Makefile.am index 6e214ab6f..f339519f4 100644 --- a/tests/cxx/Makefile.am +++ b/tests/cxx/Makefile.am @@ -30,8 +30,9 @@ LDADD = -L$(top_builddir)/.libs \ $(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_assign_SOURCES = t-assign.cc 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 --git a/tests/cxx/t-cxx11.cc b/tests/cxx/t-cxx11.cc new file mode 100644 index 000000000..8c4473c03 --- /dev/null +++ b/tests/cxx/t-cxx11.cc @@ -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) +{ + tests_start(); + + check_noexcept(); + check_common_type(); + 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 |