// Copyright John Maddock 2012. // Use, modification and distribution are subject to 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 _MSC_VER #define _SCL_SECURE_NO_WARNINGS #endif #include #include #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #if !defined(TEST_GMP) && !defined(TEST_MPFR) && !defined(TEST_TOMMATH) && !defined(TEST_CPP_INT) && !defined(TEST_MPC) #define TEST_GMP #define TEST_MPFR #define TEST_TOMMATH #define TEST_CPP_INT #define TEST_MPC #ifdef _MSC_VER #pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!") #endif #ifdef __GNUC__ #pragma warning "CAUTION!!: No backend type specified so testing everything.... this will take some time!!" #endif #endif #if defined(TEST_GMP) #include #endif #if defined(TEST_MPFR) #include #endif #ifdef TEST_TOMMATH #include #endif #ifdef TEST_CPP_INT #include #endif #ifdef TEST_MPC #include #endif #include "test.hpp" unsigned allocation_count = 0; void* (*alloc_func_ptr)(size_t); void* (*realloc_func_ptr)(void*, size_t, size_t); void (*free_func_ptr)(void*, size_t); void* alloc_func(size_t n) { ++allocation_count; return (*alloc_func_ptr)(n); } void free_func(void* p, size_t n) { (*free_func_ptr)(p, n); } void* realloc_func(void* p, size_t old, size_t n) { ++allocation_count; return (*realloc_func_ptr)(p, old, n); } template void do_something(const T&) { } template void test_std_lib() { std::vector v; for (unsigned i = 0; i < 100; ++i) v.insert(v.begin(), i); T a(2), b(3); std::swap(a, b); BOOST_TEST(a == 3); BOOST_TEST(b == 2); } template void test_move_and_assign(T x, A val) { // move away from x, then assign val to x. T z(x); T y(std::move(x)); x.assign(val); BOOST_CHECK_EQUAL(x, T(val)); BOOST_CHECK_EQUAL(z, y); } template void test_move_and_assign() { T x(23); test_move_and_assign(x, static_cast(2)); test_move_and_assign(x, static_cast(2)); test_move_and_assign(x, static_cast(2)); test_move_and_assign(x, static_cast(2)); test_move_and_assign(x, static_cast(2)); test_move_and_assign(x, static_cast(2)); test_move_and_assign(x, static_cast(2)); test_move_and_assign(x, static_cast(2)); test_move_and_assign(x, static_cast(2)); test_move_and_assign(x, static_cast(2)); test_move_and_assign(x, static_cast(2)); test_move_and_assign(x, x); test_move_and_assign(x, "23"); } int main() { #if defined(TEST_MPFR) || defined(TEST_GMP) #if defined(MPFR_VERSION) && (MPFR_VERSION_MAJOR > 3) mpfr_mp_memory_cleanup(); #endif mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr); mp_set_memory_functions(&alloc_func, &realloc_func, &free_func); #endif using namespace boost::multiprecision; #ifdef TEST_MPFR { test_std_lib(); mpfr_float_50 a = 2; if (allocation_count) { // // We can only conduct meaningful tests if we're actually using our custom allocators, // there are some situations where mpfr-4.x doesn't call them even though we've // done everything requested to make them work.... // allocation_count = 0; mpfr_float_50 b = std::move(a); BOOST_TEST(allocation_count == 0); // // Move assign - we rely on knowledge of the internals to make this test work!! // mpfr_float_50 c(3); do_something(b); do_something(c); const void* p = b.backend().data()[0]._mpfr_d; BOOST_TEST(c.backend().data()[0]._mpfr_d != p); c = std::move(b); BOOST_TEST(c.backend().data()[0]._mpfr_d == p); BOOST_TEST(b.backend().data()[0]._mpfr_d != p); // // Again with variable precision, this we can test more easily: // mpfr_float d, e; d.precision(100); e.precision(1000); d = 2; e = 3; allocation_count = 0; BOOST_TEST(d == 2); d = std::move(e); BOOST_TEST(allocation_count == 0); BOOST_TEST(d == 3); e = 2; BOOST_TEST(e == 2); d = std::move(e); e = d; BOOST_TEST(e == d); test_move_and_assign(); test_move_and_assign(); } } #endif #ifdef TEST_MPC { test_std_lib(); mpc_complex_50 a = 2; if (allocation_count) { // // We can only conduct meaningful tests if we're actually using our custom allocators, // there are some situations where mpfr-4.x doesn't call them even though we've // done everything requested to make them work.... // allocation_count = 0; mpc_complex_50 b = std::move(a); BOOST_TEST(allocation_count == 0); // // Move assign - we rely on knowledge of the internals to make this test work!! // mpc_complex_50 c(3); do_something(b); do_something(c); // // Again with variable precision, this we can test more easily: // mpc_complex d, e; d.precision(100); e.precision(1000); d = 2; e = 3; allocation_count = 0; BOOST_TEST(d == 2); d = std::move(e); BOOST_TEST(allocation_count == 0); BOOST_TEST(d == 3); e = 2; BOOST_TEST(e == 2); d = std::move(e); e = d; BOOST_TEST(e == d); test_move_and_assign(); test_move_and_assign(); } } #endif #ifdef TEST_GMP { test_std_lib(); mpf_float_50 a = 2; BOOST_TEST(allocation_count); // sanity check that we are tracking allocations allocation_count = 0; mpf_float_50 b = std::move(a); BOOST_TEST(allocation_count == 0); // // Move assign: this requires knowledge of the internals to test!! // mpf_float_50 c(3); do_something(b); do_something(c); const void* p = b.backend().data()[0]._mp_d; BOOST_TEST(c.backend().data()[0]._mp_d != p); c = std::move(b); BOOST_TEST(c.backend().data()[0]._mp_d == p); BOOST_TEST(b.backend().data()[0]._mp_d != p); // // Again with variable precision, this we can test more easily: // mpf_float d, e; d.precision(100); e.precision(1000); d = 2; e = 3; allocation_count = 0; BOOST_TEST(d == 2); d = std::move(e); BOOST_TEST(allocation_count == 0); BOOST_TEST(d == 3); e = 2; BOOST_TEST(e == 2); d = std::move(e); e = d; BOOST_TEST(e == d); test_move_and_assign(); test_move_and_assign(); } { test_std_lib(); mpz_int a = 2; BOOST_TEST(allocation_count); // sanity check that we are tracking allocations allocation_count = 0; mpz_int b = std::move(a); BOOST_TEST(allocation_count == 0); // // Move assign: // mpz_int d, e; d = 2; d <<= 1000; e = 3; allocation_count = 0; e = std::move(d); BOOST_TEST(allocation_count == 0); e = 2; BOOST_TEST(e == 2); d = std::move(e); e = d; BOOST_TEST(e == d); test_move_and_assign(); } { test_std_lib(); mpq_rational a = 2; BOOST_TEST(allocation_count); // sanity check that we are tracking allocations allocation_count = 0; mpq_rational b = std::move(a); BOOST_TEST(allocation_count == 0); // // Move assign: // mpq_rational d, e; d = mpz_int(2) << 1000; e = 3; allocation_count = 0; e = std::move(d); BOOST_TEST(allocation_count == 0); d = 2; BOOST_TEST(d == 2); d = std::move(e); e = d; BOOST_TEST(e == d); test_move_and_assign(); } #endif #ifdef TEST_TOMMATH { test_std_lib(); tom_int a = 2; void const* p = a.backend().data().dp; tom_int b = std::move(a); BOOST_TEST(b.backend().data().dp == p); // We can't test this, as it will assert inside data(): //BOOST_TEST(a.backend().data().dp == 0); // // Move assign: // tom_int d, e; d = 2; d <<= 1000; e = 3; p = d.backend().data().dp; BOOST_TEST(p != e.backend().data().dp); e = std::move(d); BOOST_TEST(e.backend().data().dp == p); d = 2; BOOST_TEST(d == 2); d = std::move(e); e = d; BOOST_TEST(e == d); test_move_and_assign(); } #endif #ifdef TEST_CPP_INT { test_std_lib(); cpp_int a = 2; a <<= 1000; // Force dynamic allocation. void const* p = a.backend().limbs(); cpp_int b = std::move(a); BOOST_TEST(b.backend().limbs() == p); // // Move assign: // cpp_int d, e; d = 2; d <<= 1000; e = 3; e <<= 1000; p = d.backend().limbs(); BOOST_TEST(p != e.backend().limbs()); e = std::move(d); BOOST_TEST(e.backend().limbs() == p); d = 2; BOOST_TEST(d == 2); d = std::move(e); e = d; BOOST_TEST(e == d); test_move_and_assign(); test_move_and_assign(); } #endif return boost::report_errors(); } #else // // No rvalue refs, nothing to test: // int main() { return 0; } #endif