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