00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef __TBB_enumerable_thread_specific_H
00030 #define __TBB_enumerable_thread_specific_H
00031
00032 #include "concurrent_vector.h"
00033 #include "tbb_thread.h"
00034 #include "tbb_allocator.h"
00035 #include "cache_aligned_allocator.h"
00036 #include "aligned_space.h"
00037 #include <string.h>
00038
00039 #if _WIN32||_WIN64
00040 #include "machine/windows_api.h"
00041 #else
00042 #include <pthread.h>
00043 #endif
00044
00045 namespace tbb {
00046
00048 enum ets_key_usage_type { ets_key_per_instance, ets_no_key };
00049
00050 namespace interface6 {
00051
00053 namespace internal {
00054
00055 template<ets_key_usage_type ETS_key_type>
00056 class ets_base: tbb::internal::no_copy {
00057 protected:
00058 #if _WIN32||_WIN64
00059 typedef DWORD key_type;
00060 #else
00061 typedef pthread_t key_type;
00062 #endif
00063 #if __TBB_PROTECTED_NESTED_CLASS_BROKEN
00064 public:
00065 #endif
00066 struct slot;
00067
00068 struct array {
00069 array* next;
00070 size_t lg_size;
00071 slot& at( size_t k ) {
00072 return ((slot*)(void*)(this+1))[k];
00073 }
00074 size_t size() const {return (size_t)1<<lg_size;}
00075 size_t mask() const {return size()-1;}
00076 size_t start( size_t h ) const {
00077 return h>>(8*sizeof(size_t)-lg_size);
00078 }
00079 };
00080 struct slot {
00081 key_type key;
00082 void* ptr;
00083 bool empty() const {return !key;}
00084 bool match( key_type k ) const {return key==k;}
00085 bool claim( key_type k ) {
00086 __TBB_ASSERT(sizeof(tbb::atomic<key_type>)==sizeof(key_type), NULL);
00087 return tbb::internal::punned_cast<tbb::atomic<key_type>*>(&key)->compare_and_swap(k,0)==0;
00088 }
00089 };
00090 #if __TBB_PROTECTED_NESTED_CLASS_BROKEN
00091 protected:
00092 #endif
00093
00094 static key_type key_of_current_thread() {
00095 tbb::tbb_thread::id id = tbb::this_tbb_thread::get_id();
00096 key_type k;
00097 memcpy( &k, &id, sizeof(k) );
00098 return k;
00099 }
00100
00102
00104 atomic<array*> my_root;
00105 atomic<size_t> my_count;
00106 virtual void* create_local() = 0;
00107 virtual void* create_array(size_t _size) = 0;
00108 virtual void free_array(void* ptr, size_t _size) = 0;
00109 array* allocate( size_t lg_size ) {
00110 size_t n = 1<<lg_size;
00111 array* a = static_cast<array*>(create_array( sizeof(array)+n*sizeof(slot) ));
00112 a->lg_size = lg_size;
00113 std::memset( a+1, 0, n*sizeof(slot) );
00114 return a;
00115 }
00116 void free(array* a) {
00117 size_t n = 1<<(a->lg_size);
00118 free_array( (void *)a, size_t(sizeof(array)+n*sizeof(slot)) );
00119 }
00120 static size_t hash( key_type k ) {
00121
00122
00123 return uintptr_t(k)*tbb::internal::size_t_select(0x9E3779B9,0x9E3779B97F4A7C15ULL);
00124 }
00125
00126 ets_base() {my_root=NULL; my_count=0;}
00127 virtual ~ets_base();
00128 void* table_lookup( bool& exists );
00129 void table_clear();
00130 slot& table_find( key_type k ) {
00131 size_t h = hash(k);
00132 array* r = my_root;
00133 size_t mask = r->mask();
00134 for(size_t i = r->start(h);;i=(i+1)&mask) {
00135 slot& s = r->at(i);
00136 if( s.empty() || s.match(k) )
00137 return s;
00138 }
00139 }
00140 void table_reserve_for_copy( const ets_base& other ) {
00141 __TBB_ASSERT(!my_root,NULL);
00142 __TBB_ASSERT(!my_count,NULL);
00143 if( other.my_root ) {
00144 array* a = allocate(other.my_root->lg_size);
00145 a->next = NULL;
00146 my_root = a;
00147 my_count = other.my_count;
00148 }
00149 }
00150 };
00151
00152 template<ets_key_usage_type ETS_key_type>
00153 ets_base<ETS_key_type>::~ets_base() {
00154 __TBB_ASSERT(!my_root, NULL);
00155 }
00156
00157 template<ets_key_usage_type ETS_key_type>
00158 void ets_base<ETS_key_type>::table_clear() {
00159 while( array* r = my_root ) {
00160 my_root = r->next;
00161 free(r);
00162 }
00163 my_count = 0;
00164 }
00165
00166 template<ets_key_usage_type ETS_key_type>
00167 void* ets_base<ETS_key_type>::table_lookup( bool& exists ) {
00168 const key_type k = key_of_current_thread();
00169
00170 __TBB_ASSERT(k!=0,NULL);
00171 void* found;
00172 size_t h = hash(k);
00173 for( array* r=my_root; r; r=r->next ) {
00174 size_t mask=r->mask();
00175 for(size_t i = r->start(h); ;i=(i+1)&mask) {
00176 slot& s = r->at(i);
00177 if( s.empty() ) break;
00178 if( s.match(k) ) {
00179 if( r==my_root ) {
00180
00181 exists = true;
00182 return s.ptr;
00183 } else {
00184
00185 exists = true;
00186 found = s.ptr;
00187 goto insert;
00188 }
00189 }
00190 }
00191 }
00192
00193 exists = false;
00194 found = create_local();
00195 {
00196 size_t c = ++my_count;
00197 array* r = my_root;
00198 if( !r || c>r->size()/2 ) {
00199 size_t s = r ? r->lg_size : 2;
00200 while( c>size_t(1)<<(s-1) ) ++s;
00201 array* a = allocate(s);
00202 for(;;) {
00203 a->next = my_root;
00204 array* new_r = my_root.compare_and_swap(a,r);
00205 if( new_r==r ) break;
00206 if( new_r->lg_size>=s ) {
00207
00208 free(a);
00209 break;
00210 }
00211 r = new_r;
00212 }
00213 }
00214 }
00215 insert:
00216
00217 array* ir = my_root;
00218 size_t mask = ir->mask();
00219 for(size_t i = ir->start(h);;i=(i+1)&mask) {
00220 slot& s = ir->at(i);
00221 if( s.empty() ) {
00222 if( s.claim(k) ) {
00223 s.ptr = found;
00224 return found;
00225 }
00226 }
00227 }
00228 }
00229
00231 template <>
00232 class ets_base<ets_key_per_instance>: protected ets_base<ets_no_key> {
00233 typedef ets_base<ets_no_key> super;
00234 #if _WIN32||_WIN64
00235 #if __TBB_WIN8UI_SUPPORT
00236 typedef DWORD tls_key_t;
00237 void create_key() { my_key = FlsAlloc(NULL); }
00238 void destroy_key() { FlsFree(my_key); }
00239 void set_tls(void * value) { FlsSetValue(my_key, (LPVOID)value); }
00240 void* get_tls() { return (void *)FlsGetValue(my_key); }
00241 #else
00242 typedef DWORD tls_key_t;
00243 void create_key() { my_key = TlsAlloc(); }
00244 void destroy_key() { TlsFree(my_key); }
00245 void set_tls(void * value) { TlsSetValue(my_key, (LPVOID)value); }
00246 void* get_tls() { return (void *)TlsGetValue(my_key); }
00247 #endif
00248 #else
00249 typedef pthread_key_t tls_key_t;
00250 void create_key() { pthread_key_create(&my_key, NULL); }
00251 void destroy_key() { pthread_key_delete(my_key); }
00252 void set_tls( void * value ) const { pthread_setspecific(my_key, value); }
00253 void* get_tls() const { return pthread_getspecific(my_key); }
00254 #endif
00255 tls_key_t my_key;
00256 virtual void* create_local() = 0;
00257 virtual void* create_array(size_t _size) = 0;
00258 virtual void free_array(void* ptr, size_t _size) = 0;
00259 public:
00260 ets_base() {create_key();}
00261 ~ets_base() {destroy_key();}
00262 void* table_lookup( bool& exists ) {
00263 void* found = get_tls();
00264 if( found ) {
00265 exists=true;
00266 } else {
00267 found = super::table_lookup(exists);
00268 set_tls(found);
00269 }
00270 return found;
00271 }
00272 void table_clear() {
00273 destroy_key();
00274 create_key();
00275 super::table_clear();
00276 }
00277 };
00278
00280 template< typename Container, typename Value >
00281 class enumerable_thread_specific_iterator
00282 #if defined(_WIN64) && defined(_MSC_VER)
00283
00284 : public std::iterator<std::random_access_iterator_tag,Value>
00285 #endif
00286 {
00288
00289 Container *my_container;
00290 typename Container::size_type my_index;
00291 mutable Value *my_value;
00292
00293 template<typename C, typename T>
00294 friend enumerable_thread_specific_iterator<C,T> operator+( ptrdiff_t offset,
00295 const enumerable_thread_specific_iterator<C,T>& v );
00296
00297 template<typename C, typename T, typename U>
00298 friend bool operator==( const enumerable_thread_specific_iterator<C,T>& i,
00299 const enumerable_thread_specific_iterator<C,U>& j );
00300
00301 template<typename C, typename T, typename U>
00302 friend bool operator<( const enumerable_thread_specific_iterator<C,T>& i,
00303 const enumerable_thread_specific_iterator<C,U>& j );
00304
00305 template<typename C, typename T, typename U>
00306 friend ptrdiff_t operator-( const enumerable_thread_specific_iterator<C,T>& i, const enumerable_thread_specific_iterator<C,U>& j );
00307
00308 template<typename C, typename U>
00309 friend class enumerable_thread_specific_iterator;
00310
00311 public:
00312
00313 enumerable_thread_specific_iterator( const Container &container, typename Container::size_type index ) :
00314 my_container(&const_cast<Container &>(container)), my_index(index), my_value(NULL) {}
00315
00317 enumerable_thread_specific_iterator() : my_container(NULL), my_index(0), my_value(NULL) {}
00318
00319 template<typename U>
00320 enumerable_thread_specific_iterator( const enumerable_thread_specific_iterator<Container, U>& other ) :
00321 my_container( other.my_container ), my_index( other.my_index), my_value( const_cast<Value *>(other.my_value) ) {}
00322
00323 enumerable_thread_specific_iterator operator+( ptrdiff_t offset ) const {
00324 return enumerable_thread_specific_iterator(*my_container, my_index + offset);
00325 }
00326
00327 enumerable_thread_specific_iterator &operator+=( ptrdiff_t offset ) {
00328 my_index += offset;
00329 my_value = NULL;
00330 return *this;
00331 }
00332
00333 enumerable_thread_specific_iterator operator-( ptrdiff_t offset ) const {
00334 return enumerable_thread_specific_iterator( *my_container, my_index-offset );
00335 }
00336
00337 enumerable_thread_specific_iterator &operator-=( ptrdiff_t offset ) {
00338 my_index -= offset;
00339 my_value = NULL;
00340 return *this;
00341 }
00342
00343 Value& operator*() const {
00344 Value* value = my_value;
00345 if( !value ) {
00346 value = my_value = reinterpret_cast<Value *>(&(*my_container)[my_index].value);
00347 }
00348 __TBB_ASSERT( value==reinterpret_cast<Value *>(&(*my_container)[my_index].value), "corrupt cache" );
00349 return *value;
00350 }
00351
00352 Value& operator[]( ptrdiff_t k ) const {
00353 return (*my_container)[my_index + k].value;
00354 }
00355
00356 Value* operator->() const {return &operator*();}
00357
00358 enumerable_thread_specific_iterator& operator++() {
00359 ++my_index;
00360 my_value = NULL;
00361 return *this;
00362 }
00363
00364 enumerable_thread_specific_iterator& operator--() {
00365 --my_index;
00366 my_value = NULL;
00367 return *this;
00368 }
00369
00371 enumerable_thread_specific_iterator operator++(int) {
00372 enumerable_thread_specific_iterator result = *this;
00373 ++my_index;
00374 my_value = NULL;
00375 return result;
00376 }
00377
00379 enumerable_thread_specific_iterator operator--(int) {
00380 enumerable_thread_specific_iterator result = *this;
00381 --my_index;
00382 my_value = NULL;
00383 return result;
00384 }
00385
00386
00387 typedef ptrdiff_t difference_type;
00388 typedef Value value_type;
00389 typedef Value* pointer;
00390 typedef Value& reference;
00391 typedef std::random_access_iterator_tag iterator_category;
00392 };
00393
00394 template<typename Container, typename T>
00395 enumerable_thread_specific_iterator<Container,T> operator+( ptrdiff_t offset,
00396 const enumerable_thread_specific_iterator<Container,T>& v ) {
00397 return enumerable_thread_specific_iterator<Container,T>( v.my_container, v.my_index + offset );
00398 }
00399
00400 template<typename Container, typename T, typename U>
00401 bool operator==( const enumerable_thread_specific_iterator<Container,T>& i,
00402 const enumerable_thread_specific_iterator<Container,U>& j ) {
00403 return i.my_index==j.my_index && i.my_container == j.my_container;
00404 }
00405
00406 template<typename Container, typename T, typename U>
00407 bool operator!=( const enumerable_thread_specific_iterator<Container,T>& i,
00408 const enumerable_thread_specific_iterator<Container,U>& j ) {
00409 return !(i==j);
00410 }
00411
00412 template<typename Container, typename T, typename U>
00413 bool operator<( const enumerable_thread_specific_iterator<Container,T>& i,
00414 const enumerable_thread_specific_iterator<Container,U>& j ) {
00415 return i.my_index<j.my_index;
00416 }
00417
00418 template<typename Container, typename T, typename U>
00419 bool operator>( const enumerable_thread_specific_iterator<Container,T>& i,
00420 const enumerable_thread_specific_iterator<Container,U>& j ) {
00421 return j<i;
00422 }
00423
00424 template<typename Container, typename T, typename U>
00425 bool operator>=( const enumerable_thread_specific_iterator<Container,T>& i,
00426 const enumerable_thread_specific_iterator<Container,U>& j ) {
00427 return !(i<j);
00428 }
00429
00430 template<typename Container, typename T, typename U>
00431 bool operator<=( const enumerable_thread_specific_iterator<Container,T>& i,
00432 const enumerable_thread_specific_iterator<Container,U>& j ) {
00433 return !(j<i);
00434 }
00435
00436 template<typename Container, typename T, typename U>
00437 ptrdiff_t operator-( const enumerable_thread_specific_iterator<Container,T>& i,
00438 const enumerable_thread_specific_iterator<Container,U>& j ) {
00439 return i.my_index-j.my_index;
00440 }
00441
00442 template<typename SegmentedContainer, typename Value >
00443 class segmented_iterator
00444 #if defined(_WIN64) && defined(_MSC_VER)
00445 : public std::iterator<std::input_iterator_tag, Value>
00446 #endif
00447 {
00448 template<typename C, typename T, typename U>
00449 friend bool operator==(const segmented_iterator<C,T>& i, const segmented_iterator<C,U>& j);
00450
00451 template<typename C, typename T, typename U>
00452 friend bool operator!=(const segmented_iterator<C,T>& i, const segmented_iterator<C,U>& j);
00453
00454 template<typename C, typename U>
00455 friend class segmented_iterator;
00456
00457 public:
00458
00459 segmented_iterator() {my_segcont = NULL;}
00460
00461 segmented_iterator( const SegmentedContainer& _segmented_container ) :
00462 my_segcont(const_cast<SegmentedContainer*>(&_segmented_container)),
00463 outer_iter(my_segcont->end()) { }
00464
00465 ~segmented_iterator() {}
00466
00467 typedef typename SegmentedContainer::iterator outer_iterator;
00468 typedef typename SegmentedContainer::value_type InnerContainer;
00469 typedef typename InnerContainer::iterator inner_iterator;
00470
00471
00472 typedef ptrdiff_t difference_type;
00473 typedef Value value_type;
00474 typedef typename SegmentedContainer::size_type size_type;
00475 typedef Value* pointer;
00476 typedef Value& reference;
00477 typedef std::input_iterator_tag iterator_category;
00478
00479
00480 template<typename U>
00481 segmented_iterator(const segmented_iterator<SegmentedContainer, U>& other) :
00482 my_segcont(other.my_segcont),
00483 outer_iter(other.outer_iter),
00484
00485 inner_iter(other.inner_iter)
00486 {}
00487
00488
00489 template<typename U>
00490 segmented_iterator& operator=( const segmented_iterator<SegmentedContainer, U>& other) {
00491 if(this != &other) {
00492 my_segcont = other.my_segcont;
00493 outer_iter = other.outer_iter;
00494 if(outer_iter != my_segcont->end()) inner_iter = other.inner_iter;
00495 }
00496 return *this;
00497 }
00498
00499
00500
00501
00502 segmented_iterator& operator=(const outer_iterator& new_outer_iter) {
00503 __TBB_ASSERT(my_segcont != NULL, NULL);
00504
00505 for(outer_iter = new_outer_iter ;outer_iter!=my_segcont->end(); ++outer_iter) {
00506 if( !outer_iter->empty() ) {
00507 inner_iter = outer_iter->begin();
00508 break;
00509 }
00510 }
00511 return *this;
00512 }
00513
00514
00515 segmented_iterator& operator++() {
00516 advance_me();
00517 return *this;
00518 }
00519
00520
00521 segmented_iterator operator++(int) {
00522 segmented_iterator tmp = *this;
00523 operator++();
00524 return tmp;
00525 }
00526
00527 bool operator==(const outer_iterator& other_outer) const {
00528 __TBB_ASSERT(my_segcont != NULL, NULL);
00529 return (outer_iter == other_outer &&
00530 (outer_iter == my_segcont->end() || inner_iter == outer_iter->begin()));
00531 }
00532
00533 bool operator!=(const outer_iterator& other_outer) const {
00534 return !operator==(other_outer);
00535
00536 }
00537
00538
00539 reference operator*() const {
00540 __TBB_ASSERT(my_segcont != NULL, NULL);
00541 __TBB_ASSERT(outer_iter != my_segcont->end(), "Dereferencing a pointer at end of container");
00542 __TBB_ASSERT(inner_iter != outer_iter->end(), NULL);
00543 return *inner_iter;
00544 }
00545
00546
00547 pointer operator->() const { return &operator*();}
00548
00549 private:
00550 SegmentedContainer* my_segcont;
00551 outer_iterator outer_iter;
00552 inner_iterator inner_iter;
00553
00554 void advance_me() {
00555 __TBB_ASSERT(my_segcont != NULL, NULL);
00556 __TBB_ASSERT(outer_iter != my_segcont->end(), NULL);
00557 __TBB_ASSERT(inner_iter != outer_iter->end(), NULL);
00558 ++inner_iter;
00559 while(inner_iter == outer_iter->end() && ++outer_iter != my_segcont->end()) {
00560 inner_iter = outer_iter->begin();
00561 }
00562 }
00563 };
00564
00565 template<typename SegmentedContainer, typename T, typename U>
00566 bool operator==( const segmented_iterator<SegmentedContainer,T>& i,
00567 const segmented_iterator<SegmentedContainer,U>& j ) {
00568 if(i.my_segcont != j.my_segcont) return false;
00569 if(i.my_segcont == NULL) return true;
00570 if(i.outer_iter != j.outer_iter) return false;
00571 if(i.outer_iter == i.my_segcont->end()) return true;
00572 return i.inner_iter == j.inner_iter;
00573 }
00574
00575
00576 template<typename SegmentedContainer, typename T, typename U>
00577 bool operator!=( const segmented_iterator<SegmentedContainer,T>& i,
00578 const segmented_iterator<SegmentedContainer,U>& j ) {
00579 return !(i==j);
00580 }
00581
00582 template<typename T>
00583 struct destruct_only: tbb::internal::no_copy {
00584 tbb::aligned_space<T,1> value;
00585 ~destruct_only() {value.begin()[0].~T();}
00586 };
00587
00588 template<typename T>
00589 struct construct_by_default: tbb::internal::no_assign {
00590 void construct(void*where) {new(where) T();}
00591 construct_by_default( int ) {}
00592 };
00593
00594 template<typename T>
00595 struct construct_by_exemplar: tbb::internal::no_assign {
00596 const T exemplar;
00597 void construct(void*where) {new(where) T(exemplar);}
00598 construct_by_exemplar( const T& t ) : exemplar(t) {}
00599 };
00600
00601 template<typename T, typename Finit>
00602 struct construct_by_finit: tbb::internal::no_assign {
00603 Finit f;
00604 void construct(void* where) {new(where) T(f());}
00605 construct_by_finit( const Finit& f_ ) : f(f_) {}
00606 };
00607
00608
00609 template<typename T>
00610 class callback_base {
00611 public:
00612
00613 virtual callback_base* clone() = 0;
00614
00615 virtual void destroy() = 0;
00616
00617 virtual ~callback_base() { }
00618
00619 virtual void construct(void* where) = 0;
00620 };
00621
00622 template <typename T, typename Constructor>
00623 class callback_leaf: public callback_base<T>, Constructor {
00624 template<typename X> callback_leaf( const X& x ) : Constructor(x) {}
00625
00626 typedef typename tbb::tbb_allocator<callback_leaf> my_allocator_type;
00627
00628 callback_base<T>* clone() {
00629 void* where = my_allocator_type().allocate(1);
00630 return new(where) callback_leaf(*this);
00631 }
00632
00633 void destroy() {
00634 my_allocator_type().destroy(this);
00635 my_allocator_type().deallocate(this,1);
00636 }
00637
00638 void construct(void* where) {
00639 Constructor::construct(where);
00640 }
00641 public:
00642 template<typename X>
00643 static callback_base<T>* make( const X& x ) {
00644 void* where = my_allocator_type().allocate(1);
00645 return new(where) callback_leaf(x);
00646 }
00647 };
00648
00650
00655 template<typename U, size_t ModularSize>
00656 struct ets_element {
00657 char value[ModularSize==0 ? sizeof(U) : sizeof(U)+(tbb::internal::NFS_MaxLineSize-ModularSize)];
00658 void unconstruct() {
00659 tbb::internal::punned_cast<U*>(&value)->~U();
00660 }
00661 };
00662
00663 }
00665
00667
00686 template <typename T,
00687 typename Allocator=cache_aligned_allocator<T>,
00688 ets_key_usage_type ETS_key_type=ets_no_key >
00689 class enumerable_thread_specific: internal::ets_base<ETS_key_type> {
00690
00691 template<typename U, typename A, ets_key_usage_type C> friend class enumerable_thread_specific;
00692
00693 typedef internal::ets_element<T,sizeof(T)%tbb::internal::NFS_MaxLineSize> padded_element;
00694
00696 template<typename I>
00697 class generic_range_type: public blocked_range<I> {
00698 public:
00699 typedef T value_type;
00700 typedef T& reference;
00701 typedef const T& const_reference;
00702 typedef I iterator;
00703 typedef ptrdiff_t difference_type;
00704 generic_range_type( I begin_, I end_, size_t grainsize_ = 1) : blocked_range<I>(begin_,end_,grainsize_) {}
00705 template<typename U>
00706 generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {}
00707 generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {}
00708 };
00709
00710 typedef typename Allocator::template rebind< padded_element >::other padded_allocator_type;
00711 typedef tbb::concurrent_vector< padded_element, padded_allocator_type > internal_collection_type;
00712
00713 internal::callback_base<T> *my_construct_callback;
00714
00715 internal_collection_type my_locals;
00716
00717 void* create_local() {
00718 #if TBB_DEPRECATED
00719 void* lref = &my_locals[my_locals.push_back(padded_element())];
00720 #else
00721 void* lref = &*my_locals.push_back(padded_element());
00722 #endif
00723 my_construct_callback->construct(lref);
00724 return lref;
00725 }
00726
00727 void unconstruct_locals() {
00728 for(typename internal_collection_type::iterator cvi = my_locals.begin(); cvi != my_locals.end(); ++cvi) {
00729 cvi->unconstruct();
00730 }
00731 }
00732
00733 typedef typename Allocator::template rebind< uintptr_t >::other array_allocator_type;
00734
00735
00736 void* create_array(size_t _size) {
00737 size_t nelements = (_size + sizeof(uintptr_t) -1) / sizeof(uintptr_t);
00738 return array_allocator_type().allocate(nelements);
00739 }
00740
00741 void free_array( void* _ptr, size_t _size) {
00742 size_t nelements = (_size + sizeof(uintptr_t) -1) / sizeof(uintptr_t);
00743 array_allocator_type().deallocate( reinterpret_cast<uintptr_t *>(_ptr),nelements);
00744 }
00745
00746 public:
00747
00749 typedef Allocator allocator_type;
00750 typedef T value_type;
00751 typedef T& reference;
00752 typedef const T& const_reference;
00753 typedef T* pointer;
00754 typedef const T* const_pointer;
00755 typedef typename internal_collection_type::size_type size_type;
00756 typedef typename internal_collection_type::difference_type difference_type;
00757
00758
00759 typedef typename internal::enumerable_thread_specific_iterator< internal_collection_type, value_type > iterator;
00760 typedef typename internal::enumerable_thread_specific_iterator< internal_collection_type, const value_type > const_iterator;
00761
00762
00763 typedef generic_range_type< iterator > range_type;
00764 typedef generic_range_type< const_iterator > const_range_type;
00765
00767 enumerable_thread_specific() :
00768 my_construct_callback( internal::callback_leaf<T,internal::construct_by_default<T> >::make(0) )
00769 {}
00770
00772 template <typename Finit>
00773 enumerable_thread_specific( Finit finit ) :
00774 my_construct_callback( internal::callback_leaf<T,internal::construct_by_finit<T,Finit> >::make( finit ) )
00775 {}
00776
00778 enumerable_thread_specific(const T& exemplar) :
00779 my_construct_callback( internal::callback_leaf<T,internal::construct_by_exemplar<T> >::make( exemplar ) )
00780 {}
00781
00783 ~enumerable_thread_specific() {
00784 my_construct_callback->destroy();
00785 this->clear();
00786
00787 }
00788
00790 reference local() {
00791 bool exists;
00792 return local(exists);
00793 }
00794
00796 reference local(bool& exists) {
00797 void* ptr = this->table_lookup(exists);
00798 return *(T*)ptr;
00799 }
00800
00802 size_type size() const { return my_locals.size(); }
00803
00805 bool empty() const { return my_locals.empty(); }
00806
00808 iterator begin() { return iterator( my_locals, 0 ); }
00810 iterator end() { return iterator(my_locals, my_locals.size() ); }
00811
00813 const_iterator begin() const { return const_iterator(my_locals, 0); }
00814
00816 const_iterator end() const { return const_iterator(my_locals, my_locals.size()); }
00817
00819 range_type range( size_t grainsize=1 ) { return range_type( begin(), end(), grainsize ); }
00820
00822 const_range_type range( size_t grainsize=1 ) const { return const_range_type( begin(), end(), grainsize ); }
00823
00825 void clear() {
00826 unconstruct_locals();
00827 my_locals.clear();
00828 this->table_clear();
00829
00830
00831 }
00832
00833 private:
00834
00835 template<typename U, typename A2, ets_key_usage_type C2>
00836 void internal_copy( const enumerable_thread_specific<U, A2, C2>& other);
00837
00838 public:
00839
00840 template<typename U, typename Alloc, ets_key_usage_type Cachetype>
00841 enumerable_thread_specific( const enumerable_thread_specific<U, Alloc, Cachetype>& other ) : internal::ets_base<ETS_key_type> ()
00842 {
00843 internal_copy(other);
00844 }
00845
00846 enumerable_thread_specific( const enumerable_thread_specific& other ) : internal::ets_base<ETS_key_type> ()
00847 {
00848 internal_copy(other);
00849 }
00850
00851 private:
00852
00853 template<typename U, typename A2, ets_key_usage_type C2>
00854 enumerable_thread_specific &
00855 internal_assign(const enumerable_thread_specific<U, A2, C2>& other) {
00856 if(static_cast<void *>( this ) != static_cast<const void *>( &other )) {
00857 this->clear();
00858 my_construct_callback->destroy();
00859 my_construct_callback = 0;
00860 internal_copy( other );
00861 }
00862 return *this;
00863 }
00864
00865 public:
00866
00867
00868 enumerable_thread_specific& operator=(const enumerable_thread_specific& other) {
00869 return internal_assign(other);
00870 }
00871
00872 template<typename U, typename Alloc, ets_key_usage_type Cachetype>
00873 enumerable_thread_specific& operator=(const enumerable_thread_specific<U, Alloc, Cachetype>& other)
00874 {
00875 return internal_assign(other);
00876 }
00877
00878
00879 template <typename combine_func_t>
00880 T combine(combine_func_t f_combine) {
00881 if(begin() == end()) {
00882 internal::destruct_only<T> location;
00883 my_construct_callback->construct(location.value.begin());
00884 return *location.value.begin();
00885 }
00886 const_iterator ci = begin();
00887 T my_result = *ci;
00888 while(++ci != end())
00889 my_result = f_combine( my_result, *ci );
00890 return my_result;
00891 }
00892
00893
00894 template <typename combine_func_t>
00895 void combine_each(combine_func_t f_combine) {
00896 for(const_iterator ci = begin(); ci != end(); ++ci) {
00897 f_combine( *ci );
00898 }
00899 }
00900
00901 };
00902
00903 template <typename T, typename Allocator, ets_key_usage_type ETS_key_type>
00904 template<typename U, typename A2, ets_key_usage_type C2>
00905 void enumerable_thread_specific<T,Allocator,ETS_key_type>::internal_copy( const enumerable_thread_specific<U, A2, C2>& other) {
00906
00907 my_construct_callback = other.my_construct_callback->clone();
00908
00909 typedef internal::ets_base<ets_no_key> base;
00910 __TBB_ASSERT(my_locals.size()==0,NULL);
00911 this->table_reserve_for_copy( other );
00912 for( base::array* r=other.my_root; r; r=r->next ) {
00913 for( size_t i=0; i<r->size(); ++i ) {
00914 base::slot& s1 = r->at(i);
00915 if( !s1.empty() ) {
00916 base::slot& s2 = this->table_find(s1.key);
00917 if( s2.empty() ) {
00918 #if TBB_DEPRECATED
00919 void* lref = &my_locals[my_locals.push_back(padded_element())];
00920 #else
00921 void* lref = &*my_locals.push_back(padded_element());
00922 #endif
00923 s2.ptr = new(lref) T(*(U*)s1.ptr);
00924 s2.key = s1.key;
00925 } else {
00926
00927 }
00928 }
00929 }
00930 }
00931 }
00932
00933 template< typename Container >
00934 class flattened2d {
00935
00936
00937 typedef typename Container::value_type conval_type;
00938
00939 public:
00940
00942 typedef typename conval_type::size_type size_type;
00943 typedef typename conval_type::difference_type difference_type;
00944 typedef typename conval_type::allocator_type allocator_type;
00945 typedef typename conval_type::value_type value_type;
00946 typedef typename conval_type::reference reference;
00947 typedef typename conval_type::const_reference const_reference;
00948 typedef typename conval_type::pointer pointer;
00949 typedef typename conval_type::const_pointer const_pointer;
00950
00951 typedef typename internal::segmented_iterator<Container, value_type> iterator;
00952 typedef typename internal::segmented_iterator<Container, const value_type> const_iterator;
00953
00954 flattened2d( const Container &c, typename Container::const_iterator b, typename Container::const_iterator e ) :
00955 my_container(const_cast<Container*>(&c)), my_begin(b), my_end(e) { }
00956
00957 flattened2d( const Container &c ) :
00958 my_container(const_cast<Container*>(&c)), my_begin(c.begin()), my_end(c.end()) { }
00959
00960 iterator begin() { return iterator(*my_container) = my_begin; }
00961 iterator end() { return iterator(*my_container) = my_end; }
00962 const_iterator begin() const { return const_iterator(*my_container) = my_begin; }
00963 const_iterator end() const { return const_iterator(*my_container) = my_end; }
00964
00965 size_type size() const {
00966 size_type tot_size = 0;
00967 for(typename Container::const_iterator i = my_begin; i != my_end; ++i) {
00968 tot_size += i->size();
00969 }
00970 return tot_size;
00971 }
00972
00973 private:
00974
00975 Container *my_container;
00976 typename Container::const_iterator my_begin;
00977 typename Container::const_iterator my_end;
00978
00979 };
00980
00981 template <typename Container>
00982 flattened2d<Container> flatten2d(const Container &c, const typename Container::const_iterator b, const typename Container::const_iterator e) {
00983 return flattened2d<Container>(c, b, e);
00984 }
00985
00986 template <typename Container>
00987 flattened2d<Container> flatten2d(const Container &c) {
00988 return flattened2d<Container>(c);
00989 }
00990
00991 }
00992
00993 namespace internal {
00994 using interface6::internal::segmented_iterator;
00995 }
00996
00997 using interface6::enumerable_thread_specific;
00998 using interface6::flattened2d;
00999 using interface6::flatten2d;
01000
01001 }
01002
01003 #endif