21 #ifndef __TBB_enumerable_thread_specific_H 22 #define __TBB_enumerable_thread_specific_H 25 #include "concurrent_vector.h" 26 #include "tbb_thread.h" 27 #include "tbb_allocator.h" 28 #include "cache_aligned_allocator.h" 29 #include "aligned_space.h" 30 #include "internal/_template_helpers.h" 31 #include "internal/_tbb_hash_compare_impl.h" 32 #include "tbb_profiling.h" 36 #include "machine/windows_api.h" 41 #define __TBB_ETS_USE_CPP11 \ 42 (__TBB_CPP11_RVALUE_REF_PRESENT && __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT \ 43 && __TBB_CPP11_DECLTYPE_PRESENT && __TBB_CPP11_LAMBDAS_PRESENT) 50 namespace interface6 {
53 template <
typename T,
typename Allocator, ets_key_usage_type ETS_key_type>
61 template<ets_key_usage_type ETS_key_type>
62 class ets_base: tbb::internal::no_copy {
65 #if __TBB_PROTECTED_NESTED_CLASS_BROKEN 73 slot& at(
size_t k ) {
74 return ((slot*)(
void*)(
this+1))[k];
76 size_t size()
const {
return size_t(1)<<lg_size;}
77 size_t mask()
const {
return size()-1;}
78 size_t start(
size_t h )
const {
79 return h>>(8*
sizeof(size_t)-lg_size);
85 bool empty()
const {
return key == key_type();}
86 bool match( key_type k )
const {
return key == k;}
87 bool claim( key_type k ) {
89 return atomic_compare_and_swap(key, k, key_type()) == key_type();
92 #if __TBB_PROTECTED_NESTED_CLASS_BROKEN 101 virtual void* create_local() = 0;
102 virtual void* create_array(
size_t _size) = 0;
103 virtual void free_array(
void* ptr,
size_t _size) = 0;
104 array* allocate(
size_t lg_size ) {
105 size_t n = size_t(1)<<lg_size;
106 array* a =
static_cast<array*
>(create_array(
sizeof(array)+n*
sizeof(slot) ));
107 a->lg_size = lg_size;
108 std::memset( a+1, 0, n*
sizeof(slot) );
111 void free(array* a) {
112 size_t n = size_t(1)<<(a->lg_size);
113 free_array( (
void *)a,
size_t(
sizeof(array)+n*
sizeof(slot)) );
116 ets_base() {my_root=NULL; my_count=0;}
118 void* table_lookup(
bool& exists );
122 void table_elementwise_copy(
const ets_base& other,
123 void*(*add_element)(ets_base&,
void*) ) {
124 __TBB_ASSERT(!my_root,NULL);
125 __TBB_ASSERT(!my_count,NULL);
126 if( !other.my_root )
return;
127 array* root = my_root = allocate(other.my_root->lg_size);
129 my_count = other.my_count;
130 size_t mask = root->mask();
131 for( array* r=other.my_root; r; r=r->next ) {
132 for(
size_t i=0; i<r->size(); ++i ) {
136 slot& s2 = root->at(j);
138 s2.ptr = add_element(*
this, s1.ptr);
142 else if( s2.match(s1.key) )
149 void table_swap( ets_base& other ) {
150 __TBB_ASSERT(
this!=&other,
"Don't swap an instance with itself");
151 tbb::internal::swap<relaxed>(my_root, other.my_root);
152 tbb::internal::swap<relaxed>(my_count, other.my_count);
156 template<ets_key_usage_type ETS_key_type>
157 ets_base<ETS_key_type>::~ets_base() {
158 __TBB_ASSERT(!my_root, NULL);
161 template<ets_key_usage_type ETS_key_type>
162 void ets_base<ETS_key_type>::table_clear() {
163 while( array* r = my_root ) {
170 template<ets_key_usage_type ETS_key_type>
171 void* ets_base<ETS_key_type>::table_lookup(
bool& exists ) {
172 const key_type k = tbb::this_tbb_thread::get_id();
174 __TBB_ASSERT(k != key_type(),NULL);
177 for( array* r=my_root; r; r=r->next ) {
178 call_itt_notify(acquired,r);
179 size_t mask=r->mask();
180 for(
size_t i = r->start(h); ;i=(i+1)&mask) {
182 if( s.empty() )
break;
201 found = create_local();
203 size_t c = ++my_count;
205 call_itt_notify(acquired,r);
206 if( !r || c>r->size()/2 ) {
207 size_t s = r ? r->lg_size : 2;
208 while( c>
size_t(1)<<(s-1) ) ++s;
209 array* a = allocate(s);
212 call_itt_notify(releasing,a);
213 array* new_r = my_root.compare_and_swap(a,r);
214 if( new_r==r )
break;
215 call_itt_notify(acquired, new_r);
216 if( new_r->lg_size>=s ) {
230 call_itt_notify(acquired, ir);
231 size_t mask = ir->mask();
232 for(
size_t i = ir->start(h);;i=(i+1)&mask) {
245 class ets_base<ets_key_per_instance>:
protected ets_base<ets_no_key> {
246 typedef ets_base<ets_no_key> super;
248 #if __TBB_WIN8UI_SUPPORT 249 typedef DWORD tls_key_t;
250 void create_key() { my_key = FlsAlloc(NULL); }
251 void destroy_key() { FlsFree(my_key); }
252 void set_tls(
void * value) { FlsSetValue(my_key, (LPVOID)value); }
253 void* get_tls() {
return (
void *)FlsGetValue(my_key); }
255 typedef DWORD tls_key_t;
256 void create_key() { my_key = TlsAlloc(); }
257 void destroy_key() { TlsFree(my_key); }
258 void set_tls(
void * value) { TlsSetValue(my_key, (LPVOID)value); }
259 void* get_tls() {
return (
void *)TlsGetValue(my_key); }
262 typedef pthread_key_t tls_key_t;
263 void create_key() { pthread_key_create(&my_key, NULL); }
264 void destroy_key() { pthread_key_delete(my_key); }
265 void set_tls(
void * value )
const { pthread_setspecific(my_key, value); }
266 void* get_tls()
const {
return pthread_getspecific(my_key); }
269 virtual void* create_local() = 0;
270 virtual void* create_array(
size_t _size) = 0;
271 virtual void free_array(
void* ptr,
size_t _size) = 0;
273 ets_base() {create_key();}
274 ~ets_base() {destroy_key();}
275 void* table_lookup(
bool& exists ) {
276 void* found = get_tls();
280 found = super::table_lookup(exists);
288 super::table_clear();
290 void table_swap( ets_base& other ) {
292 __TBB_ASSERT(
this!=&other,
"Don't swap an instance with itself");
293 swap(my_key, other.my_key);
294 super::table_swap(other);
299 template<
typename Container,
typename Value >
300 class enumerable_thread_specific_iterator
301 #if defined(_WIN64) && defined(_MSC_VER)
303 : public
std::iterator<
std::random_access_iterator_tag,Value>
308 Container *my_container;
309 typename Container::size_type my_index;
310 mutable Value *my_value;
312 template<
typename C,
typename T>
313 friend enumerable_thread_specific_iterator<C,T>
314 operator+( ptrdiff_t offset,
const enumerable_thread_specific_iterator<C,T>& v );
316 template<
typename C,
typename T,
typename U>
317 friend bool operator==(
const enumerable_thread_specific_iterator<C,T>& i,
318 const enumerable_thread_specific_iterator<C,U>& j );
320 template<
typename C,
typename T,
typename U>
321 friend bool operator<( const enumerable_thread_specific_iterator<C,T>& i,
322 const enumerable_thread_specific_iterator<C,U>& j );
324 template<
typename C,
typename T,
typename U>
325 friend ptrdiff_t operator-(
const enumerable_thread_specific_iterator<C,T>& i,
326 const enumerable_thread_specific_iterator<C,U>& j );
328 template<
typename C,
typename U>
329 friend class enumerable_thread_specific_iterator;
333 enumerable_thread_specific_iterator(
const Container &container,
typename Container::size_type index ) :
334 my_container(&const_cast<Container &>(container)), my_index(index), my_value(NULL) {}
337 enumerable_thread_specific_iterator() : my_container(NULL), my_index(0), my_value(NULL) {}
340 enumerable_thread_specific_iterator(
const enumerable_thread_specific_iterator<Container, U>& other ) :
341 my_container( other.my_container ), my_index( other.my_index), my_value( const_cast<Value *>(other.my_value) ) {}
343 enumerable_thread_specific_iterator operator+( ptrdiff_t offset )
const {
344 return enumerable_thread_specific_iterator(*my_container, my_index + offset);
347 enumerable_thread_specific_iterator &operator+=( ptrdiff_t offset ) {
353 enumerable_thread_specific_iterator operator-( ptrdiff_t offset )
const {
354 return enumerable_thread_specific_iterator( *my_container, my_index-offset );
357 enumerable_thread_specific_iterator &operator-=( ptrdiff_t offset ) {
363 Value& operator*()
const {
364 Value* value = my_value;
366 value = my_value = (*my_container)[my_index].value();
368 __TBB_ASSERT( value==(*my_container)[my_index].value(),
"corrupt cache" );
372 Value& operator[]( ptrdiff_t k )
const {
373 return (*my_container)[my_index + k].value;
376 Value* operator->()
const {
return &operator*();}
378 enumerable_thread_specific_iterator& operator++() {
384 enumerable_thread_specific_iterator& operator--() {
391 enumerable_thread_specific_iterator operator++(
int) {
392 enumerable_thread_specific_iterator result = *
this;
399 enumerable_thread_specific_iterator operator--(
int) {
400 enumerable_thread_specific_iterator result = *
this;
407 typedef ptrdiff_t difference_type;
408 typedef Value value_type;
409 typedef Value* pointer;
410 typedef Value& reference;
411 typedef std::random_access_iterator_tag iterator_category;
414 template<
typename Container,
typename T>
415 enumerable_thread_specific_iterator<Container,T>
416 operator+( ptrdiff_t offset,
const enumerable_thread_specific_iterator<Container,T>& v ) {
417 return enumerable_thread_specific_iterator<Container,T>( v.my_container, v.my_index + offset );
420 template<
typename Container,
typename T,
typename U>
421 bool operator==(
const enumerable_thread_specific_iterator<Container,T>& i,
422 const enumerable_thread_specific_iterator<Container,U>& j ) {
423 return i.my_index==j.my_index && i.my_container == j.my_container;
426 template<
typename Container,
typename T,
typename U>
427 bool operator!=(
const enumerable_thread_specific_iterator<Container,T>& i,
428 const enumerable_thread_specific_iterator<Container,U>& j ) {
432 template<
typename Container,
typename T,
typename U>
433 bool operator<( const enumerable_thread_specific_iterator<Container,T>& i,
434 const enumerable_thread_specific_iterator<Container,U>& j ) {
435 return i.my_index<j.my_index;
438 template<
typename Container,
typename T,
typename U>
439 bool operator>(
const enumerable_thread_specific_iterator<Container,T>& i,
440 const enumerable_thread_specific_iterator<Container,U>& j ) {
444 template<
typename Container,
typename T,
typename U>
445 bool operator>=(
const enumerable_thread_specific_iterator<Container,T>& i,
446 const enumerable_thread_specific_iterator<Container,U>& j ) {
450 template<
typename Container,
typename T,
typename U>
451 bool operator<=( const enumerable_thread_specific_iterator<Container,T>& i,
452 const enumerable_thread_specific_iterator<Container,U>& j ) {
456 template<
typename Container,
typename T,
typename U>
457 ptrdiff_t operator-(
const enumerable_thread_specific_iterator<Container,T>& i,
458 const enumerable_thread_specific_iterator<Container,U>& j ) {
459 return i.my_index-j.my_index;
462 template<
typename SegmentedContainer,
typename Value >
463 class segmented_iterator
464 #if defined(_WIN64) && defined(_MSC_VER)
465 : public
std::iterator<
std::input_iterator_tag, Value>
468 template<
typename C,
typename T,
typename U>
469 friend bool operator==(
const segmented_iterator<C,T>& i,
const segmented_iterator<C,U>& j);
471 template<
typename C,
typename T,
typename U>
472 friend bool operator!=(
const segmented_iterator<C,T>& i,
const segmented_iterator<C,U>& j);
474 template<
typename C,
typename U>
475 friend class segmented_iterator;
479 segmented_iterator() {my_segcont = NULL;}
481 segmented_iterator(
const SegmentedContainer& _segmented_container ) :
482 my_segcont(const_cast<SegmentedContainer*>(&_segmented_container)),
483 outer_iter(my_segcont->end()) { }
485 ~segmented_iterator() {}
487 typedef typename SegmentedContainer::iterator outer_iterator;
488 typedef typename SegmentedContainer::value_type InnerContainer;
489 typedef typename InnerContainer::iterator inner_iterator;
492 typedef ptrdiff_t difference_type;
493 typedef Value value_type;
494 typedef typename SegmentedContainer::size_type size_type;
495 typedef Value* pointer;
496 typedef Value& reference;
497 typedef std::input_iterator_tag iterator_category;
501 segmented_iterator(
const segmented_iterator<SegmentedContainer, U>& other) :
502 my_segcont(other.my_segcont),
503 outer_iter(other.outer_iter),
505 inner_iter(other.inner_iter)
510 segmented_iterator& operator=(
const segmented_iterator<SegmentedContainer, U>& other) {
512 my_segcont = other.my_segcont;
513 outer_iter = other.outer_iter;
514 if(outer_iter != my_segcont->end()) inner_iter = other.inner_iter;
522 segmented_iterator& operator=(
const outer_iterator& new_outer_iter) {
523 __TBB_ASSERT(my_segcont != NULL, NULL);
525 for(outer_iter = new_outer_iter ;outer_iter!=my_segcont->end(); ++outer_iter) {
526 if( !outer_iter->empty() ) {
527 inner_iter = outer_iter->begin();
535 segmented_iterator& operator++() {
541 segmented_iterator operator++(
int) {
542 segmented_iterator tmp = *
this;
547 bool operator==(
const outer_iterator& other_outer)
const {
548 __TBB_ASSERT(my_segcont != NULL, NULL);
549 return (outer_iter == other_outer &&
550 (outer_iter == my_segcont->end() || inner_iter == outer_iter->begin()));
553 bool operator!=(
const outer_iterator& other_outer)
const {
554 return !operator==(other_outer);
559 reference operator*()
const {
560 __TBB_ASSERT(my_segcont != NULL, NULL);
561 __TBB_ASSERT(outer_iter != my_segcont->end(),
"Dereferencing a pointer at end of container");
562 __TBB_ASSERT(inner_iter != outer_iter->end(), NULL);
567 pointer operator->()
const {
return &operator*();}
570 SegmentedContainer* my_segcont;
571 outer_iterator outer_iter;
572 inner_iterator inner_iter;
575 __TBB_ASSERT(my_segcont != NULL, NULL);
576 __TBB_ASSERT(outer_iter != my_segcont->end(), NULL);
577 __TBB_ASSERT(inner_iter != outer_iter->end(), NULL);
579 while(inner_iter == outer_iter->end() && ++outer_iter != my_segcont->end()) {
580 inner_iter = outer_iter->begin();
585 template<
typename SegmentedContainer,
typename T,
typename U>
586 bool operator==(
const segmented_iterator<SegmentedContainer,T>& i,
587 const segmented_iterator<SegmentedContainer,U>& j ) {
588 if(i.my_segcont != j.my_segcont)
return false;
589 if(i.my_segcont == NULL)
return true;
590 if(i.outer_iter != j.outer_iter)
return false;
591 if(i.outer_iter == i.my_segcont->end())
return true;
592 return i.inner_iter == j.inner_iter;
596 template<
typename SegmentedContainer,
typename T,
typename U>
597 bool operator!=(
const segmented_iterator<SegmentedContainer,T>& i,
598 const segmented_iterator<SegmentedContainer,U>& j ) {
603 struct construct_by_default: tbb::internal::no_assign {
604 void construct(
void*where) {
new(where) T();}
605 construct_by_default(
int ) {}
609 struct construct_by_exemplar: tbb::internal::no_assign {
611 void construct(
void*where) {
new(where) T(exemplar);}
612 construct_by_exemplar(
const T& t ) : exemplar(t) {}
613 #if __TBB_ETS_USE_CPP11 614 construct_by_exemplar( T&& t ) : exemplar(
std::move(t)) {}
618 template<
typename T,
typename Finit>
619 struct construct_by_finit: tbb::internal::no_assign {
621 void construct(
void* where) {
new(where) T(f());}
622 construct_by_finit(
const Finit& f_ ) : f(f_) {}
623 #if __TBB_ETS_USE_CPP11 624 construct_by_finit( Finit&& f_ ) : f(
std::move(f_)) {}
628 #if __TBB_ETS_USE_CPP11 629 template<
typename T,
typename... P>
630 struct construct_by_args: tbb::internal::no_assign {
631 internal::stored_pack<P...> pack;
632 void construct(
void* where) {
633 internal::call( [where](
const typename strip<P>::type&... args ){
634 new(where) T(args...);
637 construct_by_args( P&& ... args ) : pack(
std::forward<P>(args)...) {}
644 class callback_base {
647 virtual callback_base* clone()
const = 0;
649 virtual void destroy() = 0;
651 virtual ~callback_base() { }
653 virtual void construct(
void* where) = 0;
656 template <
typename T,
typename Constructor>
657 class callback_leaf:
public callback_base<T>, Constructor {
658 #if __TBB_ETS_USE_CPP11 659 template<
typename... P> callback_leaf( P&& ... params ) : Constructor(
std::forward<P>(params)...) {}
661 template<
typename X> callback_leaf(
const X& x ) : Constructor(x) {}
666 callback_base<T>* clone()
const {
671 my_allocator_type().destroy(
this);
672 my_allocator_type().deallocate(
this,1);
675 void construct(
void* where) {
676 Constructor::construct(where);
679 #if __TBB_ETS_USE_CPP11 680 template<
typename... P>
681 static callback_base<T>* make( P&& ... params ) {
682 void* where = my_allocator_type().allocate(1);
683 return new(where) callback_leaf( std::forward<P>(params)... );
687 static callback_base<T>* make(
const X& x ) {
688 void* where = my_allocator_type().allocate(1);
689 return new(where) callback_leaf(x);
708 ets_element() { is_built =
false; }
709 U* value() {
return my_space.
begin(); }
710 U* value_committed() { is_built =
true;
return my_space.
begin(); }
713 my_space.
begin()->~U();
722 template<
typename T,
typename ETS>
struct is_compatible_ets {
static const bool value =
false; };
723 template<
typename T,
typename U,
typename A, ets_key_usage_type C>
726 #if __TBB_ETS_USE_CPP11 728 template <
typename T>
729 class is_callable_no_args {
734 template<
typename U>
static yes& decide( decltype(declval<U>()())* );
735 template<
typename U>
static no& decide(...);
737 static const bool value = (
sizeof(decide<T>(NULL)) ==
sizeof(yes));
764 template <
typename T,
771 typedef internal::padded< internal::ets_element<T> > padded_element;
777 typedef T value_type;
778 typedef T& reference;
779 typedef const T& const_reference;
781 typedef ptrdiff_t difference_type;
782 generic_range_type( I begin_, I end_,
size_t grainsize_ = 1) :
blocked_range<I>(begin_,end_,grainsize_) {}
784 generic_range_type(
const generic_range_type<U>& r) :
blocked_range<I>(r.begin(),r.end(),r.grainsize()) {}
785 generic_range_type( generic_range_type& r, split ) :
blocked_range<I>(r,split()) {}
788 typedef typename Allocator::template rebind< padded_element >::other padded_allocator_type;
791 internal::callback_base<T> *my_construct_callback;
793 internal_collection_type my_locals;
797 void* create_local() {
798 padded_element& lref = *my_locals.
grow_by(1);
799 my_construct_callback->construct(lref.value());
800 return lref.value_committed();
803 static void* create_local_by_copy( internal::ets_base<ets_no_key>& base,
void* p ) {
805 padded_element& lref = *ets.my_locals.
grow_by(1);
806 new(lref.value()) T(*static_cast<T*>(p));
807 return lref.value_committed();
810 #if __TBB_ETS_USE_CPP11 811 static void* create_local_by_move( internal::ets_base<ets_no_key>& base,
void* p ) {
813 padded_element& lref = *ets.my_locals.
grow_by(1);
814 new(lref.value()) T(std::move(*static_cast<T*>(p)));
815 return lref.value_committed();
819 typedef typename Allocator::template rebind< uintptr_t >::other array_allocator_type;
822 void* create_array(
size_t _size) {
823 size_t nelements = (_size +
sizeof(uintptr_t) -1) /
sizeof(uintptr_t);
824 return array_allocator_type().allocate(nelements);
827 void free_array(
void* _ptr,
size_t _size) {
828 size_t nelements = (_size +
sizeof(uintptr_t) -1) /
sizeof(uintptr_t);
829 array_allocator_type().deallocate( reinterpret_cast<uintptr_t *>(_ptr),nelements);
836 typedef T value_type;
837 typedef T& reference;
838 typedef const T& const_reference;
840 typedef const T* const_pointer;
841 typedef typename internal_collection_type::size_type size_type;
842 typedef typename internal_collection_type::difference_type difference_type;
845 typedef typename internal::enumerable_thread_specific_iterator< internal_collection_type, value_type > iterator;
846 typedef typename internal::enumerable_thread_specific_iterator< internal_collection_type, const value_type > const_iterator;
849 typedef generic_range_type< iterator > range_type;
850 typedef generic_range_type< const_iterator > const_range_type;
858 template <
typename Finit
859 #if __TBB_ETS_USE_CPP11 869 internal::callback_leaf<T,
internal::construct_by_exemplar<T> >::make( exemplar )
872 #if __TBB_ETS_USE_CPP11 874 internal::callback_leaf<T,internal::construct_by_exemplar<T> >::make( std::move(exemplar) )
878 template <
typename P1,
typename... P,
880 && !internal::is_compatible_ets<T, typename internal::strip<P1>::type>::value
884 internal::callback_leaf<T,internal::construct_by_args<T,P1,P...> >::make( std::forward<P1>(arg1), std::forward<P>(args)... )
890 if(my_construct_callback) my_construct_callback->destroy();
892 this->internal::ets_base<ets_no_key>::table_clear();
898 return local(exists);
903 void* ptr = this->table_lookup(exists);
908 size_type
size()
const {
return my_locals.size(); }
911 bool empty()
const {
return my_locals.empty(); }
914 iterator
begin() {
return iterator( my_locals, 0 ); }
916 iterator
end() {
return iterator(my_locals, my_locals.size() ); }
919 const_iterator
begin()
const {
return const_iterator(my_locals, 0); }
922 const_iterator
end()
const {
return const_iterator(my_locals, my_locals.size()); }
925 range_type
range(
size_t grainsize=1 ) {
return range_type( begin(), end(), grainsize ); }
928 const_range_type
range(
size_t grainsize=1 )
const {
return const_range_type( begin(), end(), grainsize ); }
939 template<
typename A2, ets_key_usage_type C2>
941 #if __TBB_ETS_USE_CPP11 && TBB_USE_ASSERT 943 __TBB_STATIC_ASSERT( (internal::is_compatible_ets<T,
typename internal::strip<decltype(other)>::type>::value),
"is_compatible_ets fails" );
946 my_construct_callback = other.my_construct_callback->clone();
947 __TBB_ASSERT(my_locals.size()==0,NULL);
948 my_locals.reserve(other.
size());
949 this->table_elementwise_copy( other, create_local_by_copy );
952 void internal_swap(enumerable_thread_specific& other) {
954 __TBB_ASSERT(
this!=&other, NULL );
955 swap(my_construct_callback, other.my_construct_callback);
958 swap(my_locals, other.my_locals);
959 this->internal::ets_base<ETS_key_type>::table_swap(other);
962 #if __TBB_ETS_USE_CPP11 963 template<
typename A2, ets_key_usage_type C2>
967 __TBB_STATIC_ASSERT( (internal::is_compatible_ets<T,
typename internal::strip<decltype(other)>::type>::value),
"is_compatible_ets fails" );
969 my_construct_callback = other.my_construct_callback;
970 other.my_construct_callback = NULL;
971 __TBB_ASSERT(my_locals.size()==0,NULL);
972 my_locals.reserve(other.
size());
973 this->table_elementwise_copy( other, create_local_by_move );
979 enumerable_thread_specific(
const enumerable_thread_specific& other )
980 : internal::ets_base<ETS_key_type>()
982 internal_copy(other);
985 template<
typename Alloc, ets_key_usage_type Cachetype>
988 internal_copy(other);
991 #if __TBB_ETS_USE_CPP11 992 enumerable_thread_specific( enumerable_thread_specific&& other ) : my_construct_callback()
994 internal_swap(other);
997 template<
typename Alloc, ets_key_usage_type Cachetype>
1000 internal_move(std::move(other));
1004 enumerable_thread_specific& operator=(
const enumerable_thread_specific& other )
1006 if(
this != &other ) {
1008 my_construct_callback->destroy();
1009 internal_copy( other );
1014 template<
typename Alloc, ets_key_usage_type Cachetype>
1017 __TBB_ASSERT( static_cast<void*>(
this)!=static_cast<const void*>(&other), NULL );
1019 my_construct_callback->destroy();
1020 internal_copy(other);
1024 #if __TBB_ETS_USE_CPP11 1025 enumerable_thread_specific& operator=( enumerable_thread_specific&& other )
1027 if(
this != &other )
1028 internal_swap(other);
1032 template<
typename Alloc, ets_key_usage_type Cachetype>
1035 __TBB_ASSERT( static_cast<void*>(
this)!=static_cast<const void*>(&other), NULL );
1037 my_construct_callback->destroy();
1038 internal_move(std::move(other));
1044 template <
typename combine_func_t>
1045 T combine(combine_func_t f_combine) {
1046 if(begin() == end()) {
1047 internal::ets_element<T> location;
1048 my_construct_callback->construct(location.value());
1049 return *location.value_committed();
1051 const_iterator ci = begin();
1053 while(++ci != end())
1054 my_result = f_combine( my_result, *ci );
1059 template <
typename combine_func_t>
1060 void combine_each(combine_func_t f_combine) {
1061 for(iterator ci = begin(); ci != end(); ++ci) {
1068 template<
typename Container >
1072 typedef typename Container::value_type conval_type;
1078 typedef typename conval_type::difference_type difference_type;
1079 typedef typename conval_type::allocator_type allocator_type;
1080 typedef typename conval_type::value_type value_type;
1081 typedef typename conval_type::reference reference;
1082 typedef typename conval_type::const_reference const_reference;
1083 typedef typename conval_type::pointer pointer;
1084 typedef typename conval_type::const_pointer const_pointer;
1086 typedef typename internal::segmented_iterator<Container, value_type> iterator;
1087 typedef typename internal::segmented_iterator<Container, const value_type> const_iterator;
1089 flattened2d(
const Container &c,
typename Container::const_iterator b,
typename Container::const_iterator e ) :
1090 my_container(const_cast<Container*>(&c)), my_begin(b), my_end(e) { }
1093 my_container(const_cast<Container*>(&c)), my_begin(c.begin()), my_end(c.end()) { }
1095 iterator begin() {
return iterator(*my_container) = my_begin; }
1096 iterator end() {
return iterator(*my_container) = my_end; }
1097 const_iterator begin()
const {
return const_iterator(*my_container) = my_begin; }
1098 const_iterator end()
const {
return const_iterator(*my_container) = my_end; }
1100 size_type size()
const {
1101 size_type tot_size = 0;
1102 for(
typename Container::const_iterator i = my_begin; i != my_end; ++i) {
1103 tot_size += i->size();
1110 Container *my_container;
1111 typename Container::const_iterator my_begin;
1112 typename Container::const_iterator my_end;
1116 template <
typename Container>
1117 flattened2d<Container> flatten2d(
const Container &c,
const typename Container::const_iterator b,
const typename Container::const_iterator e) {
1121 template <
typename Container>
1129 using interface6::internal::segmented_iterator;
1134 using interface6::flatten2d;
Enables one or the other code branches.
Definition: _template_helpers.h:29
Definition: _tbb_hash_compare_impl.h:89
Detects whether two given types are the same.
Definition: _template_helpers.h:56
conval_type::size_type size_type
Basic types.
Definition: enumerable_thread_specific.h:1077
void clear()
Destroys local copies.
Definition: enumerable_thread_specific.h:931
const_iterator end() const
end const iterator
Definition: enumerable_thread_specific.h:922
const_iterator begin() const
begin const iterator
Definition: enumerable_thread_specific.h:919
const_range_type range(size_t grainsize=1) const
Get const range for parallel algorithms.
Definition: enumerable_thread_specific.h:928
Definition: _tbb_windef.h:37
bool empty() const
true if there have been no local copies created
Definition: enumerable_thread_specific.h:911
reference local()
returns reference to local, discarding exists
Definition: enumerable_thread_specific.h:896
A range over which to iterate.
Definition: blocked_range.h:40
Block of space aligned sufficiently to construct an array T with N elements.
Definition: aligned_space.h:33
reference local(bool &exists)
Returns reference to calling thread's local copy, creating one if necessary.
Definition: enumerable_thread_specific.h:902
The enumerable_thread_specific container.
Definition: enumerable_thread_specific.h:54
ets_key_usage_type
enum for selecting between single key and key-per-instance versions
Definition: enumerable_thread_specific.h:48
range_type range(size_t grainsize=1)
Get range for parallel algorithms.
Definition: enumerable_thread_specific.h:925
*/
Definition: material.h:665
Allocator allocator_type
Basic types.
Definition: enumerable_thread_specific.h:835
enumerable_thread_specific()
Default constructor. Each local instance of T is default constructed.
Definition: enumerable_thread_specific.h:853
Meets "allocator" requirements of ISO C++ Standard, Section 20.1.5.
Definition: cache_aligned_allocator.h:60
enumerable_thread_specific(const T &exemplar)
Constructor with exemplar. Each local instance of T is copy-constructed from the exemplar.
Definition: enumerable_thread_specific.h:868
T * begin()
Pointer to beginning of array.
Definition: aligned_space.h:39
Definition: enumerable_thread_specific.h:1069
Primary template for atomic.
Definition: atomic.h:405
Definition: _flow_graph_async_msg_impl.h:32
iterator grow_by(size_type delta)
Grow by "delta" elements.
Definition: concurrent_vector.h:789
Definition: tbb_thread.h:233
iterator end()
end iterator
Definition: enumerable_thread_specific.h:916
The namespace tbb contains all components of the library.
Definition: parallel_for.h:44
Meets "allocator" requirements of ISO C++ Standard, Section 20.1.5.
Definition: tbb_allocator.h:73
size_type size() const
Get the number of local copies.
Definition: enumerable_thread_specific.h:908
enumerable_thread_specific(Finit finit)
Constructor with initializer functor. Each local instance of T is constructed by T(finit()).
Definition: enumerable_thread_specific.h:863
Strips its template type argument from cv- and ref-qualifiers.
Definition: _template_helpers.h:33
~enumerable_thread_specific()
Destructor.
Definition: enumerable_thread_specific.h:889
iterator begin()
begin iterator
Definition: enumerable_thread_specific.h:914