1 /*
2     Copyright (c) 2005-2020 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
43 using 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
62 namespace 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 
73 template<typename counter_type = size_t>
74 struct 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>
arena_dataarena_data80     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     }
86 private:
87     void operator=( const arena_data& ); // NoAssign is not used to avoid dependency on harness.h
88 };
89 
90 template<typename T, typename pocma = Harness::false_type, typename counter_type = size_t>
91 struct arena {
92     typedef arena_data<counter_type> arena_data_t;
93 private:
94     arena_data_t * my_data;
95 public:
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 
__TBB_NOEXCEPTarena109     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 >
arenaarena115     arena(arena<U1, U2, counter_type> const& other) __TBB_NOEXCEPT(true) : my_data(other.my_data) {}
116 
swaparena117     friend void swap(arena & lhs ,arena & rhs){
118         std::swap(lhs.my_data, rhs.my_data);
119     }
120 
addressarena121     pointer address(reference x) const {return &x;}
addressarena122     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
deallocatearena133     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.
max_sizearena141     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>
constructarena148     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
constructarena152     void construct( pointer p, value_type&& value ) {::new((void*)(p)) value_type(std::move(value));}
153 #endif
constructarena154     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.
destroyarena158     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 
173 template <typename count_t = tbb::atomic<size_t> >
174 struct 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 
189 template <typename base_alloc_t, typename count_t = tbb::atomic<size_t> >
190 class static_counting_allocator : public base_alloc_t
191 {
192 public:
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 
throw()213     static_counting_allocator() throw() { }
214 
throw()215     static_counting_allocator(const base_alloc_t& src) throw()
216     : base_alloc_t(src) { }
217 
throw()218     static_counting_allocator(const static_counting_allocator& src) throw()
219     : base_alloc_t(src) { }
220 
221     template<typename U, typename C>
static_counting_allocator(const static_counting_allocator<U,C> & src)222     static_counting_allocator(const static_counting_allocator<U, C>& src) throw()
223     : base_alloc_t(src) { }
224 
allocate(const size_type n)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 
allocate(const size_type n,const void * const)240     pointer allocate(const size_type n, const void * const)
241     {   return allocate(n); }
242 
deallocate(const pointer ptr,const size_type n)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 
counters()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 
272 template <typename base_alloc_t, typename count_t>
273 size_t static_counting_allocator<base_alloc_t, count_t>::max_items;
274 template <typename base_alloc_t, typename count_t>
275 count_t static_counting_allocator<base_alloc_t, count_t>::items_allocated;
276 template <typename base_alloc_t, typename count_t>
277 count_t static_counting_allocator<base_alloc_t, count_t>::items_freed;
278 template <typename base_alloc_t, typename count_t>
279 count_t static_counting_allocator<base_alloc_t, count_t>::allocations;
280 template <typename base_alloc_t, typename count_t>
281 count_t static_counting_allocator<base_alloc_t, count_t>::frees;
282 template <typename base_alloc_t, typename count_t>
283 bool static_counting_allocator<base_alloc_t, count_t>::verbose;
284 template <typename base_alloc_t, typename count_t>
285 bool static_counting_allocator<base_alloc_t, count_t>::throwing;
286 
287 
288 template <typename tag, typename count_t = tbb::atomic<size_t> >
289 class static_shared_counting_allocator_base
290 {
291 public:
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 
counters()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 
322 template <typename tag, typename count_t>
323 size_t static_shared_counting_allocator_base<tag, count_t>::max_items;
324 
325 template <typename tag, typename count_t>
326 count_t static_shared_counting_allocator_base<tag, count_t>::items_allocated;
327 
328 template <typename tag, typename count_t>
329 count_t static_shared_counting_allocator_base<tag, count_t>::items_freed;
330 
331 template <typename tag, typename count_t>
332 count_t static_shared_counting_allocator_base<tag, count_t>::allocations;
333 
334 template <typename tag, typename count_t>
335 count_t static_shared_counting_allocator_base<tag, count_t>::frees;
336 
337 template <typename tag, typename count_t>
338 bool static_shared_counting_allocator_base<tag, count_t>::verbose;
339 
340 template <typename tag, typename count_t>
341 bool static_shared_counting_allocator_base<tag, count_t>::throwing;
342 
343 template <typename tag, typename base_alloc_t, typename count_t = tbb::atomic<size_t> >
344 class 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;
347 public:
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 
throw()359     static_shared_counting_allocator() throw() { }
360 
throw()361     static_shared_counting_allocator(const base_alloc_t& src) throw()
362     : base_alloc_t(src) { }
363 
throw()364     static_shared_counting_allocator(const static_shared_counting_allocator& src) throw()
365     : base_alloc_t(src) { }
366 
367     template<typename U, typename C>
static_shared_counting_allocator(const static_shared_counting_allocator<tag,U,C> & src)368     static_shared_counting_allocator(const static_shared_counting_allocator<tag, U, C>& src) throw()
369     : base_alloc_t(src) { }
370 
allocate(const size_type n)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 
allocate(const size_type n,const void * const)385     pointer allocate(const size_type n, const void * const)
386     {   return allocate(n); }
387 
deallocate(const pointer ptr,const size_type n)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 
397 template <typename base_alloc_t, typename count_t = tbb::atomic<size_t> >
398 class local_counting_allocator : public base_alloc_t
399 {
400 public:
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 
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)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>
set_counters(const allocator_t & a)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 
clear_counters()431     void clear_counters(){
432         count_t zero;
433         zero = 0;
434         this->set_counters(zero,zero,zero,zero,zero);
435     }
436 
throw()437     local_counting_allocator() throw() {
438         this->clear_counters();
439     }
440 
throw()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>
local_counting_allocator(const static_counting_allocator<U,C> & a)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>
local_counting_allocator(const local_counting_allocator<U,C> & a)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 
allocate(const size_type n)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 
allocate(const size_type n,const void * const)477     pointer allocate(const size_type n, const void * const)
478     { return allocate(n); }
479 
deallocate(const pointer ptr,const size_type n)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 
492 template <typename T, template<typename X> class Allocator = std::allocator>
493 class debug_allocator : public Allocator<T>
494 {
495 public:
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 
throw()508     debug_allocator() throw() { }
throw()509     debug_allocator(const debug_allocator &a) throw() : base_allocator_type( a ) { }
510     template<typename U>
debug_allocator(const debug_allocator<U> & a)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 */
522 template<template<typename T> class Allocator>
523 class debug_allocator<void, Allocator> : public Allocator<void> {
524 public:
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 
534 template<typename T1, template<typename X1> class B1, typename T2, template<typename X2> class B2>
535 inline 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 }
538 template<typename T1, template<typename X1> class B1, typename T2, template<typename X2> class B2>
539 inline 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 
543 template <typename T, typename pocma = Harness::false_type, template<typename X> class Allocator = std::allocator>
544 class 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;
550 public:
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 
throw()564     stateful_allocator() throw() : unique_pointer(this) { }
565 
566     template<typename U>
stateful_allocator(const stateful_allocator<U,pocma> & a)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 
579 template <typename T>
580 class pmr_stateful_allocator
581 {
582 private:
583     pmr_stateful_allocator& operator=(const pmr_stateful_allocator&); /* = deleted */
584 public:
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 
throw()603     pmr_stateful_allocator() throw() : unique_pointer(this) {}
604 
pmr_stateful_allocator(const pmr_stateful_allocator & a)605     pmr_stateful_allocator(const pmr_stateful_allocator &a) : unique_pointer(a.unique_pointer) {}
606 
607     template<typename U>
pmr_stateful_allocator(const pmr_stateful_allocator<U> & a)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 
deallocate(value_type * p,size_t)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>
construct(U * p,Args &&...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
construct(value_type * p,value_type && value)627     void construct(value_type* p, value_type&& value) { ::new((void*)(p)) value_type(std::move(value)); }
628 #endif
construct(value_type * p,const value_type & value)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.
destroy(value_type * 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 
655 template <typename Allocator, typename POCMA = tbb::internal::traits_false_type,
656           typename POCCA = tbb::internal::traits_false_type, typename POCS = tbb::internal::traits_false_type>
657 struct 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 
propagating_allocatorpropagating_allocator672     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 
propagating_allocatorpropagating_allocator677     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 
propagating_allocatorpropagating_allocator683     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>
propagating_allocatorpropagating_allocator691     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 
select_on_container_copy_constructionpropagating_allocator714     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 
721 namespace propagating_allocators {
722 typedef tbb::tbb_allocator<int> base_allocator;
723 typedef tbb::internal::traits_true_type true_type;
724 typedef tbb::internal::traits_false_type false_type;
725 
726 typedef propagating_allocator<base_allocator, /*POCMA=*/true_type, /*POCCA=*/true_type,
727                               /*POCS=*/true_type> always_propagating_allocator;
728 typedef propagating_allocator<base_allocator, false_type, false_type, false_type> never_propagating_allocator;
729 typedef propagating_allocator<base_allocator, true_type, false_type, false_type> pocma_allocator;
730 typedef propagating_allocator<base_allocator, false_type, true_type, false_type> pocca_allocator;
731 typedef propagating_allocator<base_allocator, false_type, false_type, true_type> pocs_allocator;
732 }
733 
734 template <typename Allocator, typename POCMA, typename POCCA, typename POCS>
swap(propagating_allocator<Allocator,POCMA,POCCA,POCS> & lhs,propagating_allocator<Allocator,POCMA,POCCA,POCS> &)735 void 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 
742 template <typename ContainerType>
test_allocator_traits_support()743 void 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
775 class non_movable_object {
non_movable_object()776     non_movable_object() {}
777 private:
778     non_movable_object(non_movable_object&&);
779     non_movable_object& operator=(non_movable_object&&);
780 };
781 
782 template <typename ContainerType>
test_allocator_traits_with_non_movable_value_type()783 void 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 
799 template<typename Allocator>
800 class allocator_aware_data {
801 public:
802     static bool assert_on_constructions;
803     typedef Allocator allocator_type;
804 
805     allocator_aware_data(const allocator_type& allocator = allocator_type())
my_allocator(allocator)806         : my_allocator(allocator), my_value(0) {}
807     allocator_aware_data(int v, const allocator_type& allocator = allocator_type())
my_allocator(allocator)808         : my_allocator(allocator), my_value(v) {}
allocator_aware_data(const allocator_aware_data &)809     allocator_aware_data(const allocator_aware_data&) {
810         ASSERT(!assert_on_constructions, "Allocator should propagate to the data during copy construction");
811     }
allocator_aware_data(allocator_aware_data &&)812     allocator_aware_data(allocator_aware_data&&) {
813         ASSERT(!assert_on_constructions, "Allocator should propagate to the data during move construction");
814     }
allocator_aware_data(const allocator_aware_data & rhs,const allocator_type & allocator)815     allocator_aware_data(const allocator_aware_data& rhs, const allocator_type& allocator)
816         : my_allocator(allocator), my_value(rhs.my_value) {}
allocator_aware_data(allocator_aware_data && rhs,const allocator_type & allocator)817     allocator_aware_data(allocator_aware_data&& rhs, const allocator_type& allocator)
818         : my_allocator(allocator), my_value(rhs.my_value) {}
819 
value()820     int value() const { return my_value; }
821 private:
822     allocator_type my_allocator;
823     int my_value;
824 };
825 
826 template<typename Allocator>
827 bool 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 
836 namespace Harness {
837 
838     struct IsEqual {
839 #if __TBB_CPP11_SMART_POINTERS_PRESENT
840         template <typename T>
compareIsEqual841         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>
compareIsEqual846         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>
compareIsEqual851         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>
compareIsEqual859         static bool compare( const T1 &t1, const T2 &t2 ) {
860             return t1 == t2;
861         }
862         template <typename T1, typename T2>
operatorIsEqual863         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