multiprecision/test/test_move.cpp

394 lines
10 KiB
C++

// 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 <boost/config.hpp>
#include <vector>
#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 <boost/multiprecision/gmp.hpp>
#endif
#if defined(TEST_MPFR)
#include <boost/multiprecision/mpfr.hpp>
#endif
#ifdef TEST_TOMMATH
#include <boost/multiprecision/tommath.hpp>
#endif
#ifdef TEST_CPP_INT
#include <boost/multiprecision/cpp_int.hpp>
#endif
#ifdef TEST_MPC
#include <boost/multiprecision/mpc.hpp>
#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 <class T>
void do_something(const T&)
{
}
template <class T>
void test_std_lib()
{
std::vector<T> 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 <class T, class A>
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 <class T>
void test_move_and_assign()
{
T x(23);
test_move_and_assign(x, static_cast<short>(2));
test_move_and_assign(x, static_cast<int>(2));
test_move_and_assign(x, static_cast<long>(2));
test_move_and_assign(x, static_cast<long long>(2));
test_move_and_assign(x, static_cast<unsigned short>(2));
test_move_and_assign(x, static_cast<unsigned int>(2));
test_move_and_assign(x, static_cast<unsigned long>(2));
test_move_and_assign(x, static_cast<unsigned long long>(2));
test_move_and_assign(x, static_cast<float>(2));
test_move_and_assign(x, static_cast<double>(2));
test_move_and_assign(x, static_cast<long double>(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>();
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<mpfr_float>();
test_move_and_assign<mpfr_float_50>();
}
}
#endif
#ifdef TEST_MPC
{
test_std_lib<mpc_complex_50>();
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<mpc_complex>();
test_move_and_assign<mpc_complex_50>();
}
}
#endif
#ifdef TEST_GMP
{
test_std_lib<mpf_float_50>();
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<mpf_float>();
test_move_and_assign<mpf_float_50>();
}
{
test_std_lib<mpz_int>();
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<mpz_int>();
}
{
test_std_lib<mpq_rational>();
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<mpq_rational>();
}
#endif
#ifdef TEST_TOMMATH
{
test_std_lib<tom_int>();
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<tom_int>();
}
#endif
#ifdef TEST_CPP_INT
{
test_std_lib<cpp_int>();
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<cpp_int>();
test_move_and_assign<int512_t>();
}
#endif
return boost::report_errors();
}
#else
//
// No rvalue refs, nothing to test:
//
int main()
{
return 0;
}
#endif