394 lines
10 KiB
C++
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
|