Shadowrun: Awakened 29 September 2011 - Build 871
enumerable_thread_specific.h
Go to the documentation of this file.
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.

GNU Lesser General Public License 3 Sourceforge.net