![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 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 "cache_aligned_allocator.h" 00035 #if __SUNPRO_CC 00036 #include <string.h> // for memcpy 00037 #endif 00038 00039 #if _WIN32||_WIN64 00040 #include <windows.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 interface5 { 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_GCC_3_3_PROTECTED_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 __TBB_ASSERT(sizeof(void*)==sizeof(tbb::atomic<key_type>*), NULL); 00088 union { void* space; tbb::atomic<key_type>* key_atomic; } helper; 00089 helper.space = &key; 00090 return helper.key_atomic->compare_and_swap(k,0)==0; 00091 } 00092 }; 00093 #if __TBB_GCC_3_3_PROTECTED_BROKEN 00094 protected: 00095 #endif 00096 00097 static key_type key_of_current_thread() { 00098 tbb::tbb_thread::id id = tbb::this_tbb_thread::get_id(); 00099 key_type k; 00100 memcpy( &k, &id, sizeof(k) ); 00101 return k; 00102 } 00103 00105 00107 atomic<array*> my_root; 00108 atomic<size_t> my_count; 00109 virtual void* create_local() = 0; 00110 virtual void* create_array(size_t _size) = 0; // _size in bytes 00111 virtual void free_array(void* ptr, size_t _size) = 0; // _size in bytes 00112 array* allocate( size_t lg_size ) { 00113 size_t n = 1<<lg_size; 00114 array* a = static_cast<array*>(create_array( sizeof(array)+n*sizeof(slot) )); 00115 a->lg_size = lg_size; 00116 std::memset( a+1, 0, n*sizeof(slot) ); 00117 return a; 00118 } 00119 void free(array* a) { 00120 size_t n = 1<<(a->lg_size); 00121 free_array( (void *)a, size_t(sizeof(array)+n*sizeof(slot)) ); 00122 } 00123 static size_t hash( key_type k ) { 00124 // Multiplicative hashing. Client should use *upper* bits. 00125 // casts required for Mac gcc4.* compiler 00126 #if __TBB_WORDSIZE == 4 00127 return uintptr_t(k)*0x9E3779B9; 00128 #else 00129 return uintptr_t(k)*0x9E3779B97F4A7C15; 00130 #endif 00131 } 00132 00133 ets_base() {my_root=NULL; my_count=0;} 00134 virtual ~ets_base(); // g++ complains if this is not virtual... 00135 void* table_lookup( bool& exists ); 00136 void table_clear(); 00137 slot& table_find( key_type k ) { 00138 size_t h = hash(k); 00139 array* r = my_root; 00140 size_t mask = r->mask(); 00141 for(size_t i = r->start(h);;i=(i+1)&mask) { 00142 slot& s = r->at(i); 00143 if( s.empty() || s.match(k) ) 00144 return s; 00145 } 00146 } 00147 void table_reserve_for_copy( const ets_base& other ) { 00148 __TBB_ASSERT(!my_root,NULL); 00149 __TBB_ASSERT(!my_count,NULL); 00150 if( other.my_root ) { 00151 array* a = allocate(other.my_root->lg_size); 00152 a->next = NULL; 00153 my_root = a; 00154 my_count = other.my_count; 00155 } 00156 } 00157 }; 00158 00159 template<ets_key_usage_type ETS_key_type> 00160 ets_base<ETS_key_type>::~ets_base() { 00161 __TBB_ASSERT(!my_root, NULL); 00162 } 00163 00164 template<ets_key_usage_type ETS_key_type> 00165 void ets_base<ETS_key_type>::table_clear() { 00166 while( array* r = my_root ) { 00167 my_root = r->next; 00168 free(r); 00169 } 00170 my_count = 0; 00171 } 00172 00173 template<ets_key_usage_type ETS_key_type> 00174 void* ets_base<ETS_key_type>::table_lookup( bool& exists ) { 00175 const key_type k = key_of_current_thread(); 00176 00177 __TBB_ASSERT(k!=0,NULL); 00178 void* found; 00179 size_t h = hash(k); 00180 for( array* r=my_root; r; r=r->next ) { 00181 size_t mask=r->mask(); 00182 for(size_t i = r->start(h); ;i=(i+1)&mask) { 00183 slot& s = r->at(i); 00184 if( s.empty() ) break; 00185 if( s.match(k) ) { 00186 if( r==my_root ) { 00187 // Success at top level 00188 exists = true; 00189 return s.ptr; 00190 } else { 00191 // Success at some other level. Need to insert at top level. 00192 exists = true; 00193 found = s.ptr; 00194 goto insert; 00195 } 00196 } 00197 } 00198 } 00199 // Key does not yet exist 00200 exists = false; 00201 found = create_local(); 00202 { 00203 size_t c = ++my_count; 00204 array* r = my_root; 00205 if( !r || c>r->size()/2 ) { 00206 size_t s = r ? r->lg_size : 2; 00207 while( c>size_t(1)<<(s-1) ) ++s; 00208 array* a = allocate(s); 00209 for(;;) { 00210 a->next = my_root; 00211 array* new_r = my_root.compare_and_swap(a,r); 00212 if( new_r==r ) break; 00213 if( new_r->lg_size>=s ) { 00214 // Another thread inserted an equal or bigger array, so our array is superfluous. 00215 free(a); 00216 break; 00217 } 00218 r = new_r; 00219 } 00220 } 00221 } 00222 insert: 00223 // Guaranteed to be room for it, and it is not present, so search for empty slot and grab it. 00224 array* ir = my_root; 00225 size_t mask = ir->mask(); 00226 for(size_t i = ir->start(h);;i=(i+1)&mask) { 00227 slot& s = ir->at(i); 00228 if( s.empty() ) { 00229 if( s.claim(k) ) { 00230 s.ptr = found; 00231 return found; 00232 } 00233 } 00234 } 00235 }; 00236 00238 template <> 00239 class ets_base<ets_key_per_instance>: protected ets_base<ets_no_key> { 00240 typedef ets_base<ets_no_key> super; 00241 #if _WIN32||_WIN64 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 #else 00248 typedef pthread_key_t tls_key_t; 00249 void create_key() { pthread_key_create(&my_key, NULL); } 00250 void destroy_key() { pthread_key_delete(my_key); } 00251 void set_tls( void * value ) const { pthread_setspecific(my_key, value); } 00252 void* get_tls() const { return pthread_getspecific(my_key); } 00253 #endif 00254 tls_key_t my_key; 00255 virtual void* create_local() = 0; 00256 virtual void* create_array(size_t _size) = 0; // _size in bytes 00257 virtual void free_array(void* ptr, size_t _size) = 0; // size in bytes 00258 public: 00259 ets_base() {create_key();} 00260 ~ets_base() {destroy_key();} 00261 void* table_lookup( bool& exists ) { 00262 void* found = get_tls(); 00263 if( found ) { 00264 exists=true; 00265 } else { 00266 found = super::table_lookup(exists); 00267 set_tls(found); 00268 } 00269 return found; 00270 } 00271 void table_clear() { 00272 destroy_key(); 00273 create_key(); 00274 super::table_clear(); 00275 } 00276 }; 00277 00279 template< typename Container, typename Value > 00280 class enumerable_thread_specific_iterator 00281 #if defined(_WIN64) && defined(_MSC_VER) 00282 // Ensure that Microsoft's internal template function _Val_type works correctly. 00283 : public std::iterator<std::random_access_iterator_tag,Value> 00284 #endif /* defined(_WIN64) && defined(_MSC_VER) */ 00285 { 00287 00288 Container *my_container; 00289 typename Container::size_type my_index; 00290 mutable Value *my_value; 00291 00292 template<typename C, typename T> 00293 friend enumerable_thread_specific_iterator<C,T> operator+( ptrdiff_t offset, 00294 const enumerable_thread_specific_iterator<C,T>& v ); 00295 00296 template<typename C, typename T, typename U> 00297 friend bool operator==( const enumerable_thread_specific_iterator<C,T>& i, 00298 const enumerable_thread_specific_iterator<C,U>& j ); 00299 00300 template<typename C, typename T, typename U> 00301 friend bool operator<( const enumerable_thread_specific_iterator<C,T>& i, 00302 const enumerable_thread_specific_iterator<C,U>& j ); 00303 00304 template<typename C, typename T, typename U> 00305 friend ptrdiff_t operator-( const enumerable_thread_specific_iterator<C,T>& i, const enumerable_thread_specific_iterator<C,U>& j ); 00306 00307 template<typename C, typename U> 00308 friend class enumerable_thread_specific_iterator; 00309 00310 public: 00311 00312 enumerable_thread_specific_iterator( const Container &container, typename Container::size_type index ) : 00313 my_container(&const_cast<Container &>(container)), my_index(index), my_value(NULL) {} 00314 00316 enumerable_thread_specific_iterator() : my_container(NULL), my_index(0), my_value(NULL) {} 00317 00318 template<typename U> 00319 enumerable_thread_specific_iterator( const enumerable_thread_specific_iterator<Container, U>& other ) : 00320 my_container( other.my_container ), my_index( other.my_index), my_value( const_cast<Value *>(other.my_value) ) {} 00321 00322 enumerable_thread_specific_iterator operator+( ptrdiff_t offset ) const { 00323 return enumerable_thread_specific_iterator(*my_container, my_index + offset); 00324 } 00325 00326 enumerable_thread_specific_iterator &operator+=( ptrdiff_t offset ) { 00327 my_index += offset; 00328 my_value = NULL; 00329 return *this; 00330 } 00331 00332 enumerable_thread_specific_iterator operator-( ptrdiff_t offset ) const { 00333 return enumerable_thread_specific_iterator( *my_container, my_index-offset ); 00334 } 00335 00336 enumerable_thread_specific_iterator &operator-=( ptrdiff_t offset ) { 00337 my_index -= offset; 00338 my_value = NULL; 00339 return *this; 00340 } 00341 00342 Value& operator*() const { 00343 Value* value = my_value; 00344 if( !value ) { 00345 value = my_value = reinterpret_cast<Value *>(&(*my_container)[my_index].value); 00346 } 00347 __TBB_ASSERT( value==reinterpret_cast<Value *>(&(*my_container)[my_index].value), "corrupt cache" ); 00348 return *value; 00349 } 00350 00351 Value& operator[]( ptrdiff_t k ) const { 00352 return (*my_container)[my_index + k].value; 00353 } 00354 00355 Value* operator->() const {return &operator*();} 00356 00357 enumerable_thread_specific_iterator& operator++() { 00358 ++my_index; 00359 my_value = NULL; 00360 return *this; 00361 } 00362 00363 enumerable_thread_specific_iterator& operator--() { 00364 --my_index; 00365 my_value = NULL; 00366 return *this; 00367 } 00368 00370 enumerable_thread_specific_iterator operator++(int) { 00371 enumerable_thread_specific_iterator result = *this; 00372 ++my_index; 00373 my_value = NULL; 00374 return result; 00375 } 00376 00378 enumerable_thread_specific_iterator operator--(int) { 00379 enumerable_thread_specific_iterator result = *this; 00380 --my_index; 00381 my_value = NULL; 00382 return result; 00383 } 00384 00385 // STL support 00386 typedef ptrdiff_t difference_type; 00387 typedef Value value_type; 00388 typedef Value* pointer; 00389 typedef Value& reference; 00390 typedef std::random_access_iterator_tag iterator_category; 00391 }; 00392 00393 template<typename Container, typename T> 00394 enumerable_thread_specific_iterator<Container,T> operator+( ptrdiff_t offset, 00395 const enumerable_thread_specific_iterator<Container,T>& v ) { 00396 return enumerable_thread_specific_iterator<Container,T>( v.my_container, v.my_index + offset ); 00397 } 00398 00399 template<typename Container, typename T, typename U> 00400 bool operator==( const enumerable_thread_specific_iterator<Container,T>& i, 00401 const enumerable_thread_specific_iterator<Container,U>& j ) { 00402 return i.my_index==j.my_index && i.my_container == j.my_container; 00403 } 00404 00405 template<typename Container, typename T, typename U> 00406 bool operator!=( const enumerable_thread_specific_iterator<Container,T>& i, 00407 const enumerable_thread_specific_iterator<Container,U>& j ) { 00408 return !(i==j); 00409 } 00410 00411 template<typename Container, typename T, typename U> 00412 bool operator<( const enumerable_thread_specific_iterator<Container,T>& i, 00413 const enumerable_thread_specific_iterator<Container,U>& j ) { 00414 return i.my_index<j.my_index; 00415 } 00416 00417 template<typename Container, typename T, typename U> 00418 bool operator>( const enumerable_thread_specific_iterator<Container,T>& i, 00419 const enumerable_thread_specific_iterator<Container,U>& j ) { 00420 return j<i; 00421 } 00422 00423 template<typename Container, typename T, typename U> 00424 bool operator>=( const enumerable_thread_specific_iterator<Container,T>& i, 00425 const enumerable_thread_specific_iterator<Container,U>& j ) { 00426 return !(i<j); 00427 } 00428 00429 template<typename Container, typename T, typename U> 00430 bool operator<=( const enumerable_thread_specific_iterator<Container,T>& i, 00431 const enumerable_thread_specific_iterator<Container,U>& j ) { 00432 return !(j<i); 00433 } 00434 00435 template<typename Container, typename T, typename U> 00436 ptrdiff_t operator-( const enumerable_thread_specific_iterator<Container,T>& i, 00437 const enumerable_thread_specific_iterator<Container,U>& j ) { 00438 return i.my_index-j.my_index; 00439 } 00440 00441 template<typename SegmentedContainer, typename Value > 00442 class segmented_iterator 00443 #if defined(_WIN64) && defined(_MSC_VER) 00444 : public std::iterator<std::input_iterator_tag, Value> 00445 #endif 00446 { 00447 template<typename C, typename T, typename U> 00448 friend bool operator==(const segmented_iterator<C,T>& i, const segmented_iterator<C,U>& j); 00449 00450 template<typename C, typename T, typename U> 00451 friend bool operator!=(const segmented_iterator<C,T>& i, const segmented_iterator<C,U>& j); 00452 00453 template<typename C, typename U> 00454 friend class segmented_iterator; 00455 00456 public: 00457 00458 segmented_iterator() {my_segcont = NULL;} 00459 00460 segmented_iterator( const SegmentedContainer& _segmented_container ) : 00461 my_segcont(const_cast<SegmentedContainer*>(&_segmented_container)), 00462 outer_iter(my_segcont->end()) { } 00463 00464 ~segmented_iterator() {} 00465 00466 typedef typename SegmentedContainer::iterator outer_iterator; 00467 typedef typename SegmentedContainer::value_type InnerContainer; 00468 typedef typename InnerContainer::iterator inner_iterator; 00469 00470 // STL support 00471 typedef ptrdiff_t difference_type; 00472 typedef Value value_type; 00473 typedef typename SegmentedContainer::size_type size_type; 00474 typedef Value* pointer; 00475 typedef Value& reference; 00476 typedef std::input_iterator_tag iterator_category; 00477 00478 // Copy Constructor 00479 template<typename U> 00480 segmented_iterator(const segmented_iterator<SegmentedContainer, U>& other) : 00481 my_segcont(other.my_segcont), 00482 outer_iter(other.outer_iter), 00483 // can we assign a default-constructed iterator to inner if we're at the end? 00484 inner_iter(other.inner_iter) 00485 {} 00486 00487 // assignment 00488 template<typename U> 00489 segmented_iterator& operator=( const segmented_iterator<SegmentedContainer, U>& other) { 00490 if(this != &other) { 00491 my_segcont = other.my_segcont; 00492 outer_iter = other.outer_iter; 00493 if(outer_iter != my_segcont->end()) inner_iter = other.inner_iter; 00494 } 00495 return *this; 00496 } 00497 00498 // allow assignment of outer iterator to segmented iterator. Once it is 00499 // assigned, move forward until a non-empty inner container is found or 00500 // the end of the outer container is reached. 00501 segmented_iterator& operator=(const outer_iterator& new_outer_iter) { 00502 __TBB_ASSERT(my_segcont != NULL, NULL); 00503 // check that this iterator points to something inside the segmented container 00504 for(outer_iter = new_outer_iter ;outer_iter!=my_segcont->end(); ++outer_iter) { 00505 if( !outer_iter->empty() ) { 00506 inner_iter = outer_iter->begin(); 00507 break; 00508 } 00509 } 00510 return *this; 00511 } 00512 00513 // pre-increment 00514 segmented_iterator& operator++() { 00515 advance_me(); 00516 return *this; 00517 } 00518 00519 // post-increment 00520 segmented_iterator operator++(int) { 00521 segmented_iterator tmp = *this; 00522 operator++(); 00523 return tmp; 00524 } 00525 00526 bool operator==(const outer_iterator& other_outer) const { 00527 __TBB_ASSERT(my_segcont != NULL, NULL); 00528 return (outer_iter == other_outer && 00529 (outer_iter == my_segcont->end() || inner_iter == outer_iter->begin())); 00530 } 00531 00532 bool operator!=(const outer_iterator& other_outer) const { 00533 return !operator==(other_outer); 00534 00535 } 00536 00537 // (i)* RHS 00538 reference operator*() const { 00539 __TBB_ASSERT(my_segcont != NULL, NULL); 00540 __TBB_ASSERT(outer_iter != my_segcont->end(), "Dereferencing a pointer at end of container"); 00541 __TBB_ASSERT(inner_iter != outer_iter->end(), NULL); // should never happen 00542 return *inner_iter; 00543 } 00544 00545 // i-> 00546 pointer operator->() const { return &operator*();} 00547 00548 private: 00549 SegmentedContainer* my_segcont; 00550 outer_iterator outer_iter; 00551 inner_iterator inner_iter; 00552 00553 void advance_me() { 00554 __TBB_ASSERT(my_segcont != NULL, NULL); 00555 __TBB_ASSERT(outer_iter != my_segcont->end(), NULL); // not true if there are no inner containers 00556 __TBB_ASSERT(inner_iter != outer_iter->end(), NULL); // not true if the inner containers are all empty. 00557 ++inner_iter; 00558 while(inner_iter == outer_iter->end() && ++outer_iter != my_segcont->end()) { 00559 inner_iter = outer_iter->begin(); 00560 } 00561 } 00562 }; // segmented_iterator 00563 00564 template<typename SegmentedContainer, typename T, typename U> 00565 bool operator==( const segmented_iterator<SegmentedContainer,T>& i, 00566 const segmented_iterator<SegmentedContainer,U>& j ) { 00567 if(i.my_segcont != j.my_segcont) return false; 00568 if(i.my_segcont == NULL) return true; 00569 if(i.outer_iter != j.outer_iter) return false; 00570 if(i.outer_iter == i.my_segcont->end()) return true; 00571 return i.inner_iter == j.inner_iter; 00572 } 00573 00574 // != 00575 template<typename SegmentedContainer, typename T, typename U> 00576 bool operator!=( const segmented_iterator<SegmentedContainer,T>& i, 00577 const segmented_iterator<SegmentedContainer,U>& j ) { 00578 return !(i==j); 00579 } 00580 00581 // storage for initialization function pointer 00582 template<typename T> 00583 struct callback_base { 00584 virtual T apply( ) = 0; 00585 virtual void destroy( ) = 0; 00586 // need to be able to create copies of callback_base for copy constructor 00587 virtual callback_base* make_copy() = 0; 00588 // need virtual destructor to satisfy GCC compiler warning 00589 virtual ~callback_base() { } 00590 }; 00591 00592 template <typename T, typename Functor> 00593 struct callback_leaf : public callback_base<T>, public tbb::internal::no_copy { 00594 typedef Functor my_callback_type; 00595 typedef callback_leaf<T,Functor> my_type; 00596 typedef my_type* callback_pointer; 00597 typedef typename tbb::tbb_allocator<my_type> my_allocator_type; 00598 Functor f; 00599 callback_leaf( const Functor& f_) : f(f_) { 00600 } 00601 00602 static callback_pointer new_callback(const Functor& f_ ) { 00603 void* new_void = my_allocator_type().allocate(1); 00604 callback_pointer new_cb = new (new_void) callback_leaf<T,Functor>(f_); // placement new 00605 return new_cb; 00606 } 00607 00608 /* override */ callback_pointer make_copy() { 00609 return new_callback( f ); 00610 } 00611 00612 /* override */ void destroy( ) { 00613 callback_pointer my_ptr = this; 00614 my_allocator_type().destroy(my_ptr); 00615 my_allocator_type().deallocate(my_ptr,1); 00616 } 00617 /* override */ T apply() { return f(); } // does copy construction of returned value. 00618 }; 00619 00620 00622 00627 template<typename U, size_t ModularSize> 00628 struct ets_element { 00629 char value[sizeof(U) + tbb::internal::NFS_MaxLineSize-ModularSize]; 00630 void unconstruct() { 00631 // "reinterpret_cast<U*>(&value)->~U();" causes type-punning warning with gcc 4.4, 00632 // "U* u = reinterpret_cast<U*>(&value); u->~U();" causes unused variable warning with VS2010. 00633 // Thus another "casting via union" hack. 00634 __TBB_ASSERT(sizeof(void*)==sizeof(U*),NULL); 00635 union { void* space; U* val; } helper; 00636 helper.space = &value; 00637 helper.val->~U(); 00638 } 00639 }; 00640 00642 template<typename U> 00643 struct ets_element<U,0> { 00644 char value[sizeof(U)]; 00645 void unconstruct() { // Same implementation as in general case 00646 __TBB_ASSERT(sizeof(void*)==sizeof(U*),NULL); 00647 union { void* space; U* val; } helper; 00648 helper.space = &value; 00649 helper.val->~U(); 00650 } 00651 }; 00652 00653 } // namespace internal 00655 00657 00676 template <typename T, 00677 typename Allocator=cache_aligned_allocator<T>, 00678 ets_key_usage_type ETS_key_type=ets_no_key > 00679 class enumerable_thread_specific: internal::ets_base<ETS_key_type> { 00680 00681 template<typename U, typename A, ets_key_usage_type C> friend class enumerable_thread_specific; 00682 00683 typedef internal::ets_element<T,sizeof(T)%tbb::internal::NFS_MaxLineSize> padded_element; 00684 00686 template<typename I> 00687 class generic_range_type: public blocked_range<I> { 00688 public: 00689 typedef T value_type; 00690 typedef T& reference; 00691 typedef const T& const_reference; 00692 typedef I iterator; 00693 typedef ptrdiff_t difference_type; 00694 generic_range_type( I begin_, I end_, size_t grainsize_ = 1) : blocked_range<I>(begin_,end_,grainsize_) {} 00695 template<typename U> 00696 generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {} 00697 generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {} 00698 }; 00699 00700 typedef typename Allocator::template rebind< padded_element >::other padded_allocator_type; 00701 typedef tbb::concurrent_vector< padded_element, padded_allocator_type > internal_collection_type; 00702 00703 internal::callback_base<T> *my_finit_callback; 00704 00705 // need to use a pointed-to exemplar because T may not be assignable. 00706 // using tbb_allocator instead of padded_element_allocator because we may be 00707 // copying an exemplar from one instantiation of ETS to another with a different 00708 // allocator. 00709 typedef typename tbb::tbb_allocator<padded_element > exemplar_allocator_type; 00710 static padded_element * create_exemplar(const T& my_value) { 00711 padded_element *new_exemplar = reinterpret_cast<padded_element *>(exemplar_allocator_type().allocate(1)); 00712 new(new_exemplar->value) T(my_value); 00713 return new_exemplar; 00714 } 00715 00716 static padded_element *create_exemplar( ) { 00717 padded_element *new_exemplar = reinterpret_cast<padded_element *>(exemplar_allocator_type().allocate(1)); 00718 new(new_exemplar->value) T( ); 00719 return new_exemplar; 00720 } 00721 00722 static void free_exemplar(padded_element *my_ptr) { 00723 my_ptr->unconstruct(); 00724 exemplar_allocator_type().destroy(my_ptr); 00725 exemplar_allocator_type().deallocate(my_ptr,1); 00726 } 00727 00728 padded_element* my_exemplar_ptr; 00729 00730 internal_collection_type my_locals; 00731 00732 /*override*/ void* create_local() { 00733 #if TBB_DEPRECATED 00734 void* lref = &my_locals[my_locals.push_back(padded_element())]; 00735 #else 00736 void* lref = &*my_locals.push_back(padded_element()); 00737 #endif 00738 if(my_finit_callback) { 00739 new(lref) T(my_finit_callback->apply()); 00740 } else if(my_exemplar_ptr) { 00741 pointer t_exemp = reinterpret_cast<T *>(&(my_exemplar_ptr->value)); 00742 new(lref) T(*t_exemp); 00743 } else { 00744 new(lref) T(); 00745 } 00746 return lref; 00747 } 00748 00749 void unconstruct_locals() { 00750 for(typename internal_collection_type::iterator cvi = my_locals.begin(); cvi != my_locals.end(); ++cvi) { 00751 cvi->unconstruct(); 00752 } 00753 } 00754 00755 typedef typename Allocator::template rebind< uintptr_t >::other array_allocator_type; 00756 00757 // _size is in bytes 00758 /*override*/ void* create_array(size_t _size) { 00759 size_t nelements = (_size + sizeof(uintptr_t) -1) / sizeof(uintptr_t); 00760 return array_allocator_type().allocate(nelements); 00761 } 00762 00763 /*override*/ void free_array( void* _ptr, size_t _size) { 00764 size_t nelements = (_size + sizeof(uintptr_t) -1) / sizeof(uintptr_t); 00765 array_allocator_type().deallocate( reinterpret_cast<uintptr_t *>(_ptr),nelements); 00766 } 00767 00768 public: 00769 00771 typedef Allocator allocator_type; 00772 typedef T value_type; 00773 typedef T& reference; 00774 typedef const T& const_reference; 00775 typedef T* pointer; 00776 typedef const T* const_pointer; 00777 typedef typename internal_collection_type::size_type size_type; 00778 typedef typename internal_collection_type::difference_type difference_type; 00779 00780 // Iterator types 00781 typedef typename internal::enumerable_thread_specific_iterator< internal_collection_type, value_type > iterator; 00782 typedef typename internal::enumerable_thread_specific_iterator< internal_collection_type, const value_type > const_iterator; 00783 00784 // Parallel range types 00785 typedef generic_range_type< iterator > range_type; 00786 typedef generic_range_type< const_iterator > const_range_type; 00787 00789 enumerable_thread_specific() : my_finit_callback(0) { 00790 my_exemplar_ptr = 0; 00791 } 00792 00794 // Finit should be a function taking 0 parameters and returning a T 00795 template <typename Finit> 00796 enumerable_thread_specific( Finit _finit ) 00797 { 00798 my_finit_callback = internal::callback_leaf<T,Finit>::new_callback( _finit ); 00799 my_exemplar_ptr = 0; // don't need exemplar if function is provided 00800 } 00801 00803 enumerable_thread_specific(const T &_exemplar) : my_finit_callback(0) { 00804 my_exemplar_ptr = create_exemplar(_exemplar); 00805 } 00806 00808 ~enumerable_thread_specific() { 00809 if(my_finit_callback) { 00810 my_finit_callback->destroy(); 00811 } 00812 if(my_exemplar_ptr) { 00813 free_exemplar(my_exemplar_ptr); 00814 } 00815 this->clear(); // deallocation before the derived class is finished destructing 00816 // So free(array *) is still accessible 00817 } 00818 00820 reference local() { 00821 bool exists; 00822 return local(exists); 00823 } 00824 00826 reference local(bool& exists) { 00827 __TBB_ASSERT(ETS_key_type==ets_no_key,"ets_key_per_instance not yet implemented"); 00828 void* ptr = this->table_lookup(exists); 00829 return *(T*)ptr; 00830 } 00831 00833 size_type size() const { return my_locals.size(); } 00834 00836 bool empty() const { return my_locals.empty(); } 00837 00839 iterator begin() { return iterator( my_locals, 0 ); } 00841 iterator end() { return iterator(my_locals, my_locals.size() ); } 00842 00844 const_iterator begin() const { return const_iterator(my_locals, 0); } 00845 00847 const_iterator end() const { return const_iterator(my_locals, my_locals.size()); } 00848 00850 range_type range( size_t grainsize=1 ) { return range_type( begin(), end(), grainsize ); } 00851 00853 const_range_type range( size_t grainsize=1 ) const { return const_range_type( begin(), end(), grainsize ); } 00854 00856 void clear() { 00857 unconstruct_locals(); 00858 my_locals.clear(); 00859 this->table_clear(); 00860 // callback is not destroyed 00861 // exemplar is not destroyed 00862 } 00863 00864 private: 00865 00866 template<typename U, typename A2, ets_key_usage_type C2> 00867 void internal_copy( const enumerable_thread_specific<U, A2, C2>& other); 00868 00869 public: 00870 00871 template<typename U, typename Alloc, ets_key_usage_type Cachetype> 00872 enumerable_thread_specific( const enumerable_thread_specific<U, Alloc, Cachetype>& other ) : internal::ets_base<ETS_key_type> () 00873 { 00874 internal_copy(other); 00875 } 00876 00877 enumerable_thread_specific( const enumerable_thread_specific& other ) : internal::ets_base<ETS_key_type> () 00878 { 00879 internal_copy(other); 00880 } 00881 00882 private: 00883 00884 template<typename U, typename A2, ets_key_usage_type C2> 00885 enumerable_thread_specific & 00886 internal_assign(const enumerable_thread_specific<U, A2, C2>& other) { 00887 if(static_cast<void *>( this ) != static_cast<const void *>( &other )) { 00888 this->clear(); 00889 if(my_finit_callback) { 00890 my_finit_callback->destroy(); 00891 my_finit_callback = 0; 00892 } 00893 if(my_exemplar_ptr) { 00894 free_exemplar(my_exemplar_ptr); 00895 my_exemplar_ptr = 0; 00896 } 00897 internal_copy( other ); 00898 } 00899 return *this; 00900 } 00901 00902 public: 00903 00904 // assignment 00905 enumerable_thread_specific& operator=(const enumerable_thread_specific& other) { 00906 return internal_assign(other); 00907 } 00908 00909 template<typename U, typename Alloc, ets_key_usage_type Cachetype> 00910 enumerable_thread_specific& operator=(const enumerable_thread_specific<U, Alloc, Cachetype>& other) 00911 { 00912 return internal_assign(other); 00913 } 00914 00915 // combine_func_t has signature T(T,T) or T(const T&, const T&) 00916 template <typename combine_func_t> 00917 T combine(combine_func_t f_combine) { 00918 if(begin() == end()) { 00919 if(my_finit_callback) { 00920 return my_finit_callback->apply(); 00921 } 00922 pointer local_ref = reinterpret_cast<T*>((my_exemplar_ptr->value)); 00923 return T(*local_ref); 00924 } 00925 const_iterator ci = begin(); 00926 T my_result = *ci; 00927 while(++ci != end()) 00928 my_result = f_combine( my_result, *ci ); 00929 return my_result; 00930 } 00931 00932 // combine_func_t has signature void(T) or void(const T&) 00933 template <typename combine_func_t> 00934 void combine_each(combine_func_t f_combine) { 00935 for(const_iterator ci = begin(); ci != end(); ++ci) { 00936 f_combine( *ci ); 00937 } 00938 } 00939 00940 }; // enumerable_thread_specific 00941 00942 00943 template <typename T, typename Allocator, ets_key_usage_type ETS_key_type> 00944 template<typename U, typename A2, ets_key_usage_type C2> 00945 void enumerable_thread_specific<T,Allocator,ETS_key_type>::internal_copy( const enumerable_thread_specific<U, A2, C2>& other) { 00946 typedef internal::ets_base<ets_no_key> base; 00947 __TBB_ASSERT(my_locals.size()==0,NULL); 00948 this->table_reserve_for_copy( other ); 00949 for( base::array* r=other.my_root; r; r=r->next ) { 00950 for( size_t i=0; i<r->size(); ++i ) { 00951 base::slot& s1 = r->at(i); 00952 if( !s1.empty() ) { 00953 base::slot& s2 = this->table_find(s1.key); 00954 if( s2.empty() ) { 00955 #if TBB_DEPRECATED 00956 void* lref = &my_locals[my_locals.push_back(padded_element())]; 00957 #else 00958 void* lref = &*my_locals.push_back(padded_element()); 00959 #endif 00960 s2.ptr = new(lref) T(*(U*)s1.ptr); 00961 s2.key = s1.key; 00962 } else { 00963 // Skip the duplicate 00964 } 00965 } 00966 } 00967 } 00968 if(other.my_finit_callback) { 00969 my_finit_callback = other.my_finit_callback->make_copy(); 00970 } else { 00971 my_finit_callback = 0; 00972 } 00973 if(other.my_exemplar_ptr) { 00974 pointer local_ref = reinterpret_cast<U*>(other.my_exemplar_ptr->value); 00975 my_exemplar_ptr = create_exemplar(*local_ref); 00976 } else { 00977 my_exemplar_ptr = 0; 00978 } 00979 } 00980 00981 template< typename Container > 00982 class flattened2d { 00983 00984 // This intermediate typedef is to address issues with VC7.1 compilers 00985 typedef typename Container::value_type conval_type; 00986 00987 public: 00988 00990 typedef typename conval_type::size_type size_type; 00991 typedef typename conval_type::difference_type difference_type; 00992 typedef typename conval_type::allocator_type allocator_type; 00993 typedef typename conval_type::value_type value_type; 00994 typedef typename conval_type::reference reference; 00995 typedef typename conval_type::const_reference const_reference; 00996 typedef typename conval_type::pointer pointer; 00997 typedef typename conval_type::const_pointer const_pointer; 00998 00999 typedef typename internal::segmented_iterator<Container, value_type> iterator; 01000 typedef typename internal::segmented_iterator<Container, const value_type> const_iterator; 01001 01002 flattened2d( const Container &c, typename Container::const_iterator b, typename Container::const_iterator e ) : 01003 my_container(const_cast<Container*>(&c)), my_begin(b), my_end(e) { } 01004 01005 flattened2d( const Container &c ) : 01006 my_container(const_cast<Container*>(&c)), my_begin(c.begin()), my_end(c.end()) { } 01007 01008 iterator begin() { return iterator(*my_container) = my_begin; } 01009 iterator end() { return iterator(*my_container) = my_end; } 01010 const_iterator begin() const { return const_iterator(*my_container) = my_begin; } 01011 const_iterator end() const { return const_iterator(*my_container) = my_end; } 01012 01013 size_type size() const { 01014 size_type tot_size = 0; 01015 for(typename Container::const_iterator i = my_begin; i != my_end; ++i) { 01016 tot_size += i->size(); 01017 } 01018 return tot_size; 01019 } 01020 01021 private: 01022 01023 Container *my_container; 01024 typename Container::const_iterator my_begin; 01025 typename Container::const_iterator my_end; 01026 01027 }; 01028 01029 template <typename Container> 01030 flattened2d<Container> flatten2d(const Container &c, const typename Container::const_iterator b, const typename Container::const_iterator e) { 01031 return flattened2d<Container>(c, b, e); 01032 } 01033 01034 template <typename Container> 01035 flattened2d<Container> flatten2d(const Container &c) { 01036 return flattened2d<Container>(c); 01037 } 01038 01039 } // interface5 01040 01041 namespace internal { 01042 using interface5::internal::segmented_iterator; 01043 } 01044 01045 using interface5::enumerable_thread_specific; 01046 using interface5::flattened2d; 01047 using interface5::flatten2d; 01048 01049 } // namespace tbb 01050 01051 #endif
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.