1/*
2 Copyright (c) 2005-2019 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17// Declarations for simple estimate of the memory being used by a program.
18// Not yet implemented for macOS*.
19// This header is an optional part of the test harness.
20// It assumes that "harness_assert.h" has already been included.
21
22#ifndef tbb_test_harness_allocator_H
23#define tbb_test_harness_allocator_H
24
25#include "harness_defs.h"
26
27#if __linux__ || __APPLE__ || __sun
28#include <unistd.h>
29#elif _WIN32
30#include "tbb/machine/windows_api.h"
31#endif /* OS specific */
32#include <memory>
33#include <new>
34#include <cstdio>
35#include <stdexcept>
36#include <utility>
37#include __TBB_STD_SWAP_HEADER
38
39#include "tbb/atomic.h"
40#include "tbb/tbb_allocator.h"
41
42#if __SUNPRO_CC
43using std::printf;
44#endif
45
46#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
47 // Workaround for overzealous compiler warnings in /Wp64 mode
48 #pragma warning (push)
49#if defined(_Wp64)
50 #pragma warning (disable: 4267)
51#endif
52#if _MSC_VER <= 1600
53 #pragma warning (disable: 4355)
54#endif
55#if _MSC_VER <= 1800
56 #pragma warning (disable: 4512)
57#endif
58#endif
59
60#if TBB_INTERFACE_VERSION >= 7005
61// Allocator traits were introduced in 4.2 U5
62namespace Harness {
63#if __TBB_ALLOCATOR_TRAITS_PRESENT
64 using std::true_type;
65 using std::false_type;
66#else
67 using tbb::internal::true_type;
68 using tbb::internal::false_type;
69#endif //__TBB_ALLOCATOR_TRAITS_PRESENT
70}
71#endif
72
73template<typename counter_type = size_t>
74struct arena_data {
75 char * const my_buffer;
76 size_t const my_size; //in bytes
77 counter_type my_allocated; // in bytes
78
79 template<typename T>
80 arena_data(T * a_buffer, size_t a_size) __TBB_NOEXCEPT(true)
81 : my_buffer(reinterpret_cast<char*>(a_buffer))
82 , my_size(a_size * sizeof(T))
83 {
84 my_allocated =0;
85 }
86private:
87 void operator=( const arena_data& ); // NoAssign is not used to avoid dependency on harness.h
88};
89
90template<typename T, typename pocma = Harness::false_type, typename counter_type = size_t>
91struct arena {
92 typedef arena_data<counter_type> arena_data_t;
93private:
94 arena_data_t * my_data;
95public:
96 typedef T value_type;
97 typedef value_type* pointer;
98 typedef const value_type* const_pointer;
99 typedef value_type& reference;
100 typedef const value_type& const_reference;
101 typedef size_t size_type;
102 typedef ptrdiff_t difference_type;
103 template<typename U> struct rebind {
104 typedef arena<U, pocma, counter_type> other;
105 };
106
107 typedef pocma propagate_on_container_move_assignment;
108
109 arena(arena_data_t & data) __TBB_NOEXCEPT(true) : my_data(&data) {}
110
111 template<typename U1, typename U2, typename U3>
112 friend struct arena;
113
114 template<typename U1, typename U2 >
115 arena(arena<U1, U2, counter_type> const& other) __TBB_NOEXCEPT(true) : my_data(other.my_data) {}
116
117 friend void swap(arena & lhs ,arena & rhs){
118 std::swap(lhs.my_data, rhs.my_data);
119 }
120
121 pointer address(reference x) const {return &x;}
122 const_pointer address(const_reference x) const {return &x;}
123
124 //! Allocate space for n objects, starting on a cache/sector line.
125 pointer allocate( size_type n, const void* =0) {
126 size_t new_size = (my_data->my_allocated += n*sizeof(T));
127 ASSERT(my_data->my_allocated <= my_data->my_size,"trying to allocate more than was reserved");
128 char* result = &(my_data->my_buffer[new_size - n*sizeof(T)]);
129 return reinterpret_cast<pointer>(result);
130 }
131
132 //! Free block of memory that starts on a cache line
133 void deallocate( pointer p_arg, size_type n) {
134 char* p = reinterpret_cast<char*>(p_arg);
135 ASSERT(p >=my_data->my_buffer && p <= my_data->my_buffer + my_data->my_size, "trying to deallocate pointer not from arena ?");
136 ASSERT(p + n*sizeof(T) <= my_data->my_buffer + my_data->my_size, "trying to deallocate incorrect number of items?");
137 tbb::internal::suppress_unused_warning(p, n);
138 }
139
140 //! Largest value for which method allocate might succeed.
141 size_type max_size() const throw() {
142 return my_data->my_size / sizeof(T);
143 }
144
145 //! Copy-construct value at location pointed to by p.
146#if __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
147 template<typename U, typename... Args>
148 void construct(U *p, Args&&... args)
149 { ::new((void *)p) U(std::forward<Args>(args)...); }
150#else // __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
151#if __TBB_CPP11_RVALUE_REF_PRESENT
152 void construct( pointer p, value_type&& value ) {::new((void*)(p)) value_type(std::move(value));}
153#endif
154 void construct( pointer p, const value_type& value ) {::new((void*)(p)) value_type(value);}
155#endif // __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
156
157 //! Destroy value at location pointed to by p.
158 void destroy( pointer p ) {
159 p->~value_type();
160 // suppress "unreferenced parameter" warnings by MSVC up to and including 2015
161 tbb::internal::suppress_unused_warning(p);
162 }
163
164 friend bool operator==(arena const& lhs, arena const& rhs){
165 return lhs.my_data == rhs.my_data;
166 }
167
168 friend bool operator!=(arena const& lhs, arena const& rhs){
169 return !(lhs== rhs);
170 }
171};
172
173template <typename count_t = tbb::atomic<size_t> >
174struct allocator_counters {
175 count_t items_allocated;
176 count_t items_freed;
177 count_t allocations;
178 count_t frees;
179
180 friend bool operator==(allocator_counters const & lhs, allocator_counters const & rhs){
181 return lhs.items_allocated == rhs.items_allocated
182 && lhs.items_freed == rhs.items_freed
183 && lhs.allocations == rhs.allocations
184 && lhs.frees == rhs.frees
185 ;
186 }
187};
188
189template <typename base_alloc_t, typename count_t = tbb::atomic<size_t> >
190class static_counting_allocator : public base_alloc_t
191{
192public:
193 typedef typename base_alloc_t::pointer pointer;
194 typedef typename base_alloc_t::const_pointer const_pointer;
195 typedef typename base_alloc_t::reference reference;
196 typedef typename base_alloc_t::const_reference const_reference;
197 typedef typename base_alloc_t::value_type value_type;
198 typedef typename base_alloc_t::size_type size_type;
199 typedef typename base_alloc_t::difference_type difference_type;
200 template<typename U> struct rebind {
201 typedef static_counting_allocator<typename base_alloc_t::template rebind<U>::other,count_t> other;
202 };
203
204 typedef allocator_counters<count_t> counters_t;
205
206 static size_t max_items;
207 static count_t items_allocated;
208 static count_t items_freed;
209 static count_t allocations;
210 static count_t frees;
211 static bool verbose, throwing;
212
213 static_counting_allocator() throw() { }
214
215 static_counting_allocator(const base_alloc_t& src) throw()
216 : base_alloc_t(src) { }
217
218 static_counting_allocator(const static_counting_allocator& src) throw()
219 : base_alloc_t(src) { }
220
221 template<typename U, typename C>
222 static_counting_allocator(const static_counting_allocator<U, C>& src) throw()
223 : base_alloc_t(src) { }
224
225 pointer allocate(const size_type n)
226 {
227 if(verbose) printf("\t+%d|", int(n));
228 if(max_items && items_allocated + n >= max_items) {
229 if(verbose) printf("items limit hits!");
230 if(throwing)
231 __TBB_THROW( std::bad_alloc() );
232 return NULL;
233 }
234 pointer p = base_alloc_t::allocate(n, pointer(0));
235 allocations++;
236 items_allocated += n;
237 return p;
238 }
239
240 pointer allocate(const size_type n, const void * const)
241 { return allocate(n); }
242
243 void deallocate(const pointer ptr, const size_type n)
244 {
245 if(verbose) printf("\t-%d|", int(n));
246 frees++;
247 items_freed += n;
248 base_alloc_t::deallocate(ptr, n);
249 }
250
251 static counters_t counters(){
252 counters_t c = {items_allocated, items_freed, allocations, frees} ;
253 return c;
254 }
255
256 static void init_counters(bool v = false) {
257 verbose = v;
258 if(verbose) printf("\n------------------------------------------- Allocations:\n");
259 items_allocated = 0;
260 items_freed = 0;
261 allocations = 0;
262 frees = 0;
263 max_items = 0;
264 }
265
266 static void set_limits(size_type max = 0, bool do_throw = true) {
267 max_items = max;
268 throwing = do_throw;
269 }
270};
271
272template <typename base_alloc_t, typename count_t>
273size_t static_counting_allocator<base_alloc_t, count_t>::max_items;
274template <typename base_alloc_t, typename count_t>
275count_t static_counting_allocator<base_alloc_t, count_t>::items_allocated;
276template <typename base_alloc_t, typename count_t>
277count_t static_counting_allocator<base_alloc_t, count_t>::items_freed;
278template <typename base_alloc_t, typename count_t>
279count_t static_counting_allocator<base_alloc_t, count_t>::allocations;
280template <typename base_alloc_t, typename count_t>
281count_t static_counting_allocator<base_alloc_t, count_t>::frees;
282template <typename base_alloc_t, typename count_t>
283bool static_counting_allocator<base_alloc_t, count_t>::verbose;
284template <typename base_alloc_t, typename count_t>
285bool static_counting_allocator<base_alloc_t, count_t>::throwing;
286
287
288template <typename tag, typename count_t = tbb::atomic<size_t> >
289class static_shared_counting_allocator_base
290{
291public:
292 typedef allocator_counters<count_t> counters_t;
293
294 static size_t max_items;
295 static count_t items_allocated;
296 static count_t items_freed;
297 static count_t allocations;
298 static count_t frees;
299 static bool verbose, throwing;
300
301 static counters_t counters(){
302 counters_t c = {items_allocated, items_freed, allocations, frees} ;
303 return c;
304 }
305
306 static void init_counters(bool v = false) {
307 verbose = v;
308 if(verbose) printf("\n------------------------------------------- Allocations:\n");
309 items_allocated = 0;
310 items_freed = 0;
311 allocations = 0;
312 frees = 0;
313 max_items = 0;
314 }
315
316 static void set_limits(size_t max = 0, bool do_throw = true) {
317 max_items = max;
318 throwing = do_throw;
319 }
320};
321
322template <typename tag, typename count_t>
323size_t static_shared_counting_allocator_base<tag, count_t>::max_items;
324
325template <typename tag, typename count_t>
326count_t static_shared_counting_allocator_base<tag, count_t>::items_allocated;
327
328template <typename tag, typename count_t>
329count_t static_shared_counting_allocator_base<tag, count_t>::items_freed;
330
331template <typename tag, typename count_t>
332count_t static_shared_counting_allocator_base<tag, count_t>::allocations;
333
334template <typename tag, typename count_t>
335count_t static_shared_counting_allocator_base<tag, count_t>::frees;
336
337template <typename tag, typename count_t>
338bool static_shared_counting_allocator_base<tag, count_t>::verbose;
339
340template <typename tag, typename count_t>
341bool static_shared_counting_allocator_base<tag, count_t>::throwing;
342
343template <typename tag, typename base_alloc_t, typename count_t = tbb::atomic<size_t> >
344class static_shared_counting_allocator : public static_shared_counting_allocator_base<tag, count_t>, public base_alloc_t
345{
346 typedef static_shared_counting_allocator_base<tag, count_t> base_t;
347public:
348 typedef typename base_alloc_t::pointer pointer;
349 typedef typename base_alloc_t::const_pointer const_pointer;
350 typedef typename base_alloc_t::reference reference;
351 typedef typename base_alloc_t::const_reference const_reference;
352 typedef typename base_alloc_t::value_type value_type;
353 typedef typename base_alloc_t::size_type size_type;
354 typedef typename base_alloc_t::difference_type difference_type;
355 template<typename U> struct rebind {
356 typedef static_shared_counting_allocator<tag, typename base_alloc_t::template rebind<U>::other, count_t> other;
357 };
358
359 static_shared_counting_allocator() throw() { }
360
361 static_shared_counting_allocator(const base_alloc_t& src) throw()
362 : base_alloc_t(src) { }
363
364 static_shared_counting_allocator(const static_shared_counting_allocator& src) throw()
365 : base_alloc_t(src) { }
366
367 template<typename U, typename C>
368 static_shared_counting_allocator(const static_shared_counting_allocator<tag, U, C>& src) throw()
369 : base_alloc_t(src) { }
370
371 pointer allocate(const size_type n)
372 {
373 if(base_t::verbose) printf("\t+%d|", int(n));
374 if(base_t::max_items && base_t::items_allocated + n >= base_t::max_items) {
375 if(base_t::verbose) printf("items limit hits!");
376 if(base_t::throwing)
377 __TBB_THROW( std::bad_alloc() );
378 return NULL;
379 }
380 base_t::allocations++;
381 base_t::items_allocated += n;
382 return base_alloc_t::allocate(n, pointer(0));
383 }
384
385 pointer allocate(const size_type n, const void * const)
386 { return allocate(n); }
387
388 void deallocate(const pointer ptr, const size_type n)
389 {
390 if(base_t::verbose) printf("\t-%d|", int(n));
391 base_t::frees++;
392 base_t::items_freed += n;
393 base_alloc_t::deallocate(ptr, n);
394 }
395};
396
397template <typename base_alloc_t, typename count_t = tbb::atomic<size_t> >
398class local_counting_allocator : public base_alloc_t
399{
400public:
401 typedef typename base_alloc_t::pointer pointer;
402 typedef typename base_alloc_t::const_pointer const_pointer;
403 typedef typename base_alloc_t::reference reference;
404 typedef typename base_alloc_t::const_reference const_reference;
405 typedef typename base_alloc_t::value_type value_type;
406 typedef typename base_alloc_t::size_type size_type;
407 typedef typename base_alloc_t::difference_type difference_type;
408 template<typename U> struct rebind {
409 typedef local_counting_allocator<typename base_alloc_t::template rebind<U>::other,count_t> other;
410 };
411
412 count_t items_allocated;
413 count_t items_freed;
414 count_t allocations;
415 count_t frees;
416 size_t max_items;
417
418 void set_counters(const count_t & a_items_allocated, const count_t & a_items_freed, const count_t & a_allocations, const count_t & a_frees, const count_t & a_max_items){
419 items_allocated = a_items_allocated;
420 items_freed = a_items_freed;
421 allocations = a_allocations;
422 frees = a_frees;
423 max_items = a_max_items;
424 }
425
426 template< typename allocator_t>
427 void set_counters(const allocator_t & a){
428 this->set_counters(a.items_allocated, a.items_freed, a.allocations, a.frees, a.max_items);
429 }
430
431 void clear_counters(){
432 count_t zero;
433 zero = 0;
434 this->set_counters(zero,zero,zero,zero,zero);
435 }
436
437 local_counting_allocator() throw() {
438 this->clear_counters();
439 }
440
441 local_counting_allocator(const local_counting_allocator &a) throw()
442 : base_alloc_t(a)
443 , items_allocated(a.items_allocated)
444 , items_freed(a.items_freed)
445 , allocations(a.allocations)
446 , frees(a.frees)
447 , max_items(a.max_items)
448 { }
449
450 template<typename U, typename C>
451 local_counting_allocator(const static_counting_allocator<U,C> & a) throw() {
452 this->set_counters(a);
453 }
454
455 template<typename U, typename C>
456 local_counting_allocator(const local_counting_allocator<U,C> &a) throw()
457 : items_allocated(a.items_allocated)
458 , items_freed(a.items_freed)
459 , allocations(a.allocations)
460 , frees(a.frees)
461 , max_items(a.max_items)
462 { }
463
464 bool operator==(const local_counting_allocator &a) const
465 { return static_cast<const base_alloc_t&>(a) == *this; }
466
467 pointer allocate(const size_type n)
468 {
469 if(max_items && items_allocated + n >= max_items)
470 __TBB_THROW( std::bad_alloc() );
471 pointer p = base_alloc_t::allocate(n, pointer(0));
472 ++allocations;
473 items_allocated += n;
474 return p;
475 }
476
477 pointer allocate(const size_type n, const void * const)
478 { return allocate(n); }
479
480 void deallocate(const pointer ptr, const size_type n)
481 {
482 ++frees;
483 items_freed += n;
484 base_alloc_t::deallocate(ptr, n);
485 }
486
487 void set_limits(size_type max = 0) {
488 max_items = max;
489 }
490};
491
492template <typename T, template<typename X> class Allocator = std::allocator>
493class debug_allocator : public Allocator<T>
494{
495public:
496 typedef Allocator<T> base_allocator_type;
497 typedef typename base_allocator_type::value_type value_type;
498 typedef typename base_allocator_type::pointer pointer;
499 typedef typename base_allocator_type::const_pointer const_pointer;
500 typedef typename base_allocator_type::reference reference;
501 typedef typename base_allocator_type::const_reference const_reference;
502 typedef typename base_allocator_type::size_type size_type;
503 typedef typename base_allocator_type::difference_type difference_type;
504 template<typename U> struct rebind {
505 typedef debug_allocator<U, Allocator> other;
506 };
507
508 debug_allocator() throw() { }
509 debug_allocator(const debug_allocator &a) throw() : base_allocator_type( a ) { }
510 template<typename U>
511 debug_allocator(const debug_allocator<U> &a) throw() : base_allocator_type( Allocator<U>( a ) ) { }
512
513 pointer allocate(const size_type n, const void *hint = 0 ) {
514 pointer ptr = base_allocator_type::allocate( n, hint );
515 std::memset( (void*)ptr, 0xE3E3E3E3, n * sizeof(value_type) );
516 return ptr;
517 }
518};
519
520//! Analogous to std::allocator<void>, as defined in ISO C++ Standard, Section 20.4.1
521/** @ingroup memory_allocation */
522template<template<typename T> class Allocator>
523class debug_allocator<void, Allocator> : public Allocator<void> {
524public:
525 typedef Allocator<void> base_allocator_type;
526 typedef typename base_allocator_type::value_type value_type;
527 typedef typename base_allocator_type::pointer pointer;
528 typedef typename base_allocator_type::const_pointer const_pointer;
529 template<typename U> struct rebind {
530 typedef debug_allocator<U, Allocator> other;
531 };
532};
533
534template<typename T1, template<typename X1> class B1, typename T2, template<typename X2> class B2>
535inline bool operator==( const debug_allocator<T1,B1> &a, const debug_allocator<T2,B2> &b) {
536 return static_cast< B1<T1> >(a) == static_cast< B2<T2> >(b);
537}
538template<typename T1, template<typename X1> class B1, typename T2, template<typename X2> class B2>
539inline bool operator!=( const debug_allocator<T1,B1> &a, const debug_allocator<T2,B2> &b) {
540 return static_cast< B1<T1> >(a) != static_cast< B2<T2> >(b);
541}
542
543template <typename T, typename pocma = Harness::false_type, template<typename X> class Allocator = std::allocator>
544class stateful_allocator : public Allocator<T>
545{
546 void* unique_pointer;
547
548 template<typename T1, typename pocma1, template<typename X1> class Allocator1>
549 friend class stateful_allocator;
550public:
551 typedef Allocator<T> base_allocator_type;
552 typedef typename base_allocator_type::value_type value_type;
553 typedef typename base_allocator_type::pointer pointer;
554 typedef typename base_allocator_type::const_pointer const_pointer;
555 typedef typename base_allocator_type::reference reference;
556 typedef typename base_allocator_type::const_reference const_reference;
557 typedef typename base_allocator_type::size_type size_type;
558 typedef typename base_allocator_type::difference_type difference_type;
559 template<typename U> struct rebind {
560 typedef stateful_allocator<U, pocma, Allocator> other;
561 };
562 typedef pocma propagate_on_container_move_assignment;
563
564 stateful_allocator() throw() : unique_pointer(this) { }
565
566 template<typename U>
567 stateful_allocator(const stateful_allocator<U, pocma> &a) throw() : base_allocator_type( Allocator<U>( a ) ), unique_pointer(a.uniqe_pointer) { }
568
569 friend bool operator==(stateful_allocator const& lhs, stateful_allocator const& rhs){
570 return lhs.unique_pointer == rhs.unique_pointer;
571 }
572
573 friend bool operator!=(stateful_allocator const& rhs, stateful_allocator const& lhs){
574 return !(lhs == rhs);
575 }
576
577};
578
579template <typename T>
580class pmr_stateful_allocator
581{
582private:
583 pmr_stateful_allocator& operator=(const pmr_stateful_allocator&); /* = deleted */
584public:
585 typedef T value_type;
586 typedef Harness::false_type propagate_on_container_move_assignment;
587 typedef Harness::false_type propagate_on_container_copy_assignment;
588 typedef Harness::false_type propagate_on_container_swap;
589
590// These types are required in C++03
591#if !__TBB_ALLOCATOR_TRAITS_PRESENT
592 typedef value_type* pointer;
593 typedef const value_type* const_pointer;
594 typedef value_type& reference;
595 typedef const value_type& const_reference;
596 typedef size_t size_type;
597 typedef ptrdiff_t difference_type;
598 template<class U> struct rebind {
599 typedef pmr_stateful_allocator<U> other;
600 };
601#endif
602
603 pmr_stateful_allocator() throw() : unique_pointer(this) {}
604
605 pmr_stateful_allocator(const pmr_stateful_allocator &a) : unique_pointer(a.unique_pointer) {}
606
607 template<typename U>
608 pmr_stateful_allocator(const pmr_stateful_allocator<U> &a) throw() : unique_pointer(a.unique_pointer) {}
609
610 value_type* allocate( size_t n, const void* /*hint*/ = 0 ) {
611 return static_cast<value_type*>( malloc( n * sizeof(value_type) ) );
612 }
613
614 void deallocate( value_type* p, size_t ) {
615 free( p );
616 }
617
618#if __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
619 //! Copy-construct value at location pointed to by p.
620 template<typename U, typename... Args>
621 void construct(U *p, Args&&... args)
622 {
623 ::new((void *)p) U(std::forward<Args>(args)...);
624 }
625#else // __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
626#if __TBB_CPP11_RVALUE_REF_PRESENT
627 void construct(value_type* p, value_type&& value) { ::new((void*)(p)) value_type(std::move(value)); }
628#endif
629 void construct(value_type* p, const value_type& value) { ::new((void*)(p)) value_type(value); }
630#endif // __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
631
632 //! Destroy value at location pointed to by p.
633 void destroy(value_type* p) {
634 p->~value_type();
635 // suppress "unreferenced parameter" warnings by MSVC up to and including 2015
636 tbb::internal::suppress_unused_warning(p);
637 }
638
639 friend bool operator==(pmr_stateful_allocator const& lhs, pmr_stateful_allocator const& rhs){
640 return lhs.unique_pointer == rhs.unique_pointer;
641 }
642
643 friend bool operator!=(pmr_stateful_allocator const& rhs, pmr_stateful_allocator const& lhs){
644 return !(lhs == rhs);
645 }
646
647 void* unique_pointer;
648};
649
650// C++03 allocator doesn't have to be assignable or swappable, so
651// tbb::internal::allocator_traits defines POCCA and POCS as false_type
652#if __TBB_ALLOCATOR_TRAITS_PRESENT
653#include "tbb/internal/_allocator_traits.h" // Need traits_true/false_type
654
655template <typename Allocator, typename POCMA = tbb::internal::traits_false_type,
656 typename POCCA = tbb::internal::traits_false_type, typename POCS = tbb::internal::traits_false_type>
657struct propagating_allocator : Allocator {
658 typedef POCMA propagate_on_container_move_assignment;
659 typedef POCCA propagate_on_container_copy_assignment;
660 typedef POCS propagate_on_container_swap;
661 bool* propagated_on_copy_assignment;
662 bool* propagated_on_move_assignment;
663 bool* propagated_on_swap;
664 bool* selected_on_copy_construction;
665
666 template <typename U>
667 struct rebind {
668 typedef propagating_allocator<typename tbb::internal::allocator_rebind<Allocator, U>::type,
669 POCMA, POCCA, POCS> other;
670 };
671
672 propagating_allocator() : propagated_on_copy_assignment(NULL),
673 propagated_on_move_assignment(NULL),
674 propagated_on_swap(NULL),
675 selected_on_copy_construction(NULL) {}
676
677 propagating_allocator(bool& poca, bool& poma, bool& pos, bool& soc)
678 : propagated_on_copy_assignment(&poca),
679 propagated_on_move_assignment(&poma),
680 propagated_on_swap(&pos),
681 selected_on_copy_construction(&soc) {}
682
683 propagating_allocator(const propagating_allocator& other)
684 : Allocator(other),
685 propagated_on_copy_assignment(other.propagated_on_copy_assignment),
686 propagated_on_move_assignment(other.propagated_on_move_assignment),
687 propagated_on_swap(other.propagated_on_swap),
688 selected_on_copy_construction(other.selected_on_copy_construction) {}
689
690 template <typename Allocator2>
691 propagating_allocator(const propagating_allocator<Allocator2, POCMA, POCCA, POCS>& other)
692 : Allocator(other),
693 propagated_on_copy_assignment(other.propagated_on_copy_assignment),
694 propagated_on_move_assignment(other.propagated_on_move_assignment),
695 propagated_on_swap(other.propagated_on_swap),
696 selected_on_copy_construction(other.selected_on_copy_construction) {}
697
698 propagating_allocator& operator=(const propagating_allocator&) {
699 ASSERT(POCCA::value, "Allocator should not copy assign if pocca is false");
700 if (propagated_on_copy_assignment)
701 *propagated_on_copy_assignment = true;
702 return *this;
703 }
704
705#if __TBB_CPP11_RVALUE_REF_PRESENT
706 propagating_allocator& operator=(propagating_allocator&&) {
707 ASSERT(POCMA::value, "Allocator should not move assign if pocma is false");
708 if (propagated_on_move_assignment)
709 *propagated_on_move_assignment = true;
710 return *this;
711 }
712#endif
713
714 propagating_allocator select_on_container_copy_construction() const {
715 if (selected_on_copy_construction)
716 *selected_on_copy_construction = true;
717 return *this;
718 }
719};
720
721namespace propagating_allocators {
722typedef tbb::tbb_allocator<int> base_allocator;
723typedef tbb::internal::traits_true_type true_type;
724typedef tbb::internal::traits_false_type false_type;
725
726typedef propagating_allocator<base_allocator, /*POCMA=*/true_type, /*POCCA=*/true_type,
727 /*POCS=*/true_type> always_propagating_allocator;
728typedef propagating_allocator<base_allocator, false_type, false_type, false_type> never_propagating_allocator;
729typedef propagating_allocator<base_allocator, true_type, false_type, false_type> pocma_allocator;
730typedef propagating_allocator<base_allocator, false_type, true_type, false_type> pocca_allocator;
731typedef propagating_allocator<base_allocator, false_type, false_type, true_type> pocs_allocator;
732}
733
734template <typename Allocator, typename POCMA, typename POCCA, typename POCS>
735void swap(propagating_allocator<Allocator, POCMA, POCCA, POCS>& lhs,
736 propagating_allocator<Allocator, POCMA, POCCA, POCS>&) {
737 ASSERT(POCS::value, "Allocator should not swap if pocs is false");
738 if (lhs.propagated_on_swap)
739 *lhs.propagated_on_swap = true;
740}
741
742template <typename ContainerType>
743void test_allocator_traits_support() {
744 typedef typename ContainerType::allocator_type allocator_type;
745 typedef std::allocator_traits<allocator_type> allocator_traits;
746 typedef typename allocator_traits::propagate_on_container_copy_assignment pocca_type;
747#if __TBB_CPP11_RVALUE_REF_PRESENT
748 typedef typename allocator_traits::propagate_on_container_move_assignment pocma_type;
749#endif
750 typedef typename allocator_traits::propagate_on_container_swap pocs_type;
751
752 bool propagated_on_copy = false;
753 bool propagated_on_move = false;
754 bool propagated_on_swap = false;
755 bool selected_on_copy = false;
756
757 allocator_type alloc(propagated_on_copy, propagated_on_move, propagated_on_swap, selected_on_copy);
758
759 ContainerType c1(alloc), c2(c1);
760 ASSERT(selected_on_copy, "select_on_container_copy_construction function was not called");
761
762 c1 = c2;
763 ASSERT(propagated_on_copy == pocca_type::value, "Unexpected allocator propagation on copy assignment");
764
765#if __TBB_CPP11_RVALUE_REF_PRESENT
766 c2 = std::move(c1);
767 ASSERT(propagated_on_move == pocma_type::value, "Unexpected allocator propagation on move assignment");
768#endif
769
770 c1.swap(c2);
771 ASSERT(propagated_on_swap == pocs_type::value, "Unexpected allocator propagation on swap");
772}
773
774#if __TBB_CPP11_RVALUE_REF_PRESENT
775class non_movable_object {
776 non_movable_object() {}
777private:
778 non_movable_object(non_movable_object&&);
779 non_movable_object& operator=(non_movable_object&&);
780};
781
782template <typename ContainerType>
783void test_allocator_traits_with_non_movable_value_type() {
784 // Check, that if pocma is true, container allows move assignment without per-element move
785 typedef typename ContainerType::allocator_type allocator_type;
786 typedef std::allocator_traits<allocator_type> allocator_traits;
787 typedef typename allocator_traits::propagate_on_container_move_assignment pocma_type;
788 ASSERT(pocma_type::value, "Allocator POCMA must be true for this test");
789 allocator_type alloc;
790 ContainerType container1(alloc), container2(alloc);
791 container1 = std::move(container2);
792}
793#endif // __TBB_CPP11_RVALUE_REF_PRESENT
794
795#endif // __TBB_ALLOCATOR_TRAITS_PRESENT
796
797#if __TBB_CPP11_RVALUE_REF_PRESENT
798
799template<typename Allocator>
800class allocator_aware_data {
801public:
802 static bool assert_on_constructions;
803 typedef Allocator allocator_type;
804
805 allocator_aware_data(const allocator_type& allocator = allocator_type())
806 : my_allocator(allocator), my_value(0) {}
807 allocator_aware_data(int v, const allocator_type& allocator = allocator_type())
808 : my_allocator(allocator), my_value(v) {}
809 allocator_aware_data(const allocator_aware_data&) {
810 ASSERT(!assert_on_constructions, "Allocator should propagate to the data during copy construction");
811 }
812 allocator_aware_data(allocator_aware_data&&) {
813 ASSERT(!assert_on_constructions, "Allocator should propagate to the data during move construction");
814 }
815 allocator_aware_data(const allocator_aware_data& rhs, const allocator_type& allocator)
816 : my_allocator(allocator), my_value(rhs.my_value) {}
817 allocator_aware_data(allocator_aware_data&& rhs, const allocator_type& allocator)
818 : my_allocator(allocator), my_value(rhs.my_value) {}
819
820 int value() const { return my_value; }
821private:
822 allocator_type my_allocator;
823 int my_value;
824};
825
826template<typename Allocator>
827bool allocator_aware_data<Allocator>::assert_on_constructions = false;
828
829#endif // __TBB_CPP11_RVALUE_REF_PRESENT
830
831#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
832 // Workaround for overzealous compiler warnings
833 #pragma warning (pop)
834#endif // warning 4267,4512,4355 is back
835
836namespace Harness {
837
838 struct IsEqual {
839#if __TBB_CPP11_SMART_POINTERS_PRESENT
840 template <typename T>
841 static bool compare( const std::weak_ptr<T> &t1, const std::weak_ptr<T> &t2 ) {
842 // Compare real pointers.
843 return t1.lock().get() == t2.lock().get();
844 }
845 template <typename T>
846 static bool compare( const std::unique_ptr<T> &t1, const std::unique_ptr<T> &t2 ) {
847 // Compare real values.
848 return *t1 == *t2;
849 }
850 template <typename T1, typename T2>
851 static bool compare( const std::pair< const std::weak_ptr<T1>, std::weak_ptr<T2> > &t1,
852 const std::pair< const std::weak_ptr<T1>, std::weak_ptr<T2> > &t2 ) {
853 // Compare real pointers.
854 return t1.first.lock().get() == t2.first.lock().get() &&
855 t1.second.lock().get() == t2.second.lock().get();
856 }
857#endif /* __TBB_CPP11_SMART_POINTERS_PRESENT */
858 template <typename T1, typename T2>
859 static bool compare( const T1 &t1, const T2 &t2 ) {
860 return t1 == t2;
861 }
862 template <typename T1, typename T2>
863 bool operator()( T1 &t1, T2 &t2) const {
864 return compare( (const T1&)t1, (const T2&)t2 );
865 }
866 };
867
868} // Harness
869#endif // tbb_test_harness_allocator_H
870