• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright John Maddock 2012.
2 
3 // Use, modification and distribution are subject to the
4 // Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt
6 // or copy at http://www.boost.org/LICENSE_1_0.txt)
7 
8 #ifdef _MSC_VER
9 #define _SCL_SECURE_NO_WARNINGS
10 #endif
11 
12 #include <boost/config.hpp>
13 #include <vector>
14 
15 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
16 
17 #if !defined(TEST_GMP) && !defined(TEST_MPFR) && !defined(TEST_TOMMATH) && !defined(TEST_CPP_INT) && !defined(TEST_MPC)
18 #define TEST_GMP
19 #define TEST_MPFR
20 #define TEST_TOMMATH
21 #define TEST_CPP_INT
22 #define TEST_MPC
23 
24 #ifdef _MSC_VER
25 #pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!")
26 #endif
27 #ifdef __GNUC__
28 #pragma warning "CAUTION!!: No backend type specified so testing everything.... this will take some time!!"
29 #endif
30 
31 #endif
32 
33 #if defined(TEST_GMP)
34 #include <boost/multiprecision/gmp.hpp>
35 #endif
36 #if defined(TEST_MPFR)
37 #include <boost/multiprecision/mpfr.hpp>
38 #endif
39 #ifdef TEST_TOMMATH
40 #include <boost/multiprecision/tommath.hpp>
41 #endif
42 #ifdef TEST_CPP_INT
43 #include <boost/multiprecision/cpp_int.hpp>
44 #endif
45 #ifdef TEST_MPC
46 #include <boost/multiprecision/mpc.hpp>
47 #endif
48 
49 #include "test.hpp"
50 
51 unsigned allocation_count = 0;
52 
53 void* (*alloc_func_ptr)(size_t);
54 void* (*realloc_func_ptr)(void*, size_t, size_t);
55 void (*free_func_ptr)(void*, size_t);
56 
alloc_func(size_t n)57 void* alloc_func(size_t n)
58 {
59    ++allocation_count;
60    return (*alloc_func_ptr)(n);
61 }
62 
free_func(void * p,size_t n)63 void free_func(void* p, size_t n)
64 {
65    (*free_func_ptr)(p, n);
66 }
67 
realloc_func(void * p,size_t old,size_t n)68 void* realloc_func(void* p, size_t old, size_t n)
69 {
70    ++allocation_count;
71    return (*realloc_func_ptr)(p, old, n);
72 }
73 
74 template <class T>
do_something(const T &)75 void do_something(const T&)
76 {
77 }
78 
79 template <class T>
test_std_lib()80 void test_std_lib()
81 {
82    std::vector<T> v;
83    for (unsigned i = 0; i < 100; ++i)
84       v.insert(v.begin(), i);
85 
86    T a(2), b(3);
87    std::swap(a, b);
88    BOOST_TEST(a == 3);
89    BOOST_TEST(b == 2);
90 }
91 
92 template <class T, class A>
test_move_and_assign(T x,A val)93 void test_move_and_assign(T x, A val)
94 {
95    // move away from x, then assign val to x.
96    T z(x);
97    T y(std::move(x));
98    x.assign(val);
99    BOOST_CHECK_EQUAL(x, T(val));
100    BOOST_CHECK_EQUAL(z, y);
101 }
102 
103 template <class T>
test_move_and_assign()104 void test_move_and_assign()
105 {
106    T x(23);
107    test_move_and_assign(x, static_cast<short>(2));
108    test_move_and_assign(x, static_cast<int>(2));
109    test_move_and_assign(x, static_cast<long>(2));
110    test_move_and_assign(x, static_cast<long long>(2));
111    test_move_and_assign(x, static_cast<unsigned short>(2));
112    test_move_and_assign(x, static_cast<unsigned int>(2));
113    test_move_and_assign(x, static_cast<unsigned long>(2));
114    test_move_and_assign(x, static_cast<unsigned long long>(2));
115    test_move_and_assign(x, static_cast<float>(2));
116    test_move_and_assign(x, static_cast<double>(2));
117    test_move_and_assign(x, static_cast<long double>(2));
118    test_move_and_assign(x, x);
119    test_move_and_assign(x, "23");
120 }
121 
main()122 int main()
123 {
124 #if defined(TEST_MPFR) || defined(TEST_GMP)
125 #if defined(MPFR_VERSION) && (MPFR_VERSION_MAJOR > 3)
126    mpfr_mp_memory_cleanup();
127 #endif
128    mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
129    mp_set_memory_functions(&alloc_func, &realloc_func, &free_func);
130 #endif
131 
132    using namespace boost::multiprecision;
133 
134 #ifdef TEST_MPFR
135    {
136       test_std_lib<mpfr_float_50>();
137       mpfr_float_50 a = 2;
138       if (allocation_count)
139       {
140          //
141          // We can only conduct meaningful tests if we're actually using our custom allocators,
142          // there are some situations where mpfr-4.x doesn't call them even though we've
143          // done everything requested to make them work....
144          //
145          allocation_count = 0;
146          mpfr_float_50 b  = std::move(a);
147          BOOST_TEST(allocation_count == 0);
148          //
149          // Move assign - we rely on knowledge of the internals to make this test work!!
150          //
151          mpfr_float_50 c(3);
152          do_something(b);
153          do_something(c);
154          const void* p = b.backend().data()[0]._mpfr_d;
155          BOOST_TEST(c.backend().data()[0]._mpfr_d != p);
156          c = std::move(b);
157          BOOST_TEST(c.backend().data()[0]._mpfr_d == p);
158          BOOST_TEST(b.backend().data()[0]._mpfr_d != p);
159          //
160          // Again with variable precision, this we can test more easily:
161          //
162          mpfr_float d, e;
163          d.precision(100);
164          e.precision(1000);
165          d                = 2;
166          e                = 3;
167          allocation_count = 0;
168          BOOST_TEST(d == 2);
169          d = std::move(e);
170          BOOST_TEST(allocation_count == 0);
171          BOOST_TEST(d == 3);
172          e = 2;
173          BOOST_TEST(e == 2);
174          d = std::move(e);
175          e = d;
176          BOOST_TEST(e == d);
177 
178          test_move_and_assign<mpfr_float>();
179          test_move_and_assign<mpfr_float_50>();
180       }
181    }
182 #endif
183 #ifdef TEST_MPC
184    {
185       test_std_lib<mpc_complex_50>();
186       mpc_complex_50 a = 2;
187       if (allocation_count)
188       {
189          //
190          // We can only conduct meaningful tests if we're actually using our custom allocators,
191          // there are some situations where mpfr-4.x doesn't call them even though we've
192          // done everything requested to make them work....
193          //
194          allocation_count = 0;
195          mpc_complex_50 b = std::move(a);
196          BOOST_TEST(allocation_count == 0);
197          //
198          // Move assign - we rely on knowledge of the internals to make this test work!!
199          //
200          mpc_complex_50 c(3);
201          do_something(b);
202          do_something(c);
203          //
204          // Again with variable precision, this we can test more easily:
205          //
206          mpc_complex d, e;
207          d.precision(100);
208          e.precision(1000);
209          d                = 2;
210          e                = 3;
211          allocation_count = 0;
212          BOOST_TEST(d == 2);
213          d = std::move(e);
214          BOOST_TEST(allocation_count == 0);
215          BOOST_TEST(d == 3);
216          e = 2;
217          BOOST_TEST(e == 2);
218          d = std::move(e);
219          e = d;
220          BOOST_TEST(e == d);
221 
222          test_move_and_assign<mpc_complex>();
223          test_move_and_assign<mpc_complex_50>();
224       }
225    }
226 #endif
227 #ifdef TEST_GMP
228    {
229       test_std_lib<mpf_float_50>();
230       mpf_float_50 a = 2;
231       BOOST_TEST(allocation_count); // sanity check that we are tracking allocations
232       allocation_count = 0;
233       mpf_float_50 b   = std::move(a);
234       BOOST_TEST(allocation_count == 0);
235       //
236       // Move assign: this requires knowledge of the internals to test!!
237       //
238       mpf_float_50 c(3);
239       do_something(b);
240       do_something(c);
241       const void* p = b.backend().data()[0]._mp_d;
242       BOOST_TEST(c.backend().data()[0]._mp_d != p);
243       c = std::move(b);
244       BOOST_TEST(c.backend().data()[0]._mp_d == p);
245       BOOST_TEST(b.backend().data()[0]._mp_d != p);
246       //
247       // Again with variable precision, this we can test more easily:
248       //
249       mpf_float d, e;
250       d.precision(100);
251       e.precision(1000);
252       d                = 2;
253       e                = 3;
254       allocation_count = 0;
255       BOOST_TEST(d == 2);
256       d = std::move(e);
257       BOOST_TEST(allocation_count == 0);
258       BOOST_TEST(d == 3);
259       e = 2;
260       BOOST_TEST(e == 2);
261       d = std::move(e);
262       e = d;
263       BOOST_TEST(e == d);
264 
265       test_move_and_assign<mpf_float>();
266       test_move_and_assign<mpf_float_50>();
267    }
268    {
269       test_std_lib<mpz_int>();
270       mpz_int a = 2;
271       BOOST_TEST(allocation_count); // sanity check that we are tracking allocations
272       allocation_count = 0;
273       mpz_int b        = std::move(a);
274       BOOST_TEST(allocation_count == 0);
275 
276       //
277       // Move assign:
278       //
279       mpz_int d, e;
280       d = 2;
281       d <<= 1000;
282       e                = 3;
283       allocation_count = 0;
284       e                = std::move(d);
285       BOOST_TEST(allocation_count == 0);
286       e = 2;
287       BOOST_TEST(e == 2);
288       d = std::move(e);
289       e = d;
290       BOOST_TEST(e == d);
291 
292       test_move_and_assign<mpz_int>();
293    }
294    {
295       test_std_lib<mpq_rational>();
296       mpq_rational a = 2;
297       BOOST_TEST(allocation_count); // sanity check that we are tracking allocations
298       allocation_count = 0;
299       mpq_rational b   = std::move(a);
300       BOOST_TEST(allocation_count == 0);
301 
302       //
303       // Move assign:
304       //
305       mpq_rational d, e;
306       d                = mpz_int(2) << 1000;
307       e                = 3;
308       allocation_count = 0;
309       e                = std::move(d);
310       BOOST_TEST(allocation_count == 0);
311       d = 2;
312       BOOST_TEST(d == 2);
313       d = std::move(e);
314       e = d;
315       BOOST_TEST(e == d);
316 
317       test_move_and_assign<mpq_rational>();
318    }
319 #endif
320 #ifdef TEST_TOMMATH
321    {
322       test_std_lib<tom_int>();
323       tom_int     a = 2;
324       void const* p = a.backend().data().dp;
325       tom_int     b = std::move(a);
326       BOOST_TEST(b.backend().data().dp == p);
327       // We can't test this, as it will assert inside data():
328       //BOOST_TEST(a.backend().data().dp == 0);
329 
330       //
331       // Move assign:
332       //
333       tom_int d, e;
334       d = 2;
335       d <<= 1000;
336       e = 3;
337       p = d.backend().data().dp;
338       BOOST_TEST(p != e.backend().data().dp);
339       e = std::move(d);
340       BOOST_TEST(e.backend().data().dp == p);
341       d = 2;
342       BOOST_TEST(d == 2);
343       d = std::move(e);
344       e = d;
345       BOOST_TEST(e == d);
346 
347       test_move_and_assign<tom_int>();
348    }
349 #endif
350 #ifdef TEST_CPP_INT
351    {
352       test_std_lib<cpp_int>();
353       cpp_int a = 2;
354       a <<= 1000; // Force dynamic allocation.
355       void const* p = a.backend().limbs();
356       cpp_int     b = std::move(a);
357       BOOST_TEST(b.backend().limbs() == p);
358 
359       //
360       // Move assign:
361       //
362       cpp_int d, e;
363       d = 2;
364       d <<= 1000;
365       e = 3;
366       e <<= 1000;
367       p = d.backend().limbs();
368       BOOST_TEST(p != e.backend().limbs());
369       e = std::move(d);
370       BOOST_TEST(e.backend().limbs() == p);
371       d = 2;
372       BOOST_TEST(d == 2);
373       d = std::move(e);
374       e = d;
375       BOOST_TEST(e == d);
376 
377       test_move_and_assign<cpp_int>();
378       test_move_and_assign<int512_t>();
379    }
380 #endif
381    return boost::report_errors();
382 }
383 
384 #else
385 //
386 // No rvalue refs, nothing to test:
387 //
main()388 int main()
389 {
390    return 0;
391 }
392 
393 #endif
394