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 |
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> |
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 | } |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 */ |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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> |
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> |
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 { |
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> |
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()) |
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; } |
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> |
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 | |