151c0b2f7Stbbdev /* 2b15aabb3Stbbdev Copyright (c) 2005-2021 Intel Corporation 351c0b2f7Stbbdev 451c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License"); 551c0b2f7Stbbdev you may not use this file except in compliance with the License. 651c0b2f7Stbbdev You may obtain a copy of the License at 751c0b2f7Stbbdev 851c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0 951c0b2f7Stbbdev 1051c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software 1151c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS, 1251c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1351c0b2f7Stbbdev See the License for the specific language governing permissions and 1451c0b2f7Stbbdev limitations under the License. 1551c0b2f7Stbbdev */ 1651c0b2f7Stbbdev 1751c0b2f7Stbbdev #ifndef __TBB_test_common_custom_allocators_H 1851c0b2f7Stbbdev #define __TBB_test_common_custom_allocators_H 1951c0b2f7Stbbdev 2051c0b2f7Stbbdev #include "test.h" 2149e08aacStbbdev #include <oneapi/tbb/detail/_allocator_traits.h> 2251c0b2f7Stbbdev #include <memory> 2351c0b2f7Stbbdev #include <atomic> 2451c0b2f7Stbbdev #include <scoped_allocator> 2551c0b2f7Stbbdev 2651c0b2f7Stbbdev template <typename CounterType> 2751c0b2f7Stbbdev struct ArenaData { 2851c0b2f7Stbbdev char* const my_buffer; 2951c0b2f7Stbbdev const std::size_t my_size; 3051c0b2f7Stbbdev CounterType my_allocated; // in bytes 3151c0b2f7Stbbdev 3251c0b2f7Stbbdev template <typename T> ArenaDataArenaData3351c0b2f7Stbbdev ArenaData( T* buf, std::size_t sz ) noexcept 3451c0b2f7Stbbdev : my_buffer(reinterpret_cast<char*>(buf)), 3551c0b2f7Stbbdev my_size(sz * sizeof(T)) 3651c0b2f7Stbbdev { 3751c0b2f7Stbbdev my_allocated = 0; 3851c0b2f7Stbbdev } 3951c0b2f7Stbbdev 4051c0b2f7Stbbdev ArenaData& operator=( const ArenaData& ) = delete; 4151c0b2f7Stbbdev }; // struct ArenaData 4251c0b2f7Stbbdev 4351c0b2f7Stbbdev template <typename T, typename POCMA = std::false_type, typename CounterType = std::size_t> 4451c0b2f7Stbbdev struct ArenaAllocator { 4551c0b2f7Stbbdev using arena_data_type = ArenaData<CounterType>; 4651c0b2f7Stbbdev 4751c0b2f7Stbbdev arena_data_type* my_data; 4851c0b2f7Stbbdev 4951c0b2f7Stbbdev using value_type = T; 5051c0b2f7Stbbdev using propagate_on_container_move_assignment = POCMA; 5151c0b2f7Stbbdev 5251c0b2f7Stbbdev template <typename U> 5351c0b2f7Stbbdev struct rebind { 5451c0b2f7Stbbdev using other = ArenaAllocator<U, POCMA, CounterType>; 5551c0b2f7Stbbdev }; 5651c0b2f7Stbbdev 5751c0b2f7Stbbdev ArenaAllocator() = default; ArenaAllocatorArenaAllocator5851c0b2f7Stbbdev ArenaAllocator( arena_data_type& data ) noexcept : my_data(&data) {} 5951c0b2f7Stbbdev 6051c0b2f7Stbbdev template <typename U, typename POCMA2> ArenaAllocatorArenaAllocator6151c0b2f7Stbbdev ArenaAllocator( const ArenaAllocator<U, POCMA2, CounterType>& other ) noexcept 6251c0b2f7Stbbdev : my_data(other.my_data) {} 6351c0b2f7Stbbdev swapArenaAllocator6451c0b2f7Stbbdev friend void swap( ArenaAllocator& lhs, ArenaAllocator& rhs ) { 6551c0b2f7Stbbdev using std::swap; 6651c0b2f7Stbbdev swap(lhs.my_data, rhs.my_data); 6751c0b2f7Stbbdev } 6851c0b2f7Stbbdev addressArenaAllocator6951c0b2f7Stbbdev value_type* address( value_type& x ) const { return &x; } addressArenaAllocator7051c0b2f7Stbbdev const value_type* address( const value_type& x ) const { return &x; } 7151c0b2f7Stbbdev allocateArenaAllocator7251c0b2f7Stbbdev value_type* allocate( std::size_t n ) { 7351c0b2f7Stbbdev std::size_t new_size = (my_data->my_allocated += n * sizeof(T)); 7451c0b2f7Stbbdev REQUIRE_MESSAGE(my_data->my_allocated <= my_data->my_size, "Trying to allocate more than was reserved"); 7551c0b2f7Stbbdev char* result = &(my_data->my_buffer[new_size - n * sizeof(T)]); 7651c0b2f7Stbbdev return reinterpret_cast<value_type*>(result); 7751c0b2f7Stbbdev } 7851c0b2f7Stbbdev deallocateArenaAllocator7951c0b2f7Stbbdev void deallocate( value_type* ptr, std::size_t n ) { 8051c0b2f7Stbbdev char* p = reinterpret_cast<char*>(ptr); 8151c0b2f7Stbbdev REQUIRE_MESSAGE((p >= my_data->my_buffer && p <= my_data->my_buffer + my_data->my_size), 8251c0b2f7Stbbdev "Trying to deallocate pointer not from arena"); 8351c0b2f7Stbbdev REQUIRE_MESSAGE((p + n * sizeof(T) <= my_data->my_buffer + my_data->my_size), 8451c0b2f7Stbbdev "Trying to deallocate pointer not from arena"); 8551c0b2f7Stbbdev // utils::suppress_unused_warning(p, n); 8651c0b2f7Stbbdev } 8751c0b2f7Stbbdev max_sizeArenaAllocator8851c0b2f7Stbbdev std::size_t max_size() const noexcept { 8951c0b2f7Stbbdev return my_data->my_size / sizeof(T); 9051c0b2f7Stbbdev } 9151c0b2f7Stbbdev }; // class ArenaAllocator 9251c0b2f7Stbbdev 9351c0b2f7Stbbdev template <typename T, typename U, typename POCMA, typename C> 9451c0b2f7Stbbdev bool operator==( const ArenaAllocator<T, POCMA, C>& lhs, const ArenaAllocator<U, POCMA, C>& rhs ) { 9551c0b2f7Stbbdev return lhs.my_data == rhs.my_data; 9651c0b2f7Stbbdev } 9751c0b2f7Stbbdev 9851c0b2f7Stbbdev template <typename T, typename U, typename POCMA, typename C> 9951c0b2f7Stbbdev bool operator!=( const ArenaAllocator<T, POCMA, C>& lhs, const ArenaAllocator<U, POCMA, C>& rhs ) { 10051c0b2f7Stbbdev return !(lhs == rhs); 10151c0b2f7Stbbdev } 10251c0b2f7Stbbdev 10351c0b2f7Stbbdev template <typename BaseAllocatorType> 10451c0b2f7Stbbdev class LocalCountingAllocator : public BaseAllocatorType { 10551c0b2f7Stbbdev using base_type = BaseAllocatorType; 106b15aabb3Stbbdev using base_traits = tbb::detail::allocator_traits<base_type>; 10751c0b2f7Stbbdev using counter_type = std::atomic<std::size_t>; 10851c0b2f7Stbbdev public: 10951c0b2f7Stbbdev using value_type = typename base_type::value_type; 11051c0b2f7Stbbdev 11151c0b2f7Stbbdev std::size_t max_items; 11251c0b2f7Stbbdev counter_type items_allocated; 11351c0b2f7Stbbdev counter_type items_freed; 11451c0b2f7Stbbdev counter_type items_constructed; 11551c0b2f7Stbbdev counter_type items_destroyed; 11651c0b2f7Stbbdev counter_type allocations; 11751c0b2f7Stbbdev counter_type frees; 11851c0b2f7Stbbdev set_counters(std::size_t it_allocated,std::size_t it_freed,std::size_t it_constructed,std::size_t it_destroyed,std::size_t allocs,std::size_t fres)11951c0b2f7Stbbdev void set_counters( std::size_t it_allocated, std::size_t it_freed, 12051c0b2f7Stbbdev std::size_t it_constructed, std::size_t it_destroyed, 12151c0b2f7Stbbdev std::size_t allocs, std::size_t fres ) { 12251c0b2f7Stbbdev items_allocated = it_allocated; // TODO: may be store 12351c0b2f7Stbbdev items_freed = it_freed; 12451c0b2f7Stbbdev items_constructed = it_constructed; 12551c0b2f7Stbbdev items_destroyed = it_destroyed; 12651c0b2f7Stbbdev allocations = allocs; 12751c0b2f7Stbbdev frees = fres; 12851c0b2f7Stbbdev } 12951c0b2f7Stbbdev 13051c0b2f7Stbbdev template <typename Allocator> set_counters(const Allocator & alloc)13151c0b2f7Stbbdev void set_counters( const Allocator& alloc ) { 13251c0b2f7Stbbdev set_counters(alloc.items_allocated, alloc.items_freed, alloc.items_constructed, 13351c0b2f7Stbbdev alloc.items_destroyed, alloc.allocations, alloc.frees); 13451c0b2f7Stbbdev } 13551c0b2f7Stbbdev clear_counters()13651c0b2f7Stbbdev void clear_counters() { 13751c0b2f7Stbbdev set_counters(0, 0, 0, 0, 0, 0); 13851c0b2f7Stbbdev } 13951c0b2f7Stbbdev 14051c0b2f7Stbbdev template <typename U> 141b15aabb3Stbbdev struct rebind { 14251c0b2f7Stbbdev using other = LocalCountingAllocator<typename base_traits::template rebind_alloc<U>>; 14351c0b2f7Stbbdev }; 14451c0b2f7Stbbdev LocalCountingAllocator()14551c0b2f7Stbbdev LocalCountingAllocator() : max_items{0} { clear_counters(); } 14651c0b2f7Stbbdev LocalCountingAllocator(const LocalCountingAllocator & other)14751c0b2f7Stbbdev LocalCountingAllocator( const LocalCountingAllocator& other ) 14851c0b2f7Stbbdev : base_type(other), max_items{other.max_items} { set_counters(other); } 14951c0b2f7Stbbdev 15051c0b2f7Stbbdev template <typename U> LocalCountingAllocator(const LocalCountingAllocator<U> & other)15151c0b2f7Stbbdev LocalCountingAllocator( const LocalCountingAllocator<U>& other ) 15251c0b2f7Stbbdev : base_type(other), max_items{other.max_items} { set_counters(other); } 15351c0b2f7Stbbdev 15451c0b2f7Stbbdev LocalCountingAllocator& operator=( const LocalCountingAllocator& other ) { 15551c0b2f7Stbbdev base_type::operator=(other); 15651c0b2f7Stbbdev max_items = other.max_items; 15751c0b2f7Stbbdev set_counters(other); 15851c0b2f7Stbbdev return *this; 15951c0b2f7Stbbdev } 16051c0b2f7Stbbdev allocate(std::size_t n)16151c0b2f7Stbbdev value_type* allocate( std::size_t n ) { 16251c0b2f7Stbbdev if (max_items != 0 && items_allocated + n >= max_items) { 16351c0b2f7Stbbdev TBB_TEST_THROW(std::bad_alloc()); 16451c0b2f7Stbbdev } 16551c0b2f7Stbbdev value_type* ptr = static_cast<base_type*>(this)->allocate(n); 16651c0b2f7Stbbdev ++allocations; 16751c0b2f7Stbbdev items_allocated += n; 16851c0b2f7Stbbdev return ptr; 16951c0b2f7Stbbdev } 17051c0b2f7Stbbdev deallocate(value_type * ptr,std::size_t n)17151c0b2f7Stbbdev void deallocate( value_type* ptr, std::size_t n ) { 17251c0b2f7Stbbdev ++frees; 17351c0b2f7Stbbdev items_freed += n; 17451c0b2f7Stbbdev static_cast<base_type*>(this)->deallocate(ptr, n); 17551c0b2f7Stbbdev } 17651c0b2f7Stbbdev 17751c0b2f7Stbbdev template <typename U, typename... Args> construct(U * ptr,Args &&...args)17851c0b2f7Stbbdev void construct( U* ptr, Args&&... args ) { 179b15aabb3Stbbdev base_traits::construct(*this, ptr, std::forward<Args>(args)...); 18051c0b2f7Stbbdev ++items_constructed; 18151c0b2f7Stbbdev } 18251c0b2f7Stbbdev 18351c0b2f7Stbbdev template <typename U> destroy(U * ptr)18451c0b2f7Stbbdev void destroy( U* ptr ) { 18551c0b2f7Stbbdev base_traits::destroy(*this, ptr); 18651c0b2f7Stbbdev ++items_destroyed; 18751c0b2f7Stbbdev } 18851c0b2f7Stbbdev set_limits(std::size_t max)18951c0b2f7Stbbdev void set_limits( std::size_t max ) { 19051c0b2f7Stbbdev max_items = max; 19151c0b2f7Stbbdev } 19251c0b2f7Stbbdev }; // class LocalCountingAllocator 19351c0b2f7Stbbdev 19451c0b2f7Stbbdev struct AllocatorCounters { 19551c0b2f7Stbbdev using counter_type = std::atomic<std::size_t>; 19651c0b2f7Stbbdev 19751c0b2f7Stbbdev counter_type items_allocated; 19851c0b2f7Stbbdev counter_type items_freed; 19951c0b2f7Stbbdev counter_type items_constructed; 20051c0b2f7Stbbdev counter_type items_destroyed; 20151c0b2f7Stbbdev counter_type allocations; 20251c0b2f7Stbbdev counter_type frees; 20351c0b2f7Stbbdev 20451c0b2f7Stbbdev AllocatorCounters() = default; 20551c0b2f7Stbbdev AllocatorCountersAllocatorCounters20651c0b2f7Stbbdev AllocatorCounters( std::size_t it_allocated, std::size_t it_freed, std::size_t it_constructed, 20751c0b2f7Stbbdev std::size_t it_destroyed, std::size_t allocs, std::size_t fres ) 20851c0b2f7Stbbdev : items_allocated(it_allocated), items_freed(it_freed), 20951c0b2f7Stbbdev items_constructed(it_constructed), items_destroyed(it_destroyed), 21051c0b2f7Stbbdev allocations(allocs), frees(fres) {} 21151c0b2f7Stbbdev AllocatorCountersAllocatorCounters21251c0b2f7Stbbdev AllocatorCounters( const AllocatorCounters& other ) 21351c0b2f7Stbbdev : items_allocated(other.items_allocated.load()), 21451c0b2f7Stbbdev items_freed(other.items_allocated.load()), 21551c0b2f7Stbbdev items_constructed(other.items_constructed.load()), 21651c0b2f7Stbbdev items_destroyed(other.items_destroyed.load()), 21751c0b2f7Stbbdev allocations(other.allocations.load()), 21851c0b2f7Stbbdev frees(other.allocations.load()) {} 21951c0b2f7Stbbdev 22051c0b2f7Stbbdev AllocatorCounters& operator=( const AllocatorCounters& other ) { 22151c0b2f7Stbbdev items_allocated.store(other.items_allocated.load()); 22251c0b2f7Stbbdev items_freed.store(other.items_freed.load()); 22351c0b2f7Stbbdev items_constructed.store(other.items_constructed.load()); 22451c0b2f7Stbbdev items_destroyed.store(other.items_destroyed.load()); 22551c0b2f7Stbbdev allocations.store(other.allocations.load()); 22651c0b2f7Stbbdev frees.store(other.frees.load()); 22751c0b2f7Stbbdev return *this; 22851c0b2f7Stbbdev } 22951c0b2f7Stbbdev 23051c0b2f7Stbbdev friend bool operator==( const AllocatorCounters& lhs, const AllocatorCounters& rhs ) { 23151c0b2f7Stbbdev return lhs.items_allocated == rhs.items_allocated && 23251c0b2f7Stbbdev lhs.items_freed == rhs.items_freed && 23351c0b2f7Stbbdev lhs.items_constructed == rhs.items_constructed && 23451c0b2f7Stbbdev lhs.items_destroyed == rhs.items_destroyed && 23551c0b2f7Stbbdev lhs.allocations == rhs.allocations && 23651c0b2f7Stbbdev lhs.frees == rhs.frees; 23751c0b2f7Stbbdev } 23851c0b2f7Stbbdev }; // struct AllocatorCounters 23951c0b2f7Stbbdev 24051c0b2f7Stbbdev template <typename BaseAllocatorType> 24151c0b2f7Stbbdev class StaticCountingAllocator : public BaseAllocatorType { 24251c0b2f7Stbbdev using base_type = BaseAllocatorType; 243b15aabb3Stbbdev using base_traits = tbb::detail::allocator_traits<BaseAllocatorType>; 24451c0b2f7Stbbdev using counter_type = std::atomic<std::size_t>; 24551c0b2f7Stbbdev public: 24651c0b2f7Stbbdev using value_type = typename base_type::value_type; 24751c0b2f7Stbbdev using pointer = value_type*; 24851c0b2f7Stbbdev using counters_type = AllocatorCounters; 24951c0b2f7Stbbdev 25051c0b2f7Stbbdev static std::size_t max_items; 25151c0b2f7Stbbdev static counter_type items_allocated; 25251c0b2f7Stbbdev static counter_type items_freed; 25351c0b2f7Stbbdev static counter_type items_constructed; 25451c0b2f7Stbbdev static counter_type items_destroyed; 25551c0b2f7Stbbdev static counter_type allocations; 25651c0b2f7Stbbdev static counter_type frees; 25751c0b2f7Stbbdev static bool throwing; 25851c0b2f7Stbbdev 25951c0b2f7Stbbdev template <typename U> 260b15aabb3Stbbdev struct rebind { 26151c0b2f7Stbbdev using other = StaticCountingAllocator<typename base_traits::template rebind_alloc<U>>; 26251c0b2f7Stbbdev }; 26351c0b2f7Stbbdev 26451c0b2f7Stbbdev StaticCountingAllocator() = default; 26551c0b2f7Stbbdev 26651c0b2f7Stbbdev template <typename U> StaticCountingAllocator(const StaticCountingAllocator<U> & other)26751c0b2f7Stbbdev StaticCountingAllocator( const StaticCountingAllocator<U>& other ) : base_type(other) {} 26851c0b2f7Stbbdev allocate(std::size_t n)26951c0b2f7Stbbdev value_type* allocate( std::size_t n ) { 27051c0b2f7Stbbdev if (max_items != 0 && items_allocated + n >= max_items) { 27151c0b2f7Stbbdev if (throwing) { 27251c0b2f7Stbbdev TBB_TEST_THROW(std::bad_alloc{}); 27351c0b2f7Stbbdev } 27451c0b2f7Stbbdev return nullptr; 27551c0b2f7Stbbdev } 27651c0b2f7Stbbdev value_type* ptr = static_cast<base_type*>(this)->allocate(n); 27751c0b2f7Stbbdev ++allocations; 27851c0b2f7Stbbdev items_allocated += n; 27951c0b2f7Stbbdev return ptr; 28051c0b2f7Stbbdev } 28151c0b2f7Stbbdev deallocate(const pointer ptr,const std::size_t n)28251c0b2f7Stbbdev void deallocate(const pointer ptr, const std::size_t n){ 28351c0b2f7Stbbdev ++frees; 28451c0b2f7Stbbdev items_freed += n; 28551c0b2f7Stbbdev static_cast<base_type*>(this)->deallocate(ptr, n); 28651c0b2f7Stbbdev } 28751c0b2f7Stbbdev 28851c0b2f7Stbbdev template <typename U, typename... Args> construct(U * ptr,Args &&...args)28951c0b2f7Stbbdev void construct( U* ptr, Args&&... args ) { 29051c0b2f7Stbbdev ++items_constructed; 291b15aabb3Stbbdev base_traits::construct(*this, ptr, std::forward<Args>(args)...); 29251c0b2f7Stbbdev } 29351c0b2f7Stbbdev 29451c0b2f7Stbbdev template <typename U> destroy(U * ptr)29551c0b2f7Stbbdev void destroy( U* ptr ) { 29651c0b2f7Stbbdev ++items_destroyed; 297b15aabb3Stbbdev base_traits::destroy(*this, ptr); 29851c0b2f7Stbbdev } 29951c0b2f7Stbbdev counters()30051c0b2f7Stbbdev static AllocatorCounters counters() { 30151c0b2f7Stbbdev return {items_allocated, items_freed, items_constructed, items_destroyed, allocations, frees}; 30251c0b2f7Stbbdev } 30351c0b2f7Stbbdev init_counters()30451c0b2f7Stbbdev static void init_counters() { 30551c0b2f7Stbbdev items_allocated = 0; 30651c0b2f7Stbbdev items_freed = 0; 30751c0b2f7Stbbdev items_constructed = 0; 30851c0b2f7Stbbdev items_destroyed = 0; 30951c0b2f7Stbbdev allocations = 0; 31051c0b2f7Stbbdev frees = 0; 31151c0b2f7Stbbdev } 31251c0b2f7Stbbdev 31351c0b2f7Stbbdev static void set_limits( std::size_t max = 0, bool do_throw = true ) { 31451c0b2f7Stbbdev max_items = max; 31551c0b2f7Stbbdev throwing = do_throw; 31651c0b2f7Stbbdev } 31751c0b2f7Stbbdev }; // class StaticCountingAllocator 31851c0b2f7Stbbdev 31951c0b2f7Stbbdev template <typename T> 32051c0b2f7Stbbdev std::size_t StaticCountingAllocator<T>::max_items; 32151c0b2f7Stbbdev template <typename T> 32251c0b2f7Stbbdev std::atomic<std::size_t> StaticCountingAllocator<T>::items_allocated; 32351c0b2f7Stbbdev template <typename T> 32451c0b2f7Stbbdev std::atomic<std::size_t> StaticCountingAllocator<T>::items_freed; 32551c0b2f7Stbbdev template <typename T> 32651c0b2f7Stbbdev std::atomic<std::size_t> StaticCountingAllocator<T>::items_constructed; 32751c0b2f7Stbbdev template <typename T> 32851c0b2f7Stbbdev std::atomic<std::size_t> StaticCountingAllocator<T>::items_destroyed; 32951c0b2f7Stbbdev template <typename T> 33051c0b2f7Stbbdev std::atomic<std::size_t> StaticCountingAllocator<T>::allocations; 33151c0b2f7Stbbdev template <typename T> 33251c0b2f7Stbbdev std::atomic<std::size_t> StaticCountingAllocator<T>::frees; 33351c0b2f7Stbbdev template <typename T> 33451c0b2f7Stbbdev bool StaticCountingAllocator<T>::throwing; 33551c0b2f7Stbbdev 33651c0b2f7Stbbdev struct StaticSharedCountingAllocatorBase { 33751c0b2f7Stbbdev using counter_type = std::atomic<std::size_t>; 33851c0b2f7Stbbdev using counters_type = AllocatorCounters; 33951c0b2f7Stbbdev static std::size_t max_items; 34051c0b2f7Stbbdev static counter_type items_allocated; 34151c0b2f7Stbbdev static counter_type items_freed; 34251c0b2f7Stbbdev static counter_type items_constructed; 34351c0b2f7Stbbdev static counter_type items_destroyed; 34451c0b2f7Stbbdev static counter_type allocations; 34551c0b2f7Stbbdev static counter_type frees; 34651c0b2f7Stbbdev static bool throwing; 34751c0b2f7Stbbdev countersStaticSharedCountingAllocatorBase34851c0b2f7Stbbdev static counters_type counters() { 34951c0b2f7Stbbdev return { items_allocated.load(), items_freed.load(), items_constructed.load(), 35051c0b2f7Stbbdev items_destroyed.load(), allocations.load(), frees.load() }; 35151c0b2f7Stbbdev } 35251c0b2f7Stbbdev init_countersStaticSharedCountingAllocatorBase35351c0b2f7Stbbdev static void init_counters() { 35451c0b2f7Stbbdev items_allocated = 0; 35551c0b2f7Stbbdev items_freed = 0; 35651c0b2f7Stbbdev items_constructed = 0; 35751c0b2f7Stbbdev items_destroyed = 0; 35851c0b2f7Stbbdev allocations = 0; 35951c0b2f7Stbbdev frees = 0; 36051c0b2f7Stbbdev } 36151c0b2f7Stbbdev 36251c0b2f7Stbbdev static void set_limits( std::size_t max = 0, bool do_throw = true ) { 36351c0b2f7Stbbdev max_items = max; 36451c0b2f7Stbbdev throwing = do_throw; 36551c0b2f7Stbbdev } 36651c0b2f7Stbbdev }; // class StaticSharedCountingAllocatorBase 36751c0b2f7Stbbdev 36851c0b2f7Stbbdev std::size_t StaticSharedCountingAllocatorBase::max_items; 36951c0b2f7Stbbdev std::atomic<std::size_t> StaticSharedCountingAllocatorBase::items_constructed; 37051c0b2f7Stbbdev std::atomic<std::size_t> StaticSharedCountingAllocatorBase::items_destroyed; 37151c0b2f7Stbbdev std::atomic<std::size_t> StaticSharedCountingAllocatorBase::items_allocated; 37251c0b2f7Stbbdev std::atomic<std::size_t> StaticSharedCountingAllocatorBase::items_freed; 37351c0b2f7Stbbdev std::atomic<std::size_t> StaticSharedCountingAllocatorBase::allocations; 37451c0b2f7Stbbdev std::atomic<std::size_t> StaticSharedCountingAllocatorBase::frees; 37551c0b2f7Stbbdev bool StaticSharedCountingAllocatorBase::throwing; 37651c0b2f7Stbbdev 37751c0b2f7Stbbdev template <typename BaseAllocatorType> 37851c0b2f7Stbbdev class StaticSharedCountingAllocator 37951c0b2f7Stbbdev : public StaticSharedCountingAllocatorBase, public BaseAllocatorType 38051c0b2f7Stbbdev { 38151c0b2f7Stbbdev using base_type = StaticSharedCountingAllocatorBase; 38251c0b2f7Stbbdev using alloc_base_type = BaseAllocatorType; 38351c0b2f7Stbbdev using base_traits = tbb::detail::allocator_traits<BaseAllocatorType>; 38451c0b2f7Stbbdev public: 38551c0b2f7Stbbdev using value_type = typename alloc_base_type::value_type; 38651c0b2f7Stbbdev using counters_type = AllocatorCounters; 38751c0b2f7Stbbdev 38851c0b2f7Stbbdev template <typename U> 38951c0b2f7Stbbdev struct rebind { 39051c0b2f7Stbbdev using other = StaticSharedCountingAllocator<typename base_traits::template rebind_alloc<U>>; 39151c0b2f7Stbbdev }; 39251c0b2f7Stbbdev 39351c0b2f7Stbbdev StaticSharedCountingAllocator() = default; 39451c0b2f7Stbbdev StaticSharedCountingAllocator( const StaticSharedCountingAllocator& ) = default; 395*1168c5cbSvlserov StaticSharedCountingAllocator& operator=( const StaticSharedCountingAllocator& ) = default; 39651c0b2f7Stbbdev 39751c0b2f7Stbbdev template <typename U> StaticSharedCountingAllocator(const StaticSharedCountingAllocator<U> & other)39851c0b2f7Stbbdev StaticSharedCountingAllocator( const StaticSharedCountingAllocator<U>& other) : alloc_base_type(other) {} 39951c0b2f7Stbbdev 40051c0b2f7Stbbdev // Constructor from the base allocator with any type 40151c0b2f7Stbbdev template <typename Alloc> StaticSharedCountingAllocator(const Alloc & src)40251c0b2f7Stbbdev StaticSharedCountingAllocator( const Alloc& src ) noexcept 40351c0b2f7Stbbdev : alloc_base_type(src) {} 40451c0b2f7Stbbdev allocate(std::size_t n)40551c0b2f7Stbbdev value_type* allocate( std::size_t n ) { 40651c0b2f7Stbbdev if (base_type::max_items != 0 && 40751c0b2f7Stbbdev base_type::items_allocated + n >= base_type::max_items) { 40851c0b2f7Stbbdev if (base_type::throwing) { 40951c0b2f7Stbbdev TBB_TEST_THROW(std::bad_alloc()); 41051c0b2f7Stbbdev } 41151c0b2f7Stbbdev return nullptr; 41251c0b2f7Stbbdev } 41351c0b2f7Stbbdev ++base_type::allocations; 41451c0b2f7Stbbdev base_type::items_allocated += n; 41551c0b2f7Stbbdev return static_cast<alloc_base_type*>(this)->allocate(n); 41651c0b2f7Stbbdev } 41751c0b2f7Stbbdev deallocate(value_type * ptr,std::size_t n)41851c0b2f7Stbbdev void deallocate( value_type* ptr, std::size_t n ) { 41951c0b2f7Stbbdev ++base_type::frees; 42051c0b2f7Stbbdev base_type::items_freed += n; 42151c0b2f7Stbbdev static_cast<alloc_base_type*>(this)->deallocate(ptr, n); 42251c0b2f7Stbbdev } 42351c0b2f7Stbbdev 42451c0b2f7Stbbdev template <typename U, typename... Args> construct(U * ptr,Args &&...args)42551c0b2f7Stbbdev void construct( U* ptr, Args&&... args ) { 42651c0b2f7Stbbdev base_traits::construct(*this, ptr, std::forward<Args>(args)...); 42751c0b2f7Stbbdev ++base_type::items_constructed; 42851c0b2f7Stbbdev } 42951c0b2f7Stbbdev 43051c0b2f7Stbbdev template <typename U> destroy(U * ptr)43151c0b2f7Stbbdev void destroy( U* ptr ) { 43251c0b2f7Stbbdev base_traits::destroy(*this, ptr); 43351c0b2f7Stbbdev ++base_type::items_destroyed; 43451c0b2f7Stbbdev } 43551c0b2f7Stbbdev }; // class StaticSharedCountingAllocator 43651c0b2f7Stbbdev 43751c0b2f7Stbbdev template <typename Allocator> 43851c0b2f7Stbbdev class AllocatorAwareData { 43951c0b2f7Stbbdev public: 44051c0b2f7Stbbdev static bool assert_on_constructions; 44151c0b2f7Stbbdev using allocator_type = Allocator; 44251c0b2f7Stbbdev 44351c0b2f7Stbbdev AllocatorAwareData( const allocator_type& allocator = allocator_type() ) my_allocator(allocator)44451c0b2f7Stbbdev : my_allocator(allocator), my_value(0) {} 44551c0b2f7Stbbdev 44651c0b2f7Stbbdev AllocatorAwareData( int v, const allocator_type& allocator = allocator_type() ) my_allocator(allocator)44751c0b2f7Stbbdev : my_allocator(allocator), my_value(v) {} 44851c0b2f7Stbbdev AllocatorAwareData(const AllocatorAwareData & rhs)44951c0b2f7Stbbdev AllocatorAwareData( const AllocatorAwareData& rhs ) 45051c0b2f7Stbbdev : my_allocator(rhs.my_allocator), my_value(rhs.my_value) 45151c0b2f7Stbbdev { 45251c0b2f7Stbbdev REQUIRE_MESSAGE(!assert_on_constructions, "Allocator should propagate to the data during copy construction"); 45351c0b2f7Stbbdev } 45451c0b2f7Stbbdev AllocatorAwareData(AllocatorAwareData && rhs)45551c0b2f7Stbbdev AllocatorAwareData( AllocatorAwareData&& rhs) 45651c0b2f7Stbbdev : my_allocator(rhs.my_allocator), my_value(rhs.my_value) 45751c0b2f7Stbbdev { 45851c0b2f7Stbbdev REQUIRE_MESSAGE(!assert_on_constructions, "Allocator should propagate to the data during move construction"); 45951c0b2f7Stbbdev } 46051c0b2f7Stbbdev AllocatorAwareData(const AllocatorAwareData & rhs,const allocator_type & allocator)46151c0b2f7Stbbdev AllocatorAwareData( const AllocatorAwareData& rhs, const allocator_type& allocator ) 46251c0b2f7Stbbdev : my_allocator(allocator), my_value(rhs.my_value) {} 46351c0b2f7Stbbdev AllocatorAwareData(AllocatorAwareData && rhs,const allocator_type & allocator)46451c0b2f7Stbbdev AllocatorAwareData( AllocatorAwareData&& rhs, const allocator_type& allocator ) 46551c0b2f7Stbbdev : my_allocator(allocator), my_value(rhs.my_value) {} 46651c0b2f7Stbbdev 46751c0b2f7Stbbdev AllocatorAwareData& operator=( const AllocatorAwareData& other ) { 46851c0b2f7Stbbdev my_value = other.my_value; 46951c0b2f7Stbbdev return *this; 47051c0b2f7Stbbdev } 47151c0b2f7Stbbdev value()47251c0b2f7Stbbdev int value() const { return my_value; } 47351c0b2f7Stbbdev activate()47451c0b2f7Stbbdev static void activate() { assert_on_constructions = true; } deactivate()47551c0b2f7Stbbdev static void deactivate() { assert_on_constructions = false; } 47651c0b2f7Stbbdev private: 47751c0b2f7Stbbdev allocator_type my_allocator; 47851c0b2f7Stbbdev int my_value; 47951c0b2f7Stbbdev }; // class AllocatorAwareData 48051c0b2f7Stbbdev 48151c0b2f7Stbbdev template <typename Allocator> 48251c0b2f7Stbbdev bool AllocatorAwareData<Allocator>::assert_on_constructions = false; 48351c0b2f7Stbbdev 48451c0b2f7Stbbdev template <typename Allocator> 48551c0b2f7Stbbdev bool operator==( const AllocatorAwareData<Allocator>& lhs, const AllocatorAwareData<Allocator>& rhs ) { 48651c0b2f7Stbbdev return lhs.value() == rhs.value(); 48751c0b2f7Stbbdev } 48851c0b2f7Stbbdev 48951c0b2f7Stbbdev template <typename Allocator> 49051c0b2f7Stbbdev bool operator<( const AllocatorAwareData<Allocator>& lhs, const AllocatorAwareData<Allocator>& rhs ) { 49151c0b2f7Stbbdev return lhs.value() < rhs.value(); 49251c0b2f7Stbbdev } 49351c0b2f7Stbbdev 49451c0b2f7Stbbdev namespace std { 49551c0b2f7Stbbdev template <typename Allocator> 49651c0b2f7Stbbdev struct hash<AllocatorAwareData<Allocator>> { 49751c0b2f7Stbbdev std::size_t operator()(const AllocatorAwareData<Allocator>& obj) const { 49851c0b2f7Stbbdev return std::hash<int>()(obj.value()); 49951c0b2f7Stbbdev } 50051c0b2f7Stbbdev }; 50151c0b2f7Stbbdev } 50251c0b2f7Stbbdev 50351c0b2f7Stbbdev template <typename Allocator, typename POCMA = std::false_type, typename POCCA = std::false_type, 50451c0b2f7Stbbdev typename POCS = std::false_type> 50551c0b2f7Stbbdev struct PropagatingAllocator : Allocator { 50651c0b2f7Stbbdev using base_allocator_traits = std::allocator_traits<Allocator>; 50751c0b2f7Stbbdev using propagate_on_container_copy_assignment = POCCA; 50851c0b2f7Stbbdev using propagate_on_container_move_assignment = POCMA; 50951c0b2f7Stbbdev using propagate_on_container_swap = POCS; 51051c0b2f7Stbbdev bool* propagated_on_copy_assignment; 51151c0b2f7Stbbdev bool* propagated_on_move_assignment; 51251c0b2f7Stbbdev bool* propagated_on_swap; 51351c0b2f7Stbbdev bool* selected_on_copy_construction; 51451c0b2f7Stbbdev 51551c0b2f7Stbbdev template <typename U> 51651c0b2f7Stbbdev struct rebind { 51751c0b2f7Stbbdev using other = PropagatingAllocator<typename base_allocator_traits::template rebind_alloc<U>, 51851c0b2f7Stbbdev POCMA, POCCA, POCS>; 51951c0b2f7Stbbdev }; 52051c0b2f7Stbbdev 52151c0b2f7Stbbdev PropagatingAllocator() 52251c0b2f7Stbbdev : propagated_on_copy_assignment(nullptr), 52351c0b2f7Stbbdev propagated_on_move_assignment(nullptr), 52451c0b2f7Stbbdev propagated_on_swap(nullptr), 52551c0b2f7Stbbdev selected_on_copy_construction(nullptr) {} 52651c0b2f7Stbbdev 52751c0b2f7Stbbdev PropagatingAllocator( bool& poca, bool& poma, bool& pos, bool& soc ) 52851c0b2f7Stbbdev : propagated_on_copy_assignment(&poca), 52951c0b2f7Stbbdev propagated_on_move_assignment(&poma), 53051c0b2f7Stbbdev propagated_on_swap(&pos), 53151c0b2f7Stbbdev selected_on_copy_construction(&soc) {} 53251c0b2f7Stbbdev 53351c0b2f7Stbbdev PropagatingAllocator( const PropagatingAllocator& other ) 53451c0b2f7Stbbdev : Allocator(other), 53551c0b2f7Stbbdev propagated_on_copy_assignment(other.propagated_on_copy_assignment), 53651c0b2f7Stbbdev propagated_on_move_assignment(other.propagated_on_move_assignment), 53751c0b2f7Stbbdev propagated_on_swap(other.propagated_on_swap), 53851c0b2f7Stbbdev selected_on_copy_construction(other.selected_on_copy_construction) {} 53951c0b2f7Stbbdev 54051c0b2f7Stbbdev template <typename Allocator2> 54151c0b2f7Stbbdev PropagatingAllocator( const PropagatingAllocator<Allocator2, POCMA, POCCA, POCS>& other ) 54251c0b2f7Stbbdev : Allocator(other), 54351c0b2f7Stbbdev propagated_on_copy_assignment(other.propagated_on_copy_assignment), 54451c0b2f7Stbbdev propagated_on_move_assignment(other.propagated_on_move_assignment), 54551c0b2f7Stbbdev propagated_on_swap(other.propagated_on_swap), 54651c0b2f7Stbbdev selected_on_copy_construction(other.selected_on_copy_construction) {} 54751c0b2f7Stbbdev 54851c0b2f7Stbbdev PropagatingAllocator& operator=( const PropagatingAllocator& ) { 54951c0b2f7Stbbdev REQUIRE_MESSAGE(POCCA::value, "Allocator should not copy assign if POCCA is false"); 55051c0b2f7Stbbdev if (propagated_on_copy_assignment) 55151c0b2f7Stbbdev *propagated_on_copy_assignment = true; 55251c0b2f7Stbbdev return *this; 55351c0b2f7Stbbdev } 55451c0b2f7Stbbdev 55551c0b2f7Stbbdev PropagatingAllocator& operator=( PropagatingAllocator&& ) { 55651c0b2f7Stbbdev REQUIRE_MESSAGE(POCMA::value, "Allocator should not move assign if POCMA is false"); 55751c0b2f7Stbbdev if (propagated_on_move_assignment) 55851c0b2f7Stbbdev *propagated_on_move_assignment = true; 55951c0b2f7Stbbdev return *this; 56051c0b2f7Stbbdev } 56151c0b2f7Stbbdev 56251c0b2f7Stbbdev PropagatingAllocator select_on_container_copy_construction() const { 56351c0b2f7Stbbdev if (selected_on_copy_construction) 56451c0b2f7Stbbdev *selected_on_copy_construction = true; 56551c0b2f7Stbbdev return *this; 56651c0b2f7Stbbdev } 56751c0b2f7Stbbdev }; // struct PropagatingAllocator 56851c0b2f7Stbbdev 56951c0b2f7Stbbdev template <typename Allocator, typename POCMA, typename POCCA, typename POCS> 57051c0b2f7Stbbdev void swap( PropagatingAllocator<Allocator, POCMA, POCCA, POCS>& lhs, 57151c0b2f7Stbbdev PropagatingAllocator<Allocator, POCMA, POCCA, POCS>& ) 57251c0b2f7Stbbdev { 57351c0b2f7Stbbdev REQUIRE_MESSAGE(POCS::value, "Allocator should not swap if POCS is false"); 57451c0b2f7Stbbdev if (lhs.propagated_on_swap) 57551c0b2f7Stbbdev *lhs.propagated_on_swap = true; 57651c0b2f7Stbbdev } 57751c0b2f7Stbbdev 57851c0b2f7Stbbdev template <typename T> 57951c0b2f7Stbbdev using AlwaysPropagatingAllocator = PropagatingAllocator<std::allocator<T>, /*POCMA = */std::true_type, 58051c0b2f7Stbbdev /*POCCA = */std::true_type, /*POCS = */std::true_type>; 58151c0b2f7Stbbdev template <typename T> 58251c0b2f7Stbbdev using NeverPropagatingAllocator = PropagatingAllocator<std::allocator<T>>; 58351c0b2f7Stbbdev template <typename T> 58451c0b2f7Stbbdev using PocmaAllocator = PropagatingAllocator<std::allocator<T>, /*POCMA = */std::true_type>; 58551c0b2f7Stbbdev template <typename T> 58651c0b2f7Stbbdev using PoccaAllocator = PropagatingAllocator<std::allocator<T>, /*POCMA = */std::false_type, /*POCCA = */std::true_type>; 58751c0b2f7Stbbdev template <typename T> 58851c0b2f7Stbbdev using PocsAllocator = PropagatingAllocator<std::allocator<T>, /*POCMA = */std::false_type, /*POCCA = */std::false_type, 58951c0b2f7Stbbdev /*POCS = */std::true_type>; 59051c0b2f7Stbbdev 59151c0b2f7Stbbdev template <typename T> 59251c0b2f7Stbbdev class AlwaysEqualAllocator : public std::allocator<T> { 59351c0b2f7Stbbdev using base_allocator = std::allocator<T>; 59451c0b2f7Stbbdev public: 59551c0b2f7Stbbdev using is_always_equal = std::true_type; 59651c0b2f7Stbbdev using value_type = typename base_allocator::value_type; 59751c0b2f7Stbbdev using propagate_on_container_move_assignment = std::false_type; 59851c0b2f7Stbbdev 59951c0b2f7Stbbdev template <typename U> 60051c0b2f7Stbbdev struct rebind { 60151c0b2f7Stbbdev using other = AlwaysEqualAllocator<U>; 60251c0b2f7Stbbdev }; 60351c0b2f7Stbbdev 60451c0b2f7Stbbdev AlwaysEqualAllocator() = default; 60551c0b2f7Stbbdev 60651c0b2f7Stbbdev AlwaysEqualAllocator( const AlwaysEqualAllocator& ) = default; 60751c0b2f7Stbbdev 60851c0b2f7Stbbdev template <typename U> 60951c0b2f7Stbbdev AlwaysEqualAllocator( const AlwaysEqualAllocator<U>& other ) 61051c0b2f7Stbbdev : base_allocator(other) {} 61151c0b2f7Stbbdev }; // class AlwaysEqualAllocator 61251c0b2f7Stbbdev 61351c0b2f7Stbbdev template <typename T> 61451c0b2f7Stbbdev class NotAlwaysEqualAllocator : public std::allocator<T> { 61551c0b2f7Stbbdev using base_allocator = std::allocator<T>; 61651c0b2f7Stbbdev public: 61751c0b2f7Stbbdev using is_always_equal = std::false_type; 61851c0b2f7Stbbdev using value_type = typename base_allocator::value_type; 61951c0b2f7Stbbdev using propagate_on_container_swap = std::false_type; 62051c0b2f7Stbbdev 62151c0b2f7Stbbdev template <typename U> 62251c0b2f7Stbbdev struct rebind { 62351c0b2f7Stbbdev using other = NotAlwaysEqualAllocator<U>; 62451c0b2f7Stbbdev }; 62551c0b2f7Stbbdev 62651c0b2f7Stbbdev NotAlwaysEqualAllocator() = default; 62751c0b2f7Stbbdev 62851c0b2f7Stbbdev NotAlwaysEqualAllocator( const NotAlwaysEqualAllocator& ) = default; 62951c0b2f7Stbbdev 63051c0b2f7Stbbdev template <typename U> 63151c0b2f7Stbbdev NotAlwaysEqualAllocator( const NotAlwaysEqualAllocator<U>& other ) 63251c0b2f7Stbbdev : base_allocator(other) {} 63351c0b2f7Stbbdev }; 63451c0b2f7Stbbdev 63551c0b2f7Stbbdev template <typename T> 63651c0b2f7Stbbdev bool operator==( const AlwaysEqualAllocator<T>&, const AlwaysEqualAllocator<T>& ) { 63751c0b2f7Stbbdev #ifndef __TBB_TEST_SKIP_IS_ALWAYS_EQUAL_CHECK 63851c0b2f7Stbbdev REQUIRE_MESSAGE(false, "operator== should not be called if is_always_equal is true"); 63951c0b2f7Stbbdev #endif 64051c0b2f7Stbbdev return true; 64151c0b2f7Stbbdev } 64251c0b2f7Stbbdev 64351c0b2f7Stbbdev #endif // __TBB_test_common_custom_allocators_H 644