| /* Test C++11 features |
| |
| Copyright 2011, 2012 Free Software Foundation, Inc. |
| |
| This file is part of the GNU MP Library test suite. |
| |
| The GNU MP Library test suite is free software; you can redistribute it |
| and/or modify it under the terms of the GNU 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 test suite 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 General |
| Public License for more details. |
| |
| You should have received a copy of the GNU General Public License along with |
| the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ |
| |
| #include "config.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; |
| static_assert(noexcept(z1 = std::move(z2)), "sorry"); |
| static_assert(noexcept(q1 = std::move(q2)), "sorry"); |
| static_assert(noexcept(f1 = std::move(f2)), "sorry"); |
| static_assert(noexcept(q1 = std::move(z1)), "sorry"); |
| |
| // Only mpz has lazy allocation for now |
| static_assert(std::is_nothrow_default_constructible<mpz_class>::value, "sorry"); |
| static_assert(std::is_nothrow_move_constructible<mpz_class>::value, "sorry"); |
| static_assert(!std::is_nothrow_default_constructible<mpq_class>::value, "sorry"); |
| static_assert(!std::is_nothrow_move_constructible<mpq_class>::value, "sorry"); |
| static_assert(!std::is_nothrow_default_constructible<mpf_class>::value, "sorry"); |
| static_assert(!std::is_nothrow_move_constructible<mpf_class>::value, "sorry"); |
| } |
| |
| void check_common_type () |
| { |
| #define CHECK_COMMON_TYPE1(T, Res) \ |
| static_assert(std::is_same<std::common_type<T>::type, Res>::value, "sorry") |
| #define CHECK_COMMON_TYPE(T, U, Res) \ |
| static_assert(std::is_same<std::common_type<T, U>::type, Res>::value, "sorry") |
| #define CHECK_COMMON_TYPE_BUILTIN1(T, Res) \ |
| CHECK_COMMON_TYPE( signed char , T, Res); \ |
| CHECK_COMMON_TYPE(unsigned char , T, Res); \ |
| CHECK_COMMON_TYPE( signed short, T, Res); \ |
| CHECK_COMMON_TYPE(unsigned short, T, Res); \ |
| CHECK_COMMON_TYPE( signed int , T, Res); \ |
| CHECK_COMMON_TYPE(unsigned int , T, Res); \ |
| CHECK_COMMON_TYPE( signed long , T, Res); \ |
| CHECK_COMMON_TYPE(unsigned long , T, Res); \ |
| CHECK_COMMON_TYPE(float , T, Res); \ |
| CHECK_COMMON_TYPE(double, T, Res) |
| #define CHECK_COMMON_TYPE_BUILTIN2(T, Res) \ |
| CHECK_COMMON_TYPE(T, signed char , Res); \ |
| CHECK_COMMON_TYPE(T, unsigned char , Res); \ |
| CHECK_COMMON_TYPE(T, signed short, Res); \ |
| CHECK_COMMON_TYPE(T, unsigned short, Res); \ |
| CHECK_COMMON_TYPE(T, signed int , Res); \ |
| CHECK_COMMON_TYPE(T, unsigned int , Res); \ |
| CHECK_COMMON_TYPE(T, signed long , Res); \ |
| CHECK_COMMON_TYPE(T, unsigned long , Res); \ |
| CHECK_COMMON_TYPE(T, float , Res); \ |
| CHECK_COMMON_TYPE(T, double, Res) |
| #define CHECK_COMMON_TYPE_BUILTIN(T, Res) \ |
| CHECK_COMMON_TYPE_BUILTIN1(T, Res); \ |
| CHECK_COMMON_TYPE_BUILTIN2(T, Res) |
| /* These would just work with implicit conversions */ |
| 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); |
| |
| CHECK_COMMON_TYPE_BUILTIN (mpz_class, mpz_class); |
| CHECK_COMMON_TYPE_BUILTIN (mpq_class, mpq_class); |
| CHECK_COMMON_TYPE_BUILTIN (mpf_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); |
| |
| /* These require a common_type specialization */ |
| CHECK_COMMON_TYPE (decltype(-z), decltype(z+z), mpz_class); |
| CHECK_COMMON_TYPE (decltype(-q), decltype(q+q), mpq_class); |
| CHECK_COMMON_TYPE (decltype(-f), decltype(f+f), mpf_class); |
| |
| 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), mpf_class); |
| CHECK_COMMON_TYPE (decltype(-q), decltype(-f), mpf_class); |
| |
| /* common_type now decays */ |
| CHECK_COMMON_TYPE (decltype(-z), decltype(-z), mpz_class); |
| CHECK_COMMON_TYPE (decltype(-q), decltype(-q), mpq_class); |
| CHECK_COMMON_TYPE (decltype(-f), decltype(-f), mpf_class); |
| CHECK_COMMON_TYPE1 (decltype(-z), mpz_class); |
| CHECK_COMMON_TYPE1 (decltype(-q), mpq_class); |
| CHECK_COMMON_TYPE1 (decltype(-f), mpf_class); |
| |
| /* Painful */ |
| CHECK_COMMON_TYPE_BUILTIN (decltype(-z), mpz_class); |
| CHECK_COMMON_TYPE_BUILTIN (decltype(-q), mpq_class); |
| CHECK_COMMON_TYPE_BUILTIN (decltype(-f), mpf_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); |
| } |
| } |
| |
| void check_user_defined_literal () |
| { |
| ASSERT_ALWAYS (123_mpz % 5 == 3); |
| ASSERT_ALWAYS (-11_mpq / 22 == -.5); |
| ASSERT_ALWAYS (112.5e-1_mpf * 4 == 45); |
| { |
| mpz_class ref ( "123456789abcdef0123456789abcdef0123", 16); |
| ASSERT_ALWAYS (0x123456789abcdef0123456789abcdef0123_mpz == ref); |
| } |
| } |
| |
| // Check for explicit conversion to bool |
| void implicit_bool(bool); |
| int implicit_bool(...); |
| |
| void check_bool_conversion () |
| { |
| const mpz_class zn = -2; |
| const mpq_class qn = -2; |
| const mpf_class fn = -2; |
| const mpz_class z0 = 0; |
| const mpq_class q0 = 0; |
| const mpf_class f0 = 0; |
| const mpz_class zp = +2; |
| const mpq_class qp = +2; |
| const mpf_class fp = +2; |
| if (zn && qn && fn && zp && qp && fp && !z0 && !q0 && !f0) |
| { |
| if (z0 || q0 || f0) ASSERT_ALWAYS(false); |
| } |
| else ASSERT_ALWAYS(false); |
| decltype(implicit_bool(zn)) zi = 1; |
| decltype(implicit_bool(qn)) qi = 1; |
| decltype(implicit_bool(fn)) fi = 1; |
| (void)(zi+qi+fi); |
| } |
| |
| 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>(); |
| check_user_defined_literal(); |
| check_bool_conversion(); |
| |
| tests_end(); |
| return 0; |
| } |
| |
| #else |
| int main () { return 0; } |
| #endif |