Move libcds 1.6.0 from SVN
[libcds.git] / tests / test-hdr / misc / cxx11_atomic_class.cpp
1 //$$CDS-header$$
2
3 #include "cppunit/cppunit_proxy.h"
4
5 //#define CDS_USE_BOOST_ATOMIC
6 #include <cds/cxx11_atomic.h>
7
8 #include "misc/cxx11_convert_memory_order.h"
9
10 namespace misc {
11     class cxx11_atomic_class: public CppUnitMini::TestCase
12     {
13         template <typename AtomicFlag>
14         void do_test_atomic_flag_mo( AtomicFlag& f, CDS_ATOMIC::memory_order order )
15         {
16             CDS_ATOMIC::memory_order mo_clear = convert_to_store_order(order);
17             for ( int i = 0; i < 5; ++i ) {
18                 CPPUNIT_ASSERT( !f.test_and_set( order ));
19                 CPPUNIT_ASSERT( f.test_and_set( order ) );
20                 f.clear( mo_clear );
21             }
22         }
23
24         template <typename AtomicFlag>
25         void do_test_atomic_flag( AtomicFlag& f)
26         {
27             f.clear();
28
29             for ( int i = 0; i < 5; ++i ) {
30                 CPPUNIT_ASSERT( !f.test_and_set());
31                 CPPUNIT_ASSERT( f.test_and_set() );
32                 f.clear();
33             }
34
35             do_test_atomic_flag_mo( f, CDS_ATOMIC::memory_order_relaxed );
36             do_test_atomic_flag_mo( f, CDS_ATOMIC::memory_order_consume );
37             do_test_atomic_flag_mo( f, CDS_ATOMIC::memory_order_acquire );
38             do_test_atomic_flag_mo( f, CDS_ATOMIC::memory_order_release );
39             do_test_atomic_flag_mo( f, CDS_ATOMIC::memory_order_acq_rel );
40             do_test_atomic_flag_mo( f, CDS_ATOMIC::memory_order_seq_cst );
41         }
42
43         template <class Atomic, typename Integral>
44         void do_test_atomic_type(Atomic& a)
45         {
46             typedef Integral    integral_type;
47
48             CPPUNIT_ASSERT( a.is_lock_free() );
49             a.store( (integral_type) 0 );
50             CPPUNIT_ASSERT( a == 0 );
51             CPPUNIT_ASSERT( a.load() == 0 );
52
53             for ( size_t nByte = 0; nByte < sizeof(Integral); ++nByte ) {
54                 integral_type n = integral_type(42) << (nByte * 8);
55                 CPPUNIT_ASSERT( a.exchange( n ) == 0 );
56                 CPPUNIT_ASSERT( a == n );
57                 CPPUNIT_ASSERT( a.exchange( (integral_type) 0 ) == n );
58                 CPPUNIT_ASSERT( a.load() == 0 );
59             }
60
61             integral_type prev = a.load();
62             for ( size_t nByte = 0; nByte < sizeof(Integral); ++nByte ) {
63                 integral_type n = integral_type(42) << (nByte * 8);
64                 integral_type expected = prev;
65
66                 CPPUNIT_ASSERT( a.compare_exchange_weak( expected, n));
67                 CPPUNIT_ASSERT( expected  == prev );
68                 CPPUNIT_ASSERT( !a.compare_exchange_weak( expected, n));
69                 CPPUNIT_ASSERT( expected  == n );
70
71                 prev = n;
72                 CPPUNIT_ASSERT( a == n );
73             }
74
75             a = (integral_type) 0;
76
77             prev = a;
78             for ( size_t nByte = 0; nByte < sizeof(Integral); ++nByte ) {
79                 integral_type n = integral_type(42) << (nByte * 8);
80                 integral_type expected = prev;
81
82                 CPPUNIT_ASSERT( a.compare_exchange_strong( expected, n));
83                 CPPUNIT_ASSERT( expected  == prev );
84                 CPPUNIT_ASSERT( !a.compare_exchange_strong( expected, n));
85                 CPPUNIT_ASSERT( expected  == n );
86
87                 prev = n;
88                 CPPUNIT_ASSERT( a.load() == n );
89             }
90
91             CPPUNIT_ASSERT( a.exchange( (integral_type) 0 ) == prev );
92         }
93
94         template <class Atomic, typename Integral>
95         void do_test_atomic_integral(Atomic& a)
96         {
97             do_test_atomic_type< Atomic, Integral >(a);
98
99             typedef Integral    integral_type;
100
101             // fetch_xxx testing
102             a.store( (integral_type) 0 );
103
104             // fetch_add
105             for ( size_t nByte = 0; nByte < sizeof(integral_type); ++nByte )
106             {
107                 integral_type prev = a.load();
108                 integral_type n = integral_type(42) << (nByte * 8);
109
110                 CPPUNIT_ASSERT( a.fetch_add(n) == prev);
111             }
112
113             // fetch_sub
114             for ( size_t nByte = sizeof(integral_type); nByte > 0; --nByte )
115             {
116                 integral_type prev = a.load();
117                 integral_type n = integral_type(42) << ((nByte - 1) * 8);
118
119                 CPPUNIT_ASSERT( a.fetch_sub(n) == prev);
120             }
121             CPPUNIT_ASSERT( a.load() == 0 );
122
123             // fetch_or / fetc_xor / fetch_and
124             for ( size_t nBit = 0; nBit < sizeof(integral_type) * 8; ++nBit )
125             {
126                 integral_type prev = a.load()  ;;
127                 integral_type mask = 1 << nBit;
128
129                 CPPUNIT_ASSERT( a.fetch_or( mask ) == prev );
130                 prev = a.load();
131                 CPPUNIT_ASSERT( ( prev & mask)  == mask);
132
133                 CPPUNIT_ASSERT( a.fetch_and( (integral_type) ~mask ) == prev );
134                 prev = a.load();
135                 CPPUNIT_ASSERT( integral_type(prev & mask) == integral_type(0));
136
137                 CPPUNIT_ASSERT( a.fetch_xor( mask ) == prev );
138                 prev = a.load();
139                 CPPUNIT_ASSERT( integral_type( prev & mask)  == mask);
140             }
141             CPPUNIT_ASSERT( a.load() == (integral_type) -1 );
142
143
144             // op= testing
145             a = (integral_type) 0;
146
147             // +=
148             for ( size_t nByte = 0; nByte < sizeof(integral_type); ++nByte )
149             {
150                 integral_type prev = a;
151                 integral_type n = integral_type(42) << (nByte * 8);
152
153                 CPPUNIT_ASSERT( (a += n) == (prev + n));
154             }
155
156             // -=
157             for ( size_t nByte = sizeof(integral_type); nByte > 0; --nByte )
158             {
159                 integral_type prev = a;
160                 integral_type n = integral_type(42) << ((nByte - 1) * 8);
161
162                 CPPUNIT_ASSERT( (a -= n) == prev - n );
163             }
164             CPPUNIT_ASSERT( a.load() == 0 );
165
166             // |= / ^= / &=
167             for ( size_t nBit = 0; nBit < sizeof(integral_type) * 8; ++nBit )
168             {
169                 integral_type prev = a;
170                 integral_type mask = integral_type(1) << nBit;
171
172                 CPPUNIT_ASSERT( (a |= mask ) == (prev | mask ));
173                 prev = a;
174                 CPPUNIT_ASSERT( ( prev & mask)  == mask);
175
176                 CPPUNIT_ASSERT( (a &= (integral_type) ~mask ) == ( prev & (integral_type) ~mask ));
177                 prev = a;
178                 CPPUNIT_ASSERT( ( prev & mask)  == 0);
179
180                 CPPUNIT_ASSERT( (a ^= mask ) == (prev ^ mask ));
181                 prev = a;
182                 CPPUNIT_ASSERT( ( prev & mask)  == mask);
183             }
184             CPPUNIT_ASSERT( a == (integral_type) -1 );
185         }
186
187         template <class Atomic, typename Integral>
188         void do_test_atomic_type( Atomic& a, CDS_ATOMIC::memory_order order )
189         {
190             typedef Integral    integral_type;
191
192             const CDS_ATOMIC::memory_order oLoad = convert_to_load_order( order );
193             const CDS_ATOMIC::memory_order oStore = convert_to_store_order( order );
194
195             CPPUNIT_ASSERT( a.is_lock_free() );
196             a.store((integral_type) 0, oStore );
197             CPPUNIT_ASSERT( a == 0 );
198             CPPUNIT_ASSERT( a.load( oLoad ) == 0 );
199
200             for ( size_t nByte = 0; nByte < sizeof(Integral); ++nByte ) {
201                 integral_type n = integral_type(42) << (nByte * 8);
202                 CPPUNIT_ASSERT( a.exchange( n, order ) == 0 );
203                 CPPUNIT_ASSERT( a.load( oLoad ) == n );
204                 CPPUNIT_ASSERT( a.exchange( (integral_type) 0, order ) == n );
205                 CPPUNIT_ASSERT( a.load( oLoad ) == 0 );
206             }
207
208             integral_type prev = a.load( oLoad );
209             for ( size_t nByte = 0; nByte < sizeof(Integral); ++nByte ) {
210                 integral_type n = integral_type(42) << (nByte * 8);
211                 integral_type expected = prev;
212
213                 CPPUNIT_ASSERT( a.compare_exchange_weak( expected, n, order, CDS_ATOMIC::memory_order_relaxed));
214                 CPPUNIT_ASSERT( expected  == prev );
215                 CPPUNIT_ASSERT( !a.compare_exchange_weak( expected, n, order, CDS_ATOMIC::memory_order_relaxed));
216                 CPPUNIT_ASSERT( expected  == n );
217
218                 prev = n;
219                 CPPUNIT_ASSERT( a.load( oLoad ) == n );
220             }
221
222             a.store( (integral_type) 0, oStore );
223
224             prev = a.load( oLoad );
225             for ( size_t nByte = 0; nByte < sizeof(Integral); ++nByte ) {
226                 integral_type n = integral_type(42) << (nByte * 8);
227                 integral_type expected = prev;
228
229                 CPPUNIT_ASSERT( a.compare_exchange_strong( expected, n, order, CDS_ATOMIC::memory_order_relaxed));
230                 CPPUNIT_ASSERT( expected  == prev );
231                 CPPUNIT_ASSERT( !a.compare_exchange_strong( expected, n, order, CDS_ATOMIC::memory_order_relaxed));
232                 CPPUNIT_ASSERT( expected  == n );
233
234                 prev = n;
235                 CPPUNIT_ASSERT( a.load( oLoad ) == n );
236             }
237
238             CPPUNIT_ASSERT( a.exchange( (integral_type) 0, order ) == prev );
239         }
240
241         template <class Atomic, typename Integral>
242         void do_test_atomic_integral( Atomic& a, CDS_ATOMIC::memory_order order )
243         {
244             do_test_atomic_type< Atomic, Integral >( a, order );
245
246             typedef Integral    integral_type;
247
248             const CDS_ATOMIC::memory_order oLoad = convert_to_load_order( order );
249             const CDS_ATOMIC::memory_order oStore = convert_to_store_order( order );
250
251             // fetch_xxx testing
252             a.store( (integral_type) 0, oStore );
253
254             // fetch_add
255             for ( size_t nByte = 0; nByte < sizeof(integral_type); ++nByte )
256             {
257                 integral_type prev = a.load( oLoad );
258                 integral_type n = integral_type(42) << (nByte * 8);
259
260                 CPPUNIT_ASSERT( a.fetch_add( n, order) == prev);
261             }
262
263             // fetch_sub
264             for ( size_t nByte = sizeof(integral_type); nByte > 0; --nByte )
265             {
266                 integral_type prev = a.load( oLoad );
267                 integral_type n = integral_type(42) << ((nByte - 1) * 8);
268
269                 CPPUNIT_ASSERT( a.fetch_sub( n, order ) == prev);
270             }
271             CPPUNIT_ASSERT( a.load( oLoad ) == 0 );
272
273             // fetch_or / fetc_xor / fetch_and
274             for ( size_t nBit = 0; nBit < sizeof(integral_type) * 8; ++nBit )
275             {
276                 integral_type prev = a.load( oLoad )  ;;
277                 integral_type mask = 1 << nBit;
278
279                 CPPUNIT_ASSERT( a.fetch_or( mask, order ) == prev );
280                 prev = a.load( oLoad );
281                 CPPUNIT_ASSERT( ( prev & mask)  == mask);
282
283                 CPPUNIT_ASSERT( a.fetch_and( (integral_type) ~mask, order ) == prev );
284                 prev = a.load( oLoad );
285                 CPPUNIT_ASSERT( ( prev & mask)  == 0);
286
287                 CPPUNIT_ASSERT( a.fetch_xor( mask, order ) == prev );
288                 prev = a.load( oLoad );
289                 CPPUNIT_ASSERT( ( prev & mask)  == mask);
290             }
291             CPPUNIT_ASSERT( a.load( oLoad ) == (integral_type) -1 );
292         }
293
294
295
296         template <typename Atomic, typename Integral>
297         void test_atomic_integral_(Atomic& a)
298         {
299             do_test_atomic_integral<Atomic, Integral >(a);
300
301             do_test_atomic_integral<Atomic, Integral >( a, CDS_ATOMIC::memory_order_relaxed );
302             do_test_atomic_integral<Atomic, Integral >( a, CDS_ATOMIC::memory_order_consume );
303             do_test_atomic_integral<Atomic, Integral >( a, CDS_ATOMIC::memory_order_acquire );
304             do_test_atomic_integral<Atomic, Integral >( a, CDS_ATOMIC::memory_order_release );
305             do_test_atomic_integral<Atomic, Integral >( a, CDS_ATOMIC::memory_order_acq_rel );
306             do_test_atomic_integral<Atomic, Integral >( a, CDS_ATOMIC::memory_order_seq_cst );
307         }
308
309         template <typename Integral>
310         void test_atomic_integral()
311         {
312             typedef CDS_ATOMIC::atomic<Integral> atomic_type;
313
314             atomic_type a[8];
315             for ( size_t i = 0; i < sizeof(a)/sizeof(a[0]); ++i ) {
316                 test_atomic_integral_<atomic_type, Integral>( a[i] );
317             }
318         }
319         template <typename Integral>
320         void test_atomic_integral_volatile()
321         {
322             typedef CDS_ATOMIC::atomic<Integral> volatile atomic_type;
323
324             atomic_type a[8];
325             for ( size_t i = 0; i < sizeof(a)/sizeof(a[0]); ++i ) {
326                 test_atomic_integral_<atomic_type, Integral>( a[i] );
327             }
328         }
329
330         template <class AtomicBool>
331         void do_test_atomic_bool( AtomicBool& a )
332         {
333             CPPUNIT_ASSERT( a.is_lock_free() );
334             a.store( false );
335             CPPUNIT_ASSERT( a == false );
336             CPPUNIT_ASSERT( a.load() == false );
337
338             CPPUNIT_ASSERT( a.exchange( true ) == false );
339             CPPUNIT_ASSERT( a.load() == true );
340             CPPUNIT_ASSERT( a.exchange( false ) == true );
341             CPPUNIT_ASSERT( a.load() == false );
342
343             bool expected = false;
344             CPPUNIT_ASSERT( a.compare_exchange_weak( expected, true));
345             CPPUNIT_ASSERT( expected  == false );
346             CPPUNIT_ASSERT( !a.compare_exchange_weak( expected, false));
347             CPPUNIT_ASSERT( expected  == true );
348             CPPUNIT_ASSERT( a.load() == true );
349
350             a.store( false );
351
352             expected = false;
353             CPPUNIT_ASSERT( a.compare_exchange_strong( expected, true));
354             CPPUNIT_ASSERT( expected  == false );
355             CPPUNIT_ASSERT( !a.compare_exchange_strong( expected, false));
356             CPPUNIT_ASSERT( expected  == true );
357
358             CPPUNIT_ASSERT( a.load() == true );
359
360             CPPUNIT_ASSERT( a.exchange( false ) == true );
361         }
362
363         template <class AtomicBool>
364         void do_test_atomic_bool( AtomicBool& a, CDS_ATOMIC::memory_order order )
365         {
366             const CDS_ATOMIC::memory_order oLoad = convert_to_load_order( order );
367             const CDS_ATOMIC::memory_order oStore = convert_to_store_order( order );
368
369             CPPUNIT_ASSERT( a.is_lock_free() );
370             a.store( false, oStore );
371             CPPUNIT_ASSERT( a == false );
372             CPPUNIT_ASSERT( a.load( oLoad ) == false );
373
374             CPPUNIT_ASSERT( a.exchange( true, order ) == false );
375             CPPUNIT_ASSERT( a.load( oLoad ) == true );
376             CPPUNIT_ASSERT( a.exchange( false, order ) == true );
377             CPPUNIT_ASSERT( a.load( oLoad ) == false );
378
379             bool expected = false;
380             CPPUNIT_ASSERT( a.compare_exchange_weak( expected, true, order, CDS_ATOMIC::memory_order_relaxed));
381             CPPUNIT_ASSERT( expected  == false );
382             CPPUNIT_ASSERT( !a.compare_exchange_weak( expected, false, order, CDS_ATOMIC::memory_order_relaxed));
383             CPPUNIT_ASSERT( expected  == true );
384             CPPUNIT_ASSERT( a.load( oLoad ) == true );
385
386             //a = bool(false);
387             a.store( false, oStore );
388
389             expected = false;
390             CPPUNIT_ASSERT( a.compare_exchange_strong( expected, true, order, CDS_ATOMIC::memory_order_relaxed));
391             CPPUNIT_ASSERT( expected  == false );
392             CPPUNIT_ASSERT( !a.compare_exchange_strong( expected, false, order, CDS_ATOMIC::memory_order_relaxed));
393             CPPUNIT_ASSERT( expected  == true );
394
395             CPPUNIT_ASSERT( a.load( oLoad ) == true );
396
397             CPPUNIT_ASSERT( a.exchange( false, order ) == true );
398         }
399
400
401         template <typename Atomic>
402         void do_test_atomic_pointer_void_( Atomic& a, char * arr, char aSize, CDS_ATOMIC::memory_order order )
403         {
404             CDS_ATOMIC::memory_order oLoad = convert_to_load_order(order);
405             CDS_ATOMIC::memory_order oStore = convert_to_store_order(order);
406             void *  p;
407
408             a.store( (void *) arr, oStore );
409             CPPUNIT_ASSERT( *reinterpret_cast<char *>(a.load( oLoad )) == 1 );
410
411             p = arr;
412             CPPUNIT_ASSERT( a.compare_exchange_weak( p, (void *)(arr + 5), order, CDS_ATOMIC::memory_order_relaxed ));
413             CPPUNIT_ASSERT( p == arr + 0 );
414             CPPUNIT_ASSERT( *reinterpret_cast<char *>(p) == 1 );
415             CPPUNIT_ASSERT( !a.compare_exchange_weak( p, (void *)(arr + 3), order, CDS_ATOMIC::memory_order_relaxed ));
416             CPPUNIT_ASSERT( p == arr + 5 );
417             CPPUNIT_ASSERT( *reinterpret_cast<char *>(p) == 6 );
418
419             CPPUNIT_ASSERT( a.compare_exchange_strong( p, (void *)(arr + 3), order, CDS_ATOMIC::memory_order_relaxed ));
420             CPPUNIT_ASSERT( p == arr + 5 );
421             CPPUNIT_ASSERT( *reinterpret_cast<char *>(p) == 6 );
422             CPPUNIT_ASSERT( !a.compare_exchange_strong( p, (void *)(arr + 5), order, CDS_ATOMIC::memory_order_relaxed ));
423             CPPUNIT_ASSERT( p == arr + 3 );
424             CPPUNIT_ASSERT( *reinterpret_cast<char *>(p) == 4 );
425
426             CPPUNIT_ASSERT( reinterpret_cast<char *>(a.exchange( (void *) arr, order )) == arr + 3 );
427             CPPUNIT_ASSERT( reinterpret_cast<char *>(a.load( oLoad )) == arr );
428             CPPUNIT_ASSERT( *reinterpret_cast<char *>(a.load( oLoad )) == 1 );
429
430             for ( char i = 1; i < aSize; ++i ) {
431                 CPPUNIT_ASSERT( *reinterpret_cast<char *>(a.load( oLoad )) == i );
432                 CPPUNIT_ASSERT( a.fetch_add( 1, order ));
433                 CPPUNIT_ASSERT( *reinterpret_cast<char *>(a.load( oLoad )) == i + 1 );
434             }
435
436             for ( char i = aSize; i > 1; --i ) {
437                 CPPUNIT_ASSERT( *reinterpret_cast<char *>(a.load( oLoad )) == i  );
438                 CPPUNIT_ASSERT( a.fetch_sub( 1, order ));
439                 CPPUNIT_ASSERT( *reinterpret_cast<char *>(a.load( oLoad )) == i - 1 );
440             }
441         }
442
443         template <bool Volatile>
444         void do_test_atomic_pointer_void()
445         {
446             typedef typename add_volatile<CDS_ATOMIC::atomic< void *>, Volatile>::type    atomic_pointer;
447
448             char   arr[8];
449             const char aSize = sizeof(arr)/sizeof(arr[0]);
450             for ( char i = 0; i < aSize; ++i ) {
451                 arr[unsigned(i)] = i + 1;
452             }
453
454             atomic_pointer  a;
455             void *  p;
456
457 #if CDS_BUILD_BITS == 32 && !( CDS_COMPILER == CDS_COMPILER_GCC && CDS_COMPILER_VERSION == 40700 )
458             /* GCC 4.7.0 has an linktime error in 32bit x86 mode:
459
460             ../tests/test-hdr/misc/cxx11_atomic_class.o: In function `std::__atomic_base<void*>::is_lock_free() const':
461             /usr/local/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/atomic_base.h:719: undefined reference to `__atomic_is_lock_free'
462
463             ../tests/test-hdr/misc/cxx11_atomic_class.o: In function `std::__atomic_base<void*>::is_lock_free() const volatile':
464             /usr/local/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/atomic_base.h:723: undefined reference to `__atomic_is_lock_free'
465
466             */
467             CPPUNIT_ASSERT( a.is_lock_free() );
468 #endif
469
470             a.store( (void *) arr );
471             CPPUNIT_ASSERT( *reinterpret_cast<char *>(a.load()) == 1 );
472
473             p = arr;
474             CPPUNIT_ASSERT( a.compare_exchange_weak( p, (void *)(arr + 5) ));
475             CPPUNIT_ASSERT( p == arr + 0 );
476             CPPUNIT_ASSERT( !a.compare_exchange_weak( p, (void *)(arr + 3) ));
477             CPPUNIT_ASSERT( p == arr + 5 );
478
479             CPPUNIT_ASSERT( a.compare_exchange_strong( p, (void *)(arr + 3) ));
480             CPPUNIT_ASSERT( p == arr + 5 );
481             CPPUNIT_ASSERT( !a.compare_exchange_strong( p, (void *)(arr + 5) ));
482             CPPUNIT_ASSERT( p == arr + 3 );
483
484             CPPUNIT_ASSERT( reinterpret_cast<char *>( a.exchange( (void *) arr )) == arr + 3 );
485             CPPUNIT_ASSERT( reinterpret_cast<char *>( a.load()) == arr );
486             CPPUNIT_ASSERT( *reinterpret_cast<char *>( a.load()) == 1 );
487
488             for ( char i = 1; i < aSize; ++i ) {
489                 CPPUNIT_ASSERT( *reinterpret_cast<char *>(a.load()) == i );
490                 CPPUNIT_ASSERT( a.fetch_add( 1 ));
491                 CPPUNIT_ASSERT( *reinterpret_cast<char *>(a.load()) == i + 1 );
492             }
493
494             for ( char i = aSize; i > 1; --i ) {
495                 CPPUNIT_ASSERT( *reinterpret_cast<char *>(a.load()) == i  );
496                 CPPUNIT_ASSERT( a.fetch_sub( 1 ));
497                 CPPUNIT_ASSERT( *reinterpret_cast<char *>(a.load()) == i - 1 );
498             }
499
500             do_test_atomic_pointer_void_( a, arr, aSize, CDS_ATOMIC::memory_order_relaxed );
501             do_test_atomic_pointer_void_( a, arr, aSize, CDS_ATOMIC::memory_order_consume );
502             do_test_atomic_pointer_void_( a, arr, aSize, CDS_ATOMIC::memory_order_acquire );
503             do_test_atomic_pointer_void_( a, arr, aSize, CDS_ATOMIC::memory_order_release );
504             do_test_atomic_pointer_void_( a, arr, aSize, CDS_ATOMIC::memory_order_acq_rel );
505             do_test_atomic_pointer_void_( a, arr, aSize, CDS_ATOMIC::memory_order_seq_cst );
506         }
507
508         template <typename Atomic, typename Integral>
509         void test_atomic_pointer_for_( Atomic& a, Integral * arr, Integral aSize, CDS_ATOMIC::memory_order order )
510         {
511             typedef Integral integral_type;
512             CDS_ATOMIC::memory_order oLoad = convert_to_load_order(order);
513             CDS_ATOMIC::memory_order oStore = convert_to_store_order(order);
514             integral_type *  p;
515
516             a.store( arr, oStore );
517             CPPUNIT_ASSERT( *a.load( oLoad ) == 1 );
518
519             p = arr;
520             CPPUNIT_ASSERT( a.compare_exchange_weak( p, arr + 5, order, CDS_ATOMIC::memory_order_relaxed ));
521             CPPUNIT_ASSERT( p == arr + 0 );
522             CPPUNIT_ASSERT( *p == 1 );
523             CPPUNIT_ASSERT( !a.compare_exchange_weak( p, arr + 3, order, CDS_ATOMIC::memory_order_relaxed ));
524             CPPUNIT_ASSERT( p == arr + 5 );
525             CPPUNIT_ASSERT( *p == 6 );
526
527             CPPUNIT_ASSERT( a.compare_exchange_strong( p, arr + 3, order, CDS_ATOMIC::memory_order_relaxed ));
528             CPPUNIT_ASSERT( p == arr + 5 );
529             CPPUNIT_ASSERT( *p == 6 );
530             CPPUNIT_ASSERT( !a.compare_exchange_strong( p, arr + 5, order, CDS_ATOMIC::memory_order_relaxed ));
531             CPPUNIT_ASSERT( p == arr + 3 );
532             CPPUNIT_ASSERT( *p == 4 );
533
534             CPPUNIT_ASSERT( a.exchange( arr, order ) == arr + 3 );
535             CPPUNIT_ASSERT( a.load( oLoad ) == arr );
536             CPPUNIT_ASSERT( *a.load( oLoad ) == 1 );
537
538             for ( integral_type i = 1; i < aSize; ++i ) {
539                 integral_type * p = a.load();
540                 CPPUNIT_ASSERT( *p == i );
541                 CPPUNIT_ASSERT( a.fetch_add( 1, order ) == p  );
542                 CPPUNIT_ASSERT( *a.load( oLoad ) == i + 1 );
543             }
544
545             for ( integral_type i = aSize; i > 1; --i ) {
546                 integral_type * p = a.load();
547                 CPPUNIT_ASSERT( *p == i  );
548                 CPPUNIT_ASSERT( a.fetch_sub( 1, order ) == p );
549                 CPPUNIT_ASSERT( *a.load( oLoad ) == i - 1 );
550             }
551         }
552
553         template <typename Integral, bool Volatile>
554         void test_atomic_pointer_for()
555         {
556             typedef Integral integral_type;
557             typedef typename add_volatile<CDS_ATOMIC::atomic< integral_type *>, Volatile>::type    atomic_pointer;
558
559             integral_type   arr[8];
560             const integral_type aSize = sizeof(arr)/sizeof(arr[0]);
561             for ( integral_type i = 0; i < aSize; ++i ) {
562                 arr[size_t(i)] = i + 1;
563             }
564
565             atomic_pointer  a;
566             integral_type *  p;
567
568             a.store( arr );
569             CPPUNIT_ASSERT( *a.load() == 1 );
570
571             p = arr;
572             CPPUNIT_ASSERT( a.compare_exchange_weak( p, arr + 5 ));
573             CPPUNIT_ASSERT( p == arr + 0 );
574             CPPUNIT_ASSERT( *p == 1 );
575             CPPUNIT_ASSERT( !a.compare_exchange_weak( p, arr + 3 ));
576             CPPUNIT_ASSERT( p == arr + 5 );
577             CPPUNIT_ASSERT( *p == 6 );
578
579             CPPUNIT_ASSERT( a.compare_exchange_strong( p, arr + 3 ));
580             CPPUNIT_ASSERT( p == arr + 5 );
581             CPPUNIT_ASSERT( *p == 6 );
582             CPPUNIT_ASSERT( !a.compare_exchange_strong( p, arr + 5 ));
583             CPPUNIT_ASSERT( p == arr + 3 );
584             CPPUNIT_ASSERT( *p == 4 );
585
586             CPPUNIT_ASSERT( a.exchange( arr ) == arr + 3 );
587             CPPUNIT_ASSERT( a.load() == arr );
588             CPPUNIT_ASSERT( *a.load() == 1 );
589
590             for ( integral_type i = 1; i < aSize; ++i ) {
591                 integral_type * p = a.load();
592                 CPPUNIT_ASSERT( *p == i );
593                 integral_type * pa = a.fetch_add( 1 );
594                 CPPUNIT_ASSERT_EX( pa == p, "pa=" << ((uintptr_t) pa) << " p=" << ((uintptr_t) p) );
595                 CPPUNIT_ASSERT( *a.load() == i + 1 );
596             }
597
598             for ( integral_type i = aSize; i > 1; --i ) {
599                 integral_type * p = a.load();
600                 CPPUNIT_ASSERT( *p == i  );
601                 CPPUNIT_ASSERT( a.fetch_sub( 1 ) == p );
602                 CPPUNIT_ASSERT( *a.load() == i - 1 );
603             }
604
605             test_atomic_pointer_for_( a, arr, aSize, CDS_ATOMIC::memory_order_relaxed );
606             test_atomic_pointer_for_( a, arr, aSize, CDS_ATOMIC::memory_order_consume );
607             test_atomic_pointer_for_( a, arr, aSize, CDS_ATOMIC::memory_order_acquire );
608             test_atomic_pointer_for_( a, arr, aSize, CDS_ATOMIC::memory_order_release );
609             test_atomic_pointer_for_( a, arr, aSize, CDS_ATOMIC::memory_order_acq_rel );
610             test_atomic_pointer_for_( a, arr, aSize, CDS_ATOMIC::memory_order_seq_cst );
611         }
612
613     public:
614         void test_atomic_flag()
615         {
616             // Array to test different alignment
617
618             CDS_ATOMIC::atomic_flag flags[8];
619             for ( size_t i = 0; i < sizeof(flags)/sizeof(flags[0]); ++i )
620                 do_test_atomic_flag( flags[i] );
621         }
622
623         void test_atomic_flag_volatile()
624         {
625             // Array to test different alignment
626
627             CDS_ATOMIC::atomic_flag volatile flags[8];
628             for ( size_t i = 0; i < sizeof(flags)/sizeof(flags[0]); ++i )
629                 do_test_atomic_flag( flags[i] );
630         }
631
632         template <typename AtomicBool>
633         void test_atomic_bool_()
634         {
635             // Array to test different alignment
636             AtomicBool  a[8];
637
638             for ( size_t i = 0; i < sizeof(a)/sizeof(a[0]); ++i ) {
639                 do_test_atomic_bool( a[i] );
640
641                 do_test_atomic_bool( a[i], CDS_ATOMIC::memory_order_relaxed );
642                 do_test_atomic_bool( a[i], CDS_ATOMIC::memory_order_consume );
643                 do_test_atomic_bool( a[i], CDS_ATOMIC::memory_order_acquire );
644                 do_test_atomic_bool( a[i], CDS_ATOMIC::memory_order_release );
645                 do_test_atomic_bool( a[i], CDS_ATOMIC::memory_order_acq_rel );
646                 do_test_atomic_bool( a[i], CDS_ATOMIC::memory_order_seq_cst );
647             }
648         }
649
650         void test_atomic_bool()
651         {
652             test_atomic_bool_< CDS_ATOMIC::atomic<bool> >();
653         }
654         void test_atomic_bool_volatile()
655         {
656             test_atomic_bool_< CDS_ATOMIC::atomic<bool> volatile >();
657         }
658
659         void test_atomic_char()                 { test_atomic_integral<char>(); }
660         void test_atomic_signed_char()          { test_atomic_integral<signed char>(); }
661         void test_atomic_unsigned_char()        { test_atomic_integral<unsigned char>(); }
662         void test_atomic_short_int()            { test_atomic_integral<short int>(); }
663         void test_atomic_unsigned_short_int()   { test_atomic_integral<unsigned short int>(); }
664         void test_atomic_int()                  { test_atomic_integral<int>(); }
665         void test_atomic_unsigned_int()         { test_atomic_integral<unsigned int>(); }
666         void test_atomic_long()                 { test_atomic_integral<long>(); }
667         void test_atomic_unsigned_long()        { test_atomic_integral<unsigned long>(); }
668         void test_atomic_long_long()            { test_atomic_integral<long long>(); }
669         void test_atomic_unsigned_long_long()   { test_atomic_integral<unsigned long long>(); }
670 //#if CDS_COMPILER == CDS_COMPILER_GCC && CDS_COMPILER_VERSION >= 40400
671 //        void test_atomic_char16_t()             { test_atomic_integral<char16_t>(); }
672 //        void test_atomic_char32_t()             { test_atomic_integral<char32_t>(); }
673 //#endif
674 //        void test_atomic_wchar_t()
675 //        {
676 //#if CDS_OS_TYPE != CDS_OS_HPUX
677 //            test_atomic_integral<wchar_t>();
678 //#endif
679 //        }
680
681         void test_atomic_char_volatile()                 { test_atomic_integral_volatile<char>(); }
682         void test_atomic_signed_char_volatile()          { test_atomic_integral_volatile<signed char>(); }
683         void test_atomic_unsigned_char_volatile()        { test_atomic_integral_volatile<unsigned char>(); }
684         void test_atomic_short_int_volatile()            { test_atomic_integral_volatile<short int>(); }
685         void test_atomic_unsigned_short_int_volatile()   { test_atomic_integral_volatile<unsigned short int>(); }
686         void test_atomic_int_volatile()                  { test_atomic_integral_volatile<int>(); }
687         void test_atomic_unsigned_int_volatile()         { test_atomic_integral_volatile<unsigned int>(); }
688         void test_atomic_long_volatile()                 { test_atomic_integral_volatile<long>(); }
689         void test_atomic_unsigned_long_volatile()        { test_atomic_integral_volatile<unsigned long>(); }
690         void test_atomic_long_long_volatile()            { test_atomic_integral_volatile<long long>(); }
691         void test_atomic_unsigned_long_long_volatile()   { test_atomic_integral_volatile<unsigned long long>(); }
692 //#if CDS_COMPILER == CDS_COMPILER_GCC && CDS_COMPILER_VERSION >= 40400
693 //        void test_atomic_char16_t_volatile()             { test_atomic_integral_volatile<char16_t>(); }
694 //        void test_atomic_char32_t_volatile()             { test_atomic_integral_volatile<char32_t>(); }
695 //#endif
696 //        void test_atomic_wchar_t_volatile()
697 //        {
698 //#if CDS_OS_TYPE != CDS_OS_HPUX
699 //            test_atomic_integral_volatile<wchar_t>();
700 //#endif
701 //        }
702
703         void test_atomic_pointer_void()         { do_test_atomic_pointer_void<false>() ;}
704         void test_atomic_pointer_void_volatile(){ do_test_atomic_pointer_void<true>() ;}
705
706         void test_atomic_pointer_char()         { test_atomic_pointer_for<char, false>() ;}
707         void test_atomic_pointer_short()        { test_atomic_pointer_for<short int, false>() ;}
708         void test_atomic_pointer_int()          { test_atomic_pointer_for<int, false>() ;}
709         void test_atomic_pointer_long()         { test_atomic_pointer_for<long, false>() ;}
710         void test_atomic_pointer_long_long()    { test_atomic_pointer_for<long long, false>() ;}
711
712         void test_atomic_pointer_char_volatile()        { test_atomic_pointer_for<char, true>() ;}
713         void test_atomic_pointer_short_volatile()       { test_atomic_pointer_for<unsigned short int, true>() ;}
714         void test_atomic_pointer_int_volatile()          { test_atomic_pointer_for<int, true>() ;}
715         void test_atomic_pointer_long_volatile()         { test_atomic_pointer_for<long, true>() ;}
716         void test_atomic_pointer_long_long_volatile()    { test_atomic_pointer_for<long long, true>() ;}
717
718     public:
719         CPPUNIT_TEST_SUITE(cxx11_atomic_class)
720             CPPUNIT_TEST( test_atomic_flag )
721             CPPUNIT_TEST( test_atomic_flag_volatile )
722
723             CPPUNIT_TEST( test_atomic_bool )
724             CPPUNIT_TEST( test_atomic_char )
725             CPPUNIT_TEST( test_atomic_signed_char)
726             CPPUNIT_TEST( test_atomic_unsigned_char)
727             CPPUNIT_TEST( test_atomic_short_int)
728             CPPUNIT_TEST( test_atomic_unsigned_short_int)
729             CPPUNIT_TEST( test_atomic_int)
730             CPPUNIT_TEST( test_atomic_unsigned_int)
731             CPPUNIT_TEST( test_atomic_long)
732             CPPUNIT_TEST( test_atomic_unsigned_long)
733             CPPUNIT_TEST( test_atomic_long_long)
734             CPPUNIT_TEST( test_atomic_unsigned_long_long)
735 //#if CDS_COMPILER == CDS_COMPILER_GCC && CDS_COMPILER_VERSION >= 40400
736 //            CPPUNIT_TEST( test_atomic_char16_t )
737 //            CPPUNIT_TEST( test_atomic_char32_t )
738 //#endif
739 //            CPPUNIT_TEST( test_atomic_wchar_t)
740
741             CPPUNIT_TEST( test_atomic_bool_volatile )
742             CPPUNIT_TEST( test_atomic_char_volatile )
743             CPPUNIT_TEST( test_atomic_signed_char_volatile)
744             CPPUNIT_TEST( test_atomic_unsigned_char_volatile)
745             CPPUNIT_TEST( test_atomic_short_int_volatile)
746             CPPUNIT_TEST( test_atomic_unsigned_short_int_volatile)
747             CPPUNIT_TEST( test_atomic_int_volatile)
748             CPPUNIT_TEST( test_atomic_unsigned_int_volatile)
749             CPPUNIT_TEST( test_atomic_long_volatile)
750             CPPUNIT_TEST( test_atomic_unsigned_long_volatile)
751             CPPUNIT_TEST( test_atomic_long_long_volatile)
752             CPPUNIT_TEST( test_atomic_unsigned_long_long_volatile)
753 //#if CDS_COMPILER == CDS_COMPILER_GCC && CDS_COMPILER_VERSION >= 40400
754 //            CPPUNIT_TEST( test_atomic_char16_t_volatile )
755 //            CPPUNIT_TEST( test_atomic_char32_t_volatile )
756 //#endif
757 //            CPPUNIT_TEST( test_atomic_wchar_t_volatile)
758
759             CPPUNIT_TEST( test_atomic_pointer_void)
760             CPPUNIT_TEST( test_atomic_pointer_void_volatile)
761
762             CPPUNIT_TEST( test_atomic_pointer_char)
763             CPPUNIT_TEST( test_atomic_pointer_short)
764             CPPUNIT_TEST( test_atomic_pointer_int)
765             CPPUNIT_TEST( test_atomic_pointer_long)
766             CPPUNIT_TEST( test_atomic_pointer_long_long)
767
768             CPPUNIT_TEST( test_atomic_pointer_char_volatile)
769             CPPUNIT_TEST( test_atomic_pointer_short_volatile)
770             CPPUNIT_TEST( test_atomic_pointer_int_volatile)
771             CPPUNIT_TEST( test_atomic_pointer_long_volatile)
772             CPPUNIT_TEST( test_atomic_pointer_long_long_volatile)
773
774         CPPUNIT_TEST_SUITE_END()
775     };
776 }   // namespace misc
777
778 CPPUNIT_TEST_SUITE_REGISTRATION(misc::cxx11_atomic_class);