00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 #ifndef __TBB_concurrent_queue_H
00022 #define __TBB_concurrent_queue_H
00023 
00024 #include "_concurrent_queue_internal.h"
00025 
00026 namespace tbb {
00027 
00028 namespace strict_ppl {
00029 
00031 
00034 template<typename T, typename A = cache_aligned_allocator<T> > 
00035 class concurrent_queue: public internal::concurrent_queue_base_v3<T> {
00036     template<typename Container, typename Value> friend class internal::concurrent_queue_iterator;
00037 
00039     typedef typename A::template rebind<char>::other page_allocator_type;
00040     page_allocator_type my_allocator;
00041 
00043      virtual void *allocate_block( size_t n ) {
00044         void *b = reinterpret_cast<void*>(my_allocator.allocate( n ));
00045         if( !b )
00046             internal::throw_exception(internal::eid_bad_alloc); 
00047         return b;
00048     }
00049 
00051      virtual void deallocate_block( void *b, size_t n ) {
00052         my_allocator.deallocate( reinterpret_cast<char*>(b), n );
00053     }
00054 
00055 public:
00057     typedef T value_type;
00058 
00060     typedef T& reference;
00061 
00063     typedef const T& const_reference;
00064 
00066     typedef size_t size_type;
00067 
00069     typedef ptrdiff_t difference_type;
00070 
00072     typedef A allocator_type;
00073 
00075     explicit concurrent_queue(const allocator_type& a = allocator_type()) : 
00076         internal::concurrent_queue_base_v3<T>( sizeof(T) ), my_allocator( a )
00077     {
00078     }
00079 
00081     template<typename InputIterator>
00082     concurrent_queue( InputIterator begin, InputIterator end, const allocator_type& a = allocator_type()) :
00083         internal::concurrent_queue_base_v3<T>( sizeof(T) ), my_allocator( a )
00084     {
00085         for( ; begin != end; ++begin )
00086             internal_push(&*begin);
00087     }
00088     
00090     concurrent_queue( const concurrent_queue& src, const allocator_type& a = allocator_type()) : 
00091         internal::concurrent_queue_base_v3<T>( sizeof(T) ), my_allocator( a )
00092     {
00093         assign( src );
00094     }
00095     
00097     ~concurrent_queue();
00098 
00100     void push( const T& source ) {
00101         internal_push( &source );
00102     }
00103 
00105 
00107     bool try_pop( T& result ) {
00108         return internal_try_pop( &result );
00109     }
00110 
00112     size_type unsafe_size() const {return this->internal_size();}
00113 
00115     bool empty() const {return this->internal_empty();}
00116 
00118     void clear() ;
00119 
00121     allocator_type get_allocator() const { return this->my_allocator; }
00122 
00123     typedef internal::concurrent_queue_iterator<concurrent_queue,T> iterator;
00124     typedef internal::concurrent_queue_iterator<concurrent_queue,const T> const_iterator;
00125 
00126     
00127     
00128     
00129     iterator unsafe_begin() {return iterator(*this);}
00130     iterator unsafe_end() {return iterator();}
00131     const_iterator unsafe_begin() const {return const_iterator(*this);}
00132     const_iterator unsafe_end() const {return const_iterator();}
00133 } ;
00134 
00135 template<typename T, class A>
00136 concurrent_queue<T,A>::~concurrent_queue() {
00137     clear();
00138     this->internal_finish_clear();
00139 }
00140 
00141 template<typename T, class A>
00142 void concurrent_queue<T,A>::clear() {
00143     while( !empty() ) {
00144         T value;
00145         internal_try_pop(&value);
00146     }
00147 }
00148 
00149 } 
00150     
00152 
00157 template<typename T, class A = cache_aligned_allocator<T> >
00158 class concurrent_bounded_queue: public internal::concurrent_queue_base_v3 {
00159     template<typename Container, typename Value> friend class internal::concurrent_queue_iterator;
00160 
00162     typedef typename A::template rebind<char>::other page_allocator_type;
00163     page_allocator_type my_allocator;
00164 
00166     class destroyer: internal::no_copy {
00167         T& my_value;
00168     public:
00169         destroyer( T& value ) : my_value(value) {}
00170         ~destroyer() {my_value.~T();}          
00171     };
00172 
00173     T& get_ref( page& page, size_t index ) {
00174         __TBB_ASSERT( index<items_per_page, NULL );
00175         return static_cast<T*>(static_cast<void*>(&page+1))[index];
00176     }
00177 
00178      virtual void copy_item( page& dst, size_t index, const void* src ) {
00179         new( &get_ref(dst,index) ) T(*static_cast<const T*>(src)); 
00180     }
00181 
00182      virtual void copy_page_item( page& dst, size_t dindex, const page& src, size_t sindex ) {
00183         new( &get_ref(dst,dindex) ) T( static_cast<const T*>(static_cast<const void*>(&src+1))[sindex] );
00184     }
00185 
00186      virtual void assign_and_destroy_item( void* dst, page& src, size_t index ) {
00187         T& from = get_ref(src,index);
00188         destroyer d(from);
00189         *static_cast<T*>(dst) = from;
00190     }
00191 
00192      virtual page *allocate_page() {
00193         size_t n = sizeof(page) + items_per_page*item_size;
00194         page *p = reinterpret_cast<page*>(my_allocator.allocate( n ));
00195         if( !p )
00196             internal::throw_exception(internal::eid_bad_alloc); 
00197         return p;
00198     }
00199 
00200      virtual void deallocate_page( page *p ) {
00201         size_t n = sizeof(page) + items_per_page*item_size;
00202         my_allocator.deallocate( reinterpret_cast<char*>(p), n );
00203     }
00204 
00205 public:
00207     typedef T value_type;
00208 
00210     typedef A allocator_type;
00211 
00213     typedef T& reference;
00214 
00216     typedef const T& const_reference;
00217 
00219 
00221     typedef std::ptrdiff_t size_type;
00222 
00224     typedef std::ptrdiff_t difference_type;
00225 
00227     explicit concurrent_bounded_queue(const allocator_type& a = allocator_type()) : 
00228         concurrent_queue_base_v3( sizeof(T) ), my_allocator( a )
00229     {
00230     }
00231 
00233     concurrent_bounded_queue( const concurrent_bounded_queue& src, const allocator_type& a = allocator_type()) : 
00234         concurrent_queue_base_v3( sizeof(T) ), my_allocator( a )
00235     {
00236         assign( src );
00237     }
00238 
00240     template<typename InputIterator>
00241     concurrent_bounded_queue( InputIterator begin, InputIterator end, const allocator_type& a = allocator_type()) :
00242         concurrent_queue_base_v3( sizeof(T) ), my_allocator( a )
00243     {
00244         for( ; begin != end; ++begin )
00245             internal_push_if_not_full(&*begin);
00246     }
00247 
00249     ~concurrent_bounded_queue();
00250 
00252     void push( const T& source ) {
00253         internal_push( &source );
00254     }
00255 
00257 
00258     void pop( T& destination ) {
00259         internal_pop( &destination );
00260     }
00261 
00263 
00265     bool try_push( const T& source ) {
00266         return internal_push_if_not_full( &source );
00267     }
00268 
00270 
00272     bool try_pop( T& destination ) {
00273         return internal_pop_if_present( &destination );
00274     }
00275 
00277 
00280     size_type size() const {return internal_size();}
00281 
00283     bool empty() const {return internal_empty();}
00284 
00286     size_type capacity() const {
00287         return my_capacity;
00288     }
00289 
00291 
00293     void set_capacity( size_type capacity ) {
00294         internal_set_capacity( capacity, sizeof(T) );
00295     }
00296 
00298     allocator_type get_allocator() const { return this->my_allocator; }
00299 
00301     void clear() ;
00302 
00303     typedef internal::concurrent_queue_iterator<concurrent_bounded_queue,T> iterator;
00304     typedef internal::concurrent_queue_iterator<concurrent_bounded_queue,const T> const_iterator;
00305 
00306     
00307     
00308     
00309     iterator unsafe_begin() {return iterator(*this);}
00310     iterator unsafe_end() {return iterator();}
00311     const_iterator unsafe_begin() const {return const_iterator(*this);}
00312     const_iterator unsafe_end() const {return const_iterator();}
00313 
00314 }; 
00315 
00316 template<typename T, class A>
00317 concurrent_bounded_queue<T,A>::~concurrent_bounded_queue() {
00318     clear();
00319     internal_finish_clear();
00320 }
00321 
00322 template<typename T, class A>
00323 void concurrent_bounded_queue<T,A>::clear() {
00324     while( !empty() ) {
00325         T value;
00326         internal_pop_if_present(&value);
00327     }
00328 }
00329 
00330 namespace deprecated {
00331 
00333 
00338 template<typename T, class A = cache_aligned_allocator<T> > 
00339 class concurrent_queue: public concurrent_bounded_queue<T,A> {
00340 #if !__TBB_TEMPLATE_FRIENDS_BROKEN
00341     template<typename Container, typename Value> friend class internal::concurrent_queue_iterator;
00342 #endif 
00343 
00344 public:
00346     explicit concurrent_queue(const A& a = A()) : 
00347         concurrent_bounded_queue<T,A>( a )
00348     {
00349     }
00350 
00352     concurrent_queue( const concurrent_queue& src, const A& a = A()) : 
00353         concurrent_bounded_queue<T,A>( src, a )
00354     {
00355     }
00356 
00358     template<typename InputIterator>
00359     concurrent_queue( InputIterator begin, InputIterator end, const A& a = A()) :
00360         concurrent_bounded_queue<T,A>( begin, end, a )
00361     {
00362     }
00363 
00365 
00367     bool push_if_not_full( const T& source ) {
00368         return try_push( source );
00369     }
00370 
00372 
00376     bool pop_if_present( T& destination ) {
00377         return try_pop( destination );
00378     }
00379 
00380     typedef typename concurrent_bounded_queue<T,A>::iterator iterator;
00381     typedef typename concurrent_bounded_queue<T,A>::const_iterator const_iterator;
00382     
00383     
00384     
00385     
00386     iterator begin() {return this->unsafe_begin();}
00387     iterator end() {return this->unsafe_end();}
00388     const_iterator begin() const {return this->unsafe_begin();}
00389     const_iterator end() const {return this->unsafe_end();}
00390 }; 
00391 
00392 }
00393     
00394 
00395 #if TBB_DEPRECATED
00396 using deprecated::concurrent_queue;
00397 #else
00398 using strict_ppl::concurrent_queue;    
00399 #endif
00400 
00401 } 
00402 
00403 #endif