- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

# enumerable_thread_specific.h

    00001 /*
    00002     Copyright 2005-2012 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 "tbb_allocator.h"
    00035 #include "cache_aligned_allocator.h"
    00036 #include "aligned_space.h"
    00037 #include <string.h>  // for memcpy
    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;  // _size in bytes
    00108             virtual void free_array(void* ptr, size_t _size) = 0; // _size in bytes
    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                 // Multiplicative hashing.  Client should use *upper* bits.
    00122                 // casts required for Mac gcc4.* compiler
    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();  // g++ complains if this is not virtual...
    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                             // Success at top level
    00181                             exists = true;
    00182                             return s.ptr;
    00183                         } else {
    00184                             // Success at some other level.  Need to insert at top level.
    00185                             exists = true;
    00186                             found = s.ptr;
    00187                             goto insert;
    00188                         }
    00189                     }
    00190                 }
    00191             }
    00192             // Key does not yet exist
    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                             // Another thread inserted an equal or  bigger array, so our array is superfluous.
    00208                             free(a);
    00209                             break;
    00210                         }
    00211                         r = new_r;
    00212                     }
    00213                 }
    00214             }
    00215         insert:
    00216             // Guaranteed to be room for it, and it is not present, so search for empty slot and grab it.
    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;  // _size in bytes
    00258             virtual void free_array(void* ptr, size_t _size) = 0; // size in bytes
    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             // Ensure that Microsoft's internal template function _Val_type works correctly.
    00284             : public std::iterator<std::random_access_iterator_tag,Value>
    00285 #endif /* defined(_WIN64) && defined(_MSC_VER) */
    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             // STL support
    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                 // STL support
    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                 // Copy Constructor
    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                     // can we assign a default-constructed iterator to inner if we're at the end?
    00485                     inner_iter(other.inner_iter)
    00486                 {}
    00487
    00488                 // assignment
    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                 // allow assignment of outer iterator to segmented iterator.  Once it is
    00500                 // assigned, move forward until a non-empty inner container is found or
    00501                 // the end of the outer container is reached.
    00502                 segmented_iterator& operator=(const outer_iterator& new_outer_iter) {
    00503                     __TBB_ASSERT(my_segcont != NULL, NULL);
    00504                     // check that this iterator points to something inside the segmented container
    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                 // pre-increment
    00515                 segmented_iterator& operator++() {
    00516                     advance_me();
    00517                     return *this;
    00518                 }
    00519
    00520                 // post-increment
    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                 // (i)* RHS
    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); // should never happen
    00543                     return *inner_iter;
    00544                 }
    00545
    00546                 // i->
    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); // not true if there are no inner containers
    00557                     __TBB_ASSERT(inner_iter != outer_iter->end(), NULL); // not true if the inner containers are all empty.
    00558                     ++inner_iter;
    00559                     while(inner_iter == outer_iter->end() && ++outer_iter != my_segcont->end()) {
    00560                         inner_iter = outer_iter->begin();
    00561                     }
    00562                 }
    00563         };    // segmented_iterator
    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();} // C++ note: the () in T() ensure zero initialization.
    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         // storage for initialization function pointer
    00609         template<typename T>
    00610         class callback_base {
    00611         public:
    00612             // Clone *this
    00613             virtual callback_base* clone() = 0;
    00614             // Destruct and free *this
    00615             virtual void destroy() = 0;
    00616             // Need virtual destructor to satisfy GCC compiler warning
    00617             virtual ~callback_base() { }
    00618             // Construct T at where
    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             /*override*/ callback_base<T>* clone() {
    00629                 void* where = my_allocator_type().allocate(1);
    00630                 return new(where) callback_leaf(*this);
    00631             }
    00632
    00633             /*override*/ void destroy() {
    00634                 my_allocator_type().destroy(this);
    00635                 my_allocator_type().deallocate(this,1);
    00636             }
    00637
    00638             /*override*/ 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     } // namespace internal
    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         /*override*/ 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         // _size is in bytes
    00736         /*override*/ 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         /*override*/ 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         // Iterator types
    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         // Parallel range types
    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(/*dummy argument*/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();  // deallocation before the derived class is finished destructing
    00786             // So free(array *) is still accessible
    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             // callback is not destroyed
    00830             // exemplar is not destroyed
    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         // assignment
    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         // combine_func_t has signature T(T,T) or T(const T&, const T&)
    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         // combine_func_t has signature void(T) or void(const T&)
    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     }; // enumerable_thread_specific
    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         // Initialize my_construct_callback first, so that it is valid even if rest of this routine throws an exception.
    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                         // Skip the duplicate
    00927                     }
    00928                 }
    00929             }
    00930         }
    00931     }
    00932
    00933     template< typename Container >
    00934     class flattened2d {
    00935
    00936         // This intermediate typedef is to address issues with VC7.1 compilers
    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 } // interface6
    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 } // namespace tbb
    01002
    01003 #endif

Copyright © 2005-2012 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.