Lunchbox  1.4.0
mtQueue.h
00001 
00002 /* Copyright (c) 2005-2012, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #ifndef LUNCHBOX_MTQUEUE_H
00019 #define LUNCHBOX_MTQUEUE_H
00020 
00021 #include <lunchbox/condition.h>
00022 #include <lunchbox/debug.h>
00023 
00024 #include <algorithm>
00025 #include <limits.h>
00026 #include <queue>
00027 #include <string.h>
00028 
00029 namespace lunchbox
00030 {
00040     template< typename T, size_t S = ULONG_MAX > class MTQueue
00041     // S = std::numeric_limits< size_t >::max() does not work:
00042     //   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=6424
00043     {
00044     public:
00046         MTQueue( size_t maxSize = S ) : _maxSize( maxSize ) {}
00047 
00049         MTQueue( const MTQueue< T, S >& from )  { *this = from; }
00050 
00052         ~MTQueue() {}
00053 
00055         MTQueue< T, S >& operator = ( const MTQueue< T, S >& from )
00056             {
00057                 if( this != &from )
00058                 {
00059                     from._cond.lock();
00060                     std::deque< T > copy = from._queue;
00061                     const size_t maxSize = from._maxSize;
00062                     from._cond.unlock();
00063 
00064                     _cond.lock();
00065                     _maxSize = maxSize;
00066                     _queue.swap( copy );
00067                     _cond.signal();
00068                     _cond.unlock();
00069                 }
00070                 return *this;
00071             }
00072 
00077         const T& operator[]( const size_t index ) const
00078             {
00079                 _cond.lock();
00080                 while( _queue.size() <= index )
00081                     _cond.wait();
00082 
00083                 LBASSERT( _queue.size() > index );
00084                 const T& element = _queue[index];
00085                 _cond.unlock();
00086                 return element;
00087             }
00088 
00090         bool isEmpty() const { return _queue.empty(); }
00091 
00093         size_t getSize() const { return _queue.size(); }
00094 
00103         void setMaxSize( const size_t maxSize )
00104             {
00105                 _cond.lock();
00106                 while( _queue.size() > maxSize )
00107                     _cond.wait();
00108                 _maxSize = maxSize;
00109                 _cond.signal();
00110                 _cond.unlock();
00111             }
00112 
00114         size_t getMaxSize() const { return _maxSize; }
00115 
00122         size_t waitSize( const size_t minSize ) const
00123             {
00124                 LBASSERT( minSize <= _maxSize );
00125                 _cond.lock();
00126                 while( _queue.size() < minSize )
00127                     _cond.wait();
00128                 const size_t size = _queue.size();
00129                 _cond.unlock();
00130                 return size;
00131             }
00132 
00134         void clear()
00135             {
00136                 _cond.lock();
00137                 _queue.clear();
00138                 _cond.signal();
00139                 _cond.unlock();
00140             }
00141 
00146         T pop()
00147             {
00148                 _cond.lock();
00149                 while( _queue.empty( ))
00150                     _cond.wait();
00151                 
00152                 LBASSERT( !_queue.empty( ));
00153                 T element = _queue.front();
00154                 _queue.pop_front();
00155                 _cond.signal();
00156                 _cond.unlock();
00157                 return element;
00158             }
00159 
00169         bool timedPop( const unsigned timeout, T& element )
00170             {
00171                 _cond.lock();
00172                 while( _queue.empty( ))
00173                 {
00174                     if( !_cond.timedWait( timeout ))
00175                     {
00176                         _cond.unlock();
00177                         return false;
00178                     }
00179                 }
00180                 LBASSERT( !_queue.empty( ));
00181                 element = _queue.front();
00182                 _queue.pop_front();
00183                 _cond.signal();
00184                 _cond.unlock();
00185                 return true;
00186             }
00187 
00196         bool tryPop( T& result )
00197             {
00198                 _cond.lock();
00199                 if( _queue.empty( ))
00200                 {
00201                     _cond.unlock();
00202                     return false;
00203                 }
00204 
00205                 result = _queue.front();
00206                 _queue.pop_front();
00207                 _cond.signal();
00208                 _cond.unlock();
00209                 return true;
00210             }   
00211 
00224         void tryPop( const size_t num, std::vector< T >& result )
00225             {
00226                 _cond.lock();
00227                 const size_t size = LB_MIN( num, _queue.size( ));
00228                 if( size > 0 )
00229                 {
00230                     result.reserve( result.size() + size );
00231                     for( size_t i = 0; i < size; ++i )
00232                     {
00233                         result.push_back( _queue.front( ));
00234                         _queue.pop_front();
00235                     }
00236                     _cond.signal();
00237                 }
00238                 _cond.unlock();
00239             }   
00240 
00247         bool getFront( T& result ) const
00248             {
00249                 _cond.lock();
00250                 if( _queue.empty( ))
00251                 {
00252                     _cond.unlock();
00253                     return false;
00254                 }
00255                 // else
00256                 result = _queue.front();
00257                 _cond.unlock();
00258                 return true;
00259             }
00260 
00267         bool getBack( T& result ) const
00268             {
00269                 _cond.lock();
00270                 if( _queue.empty( ))
00271                 {
00272                     _cond.unlock();
00273                     return false;
00274                 }
00275                 // else
00276                 result = _queue.back();
00277                 _cond.unlock();
00278                 return true;
00279             }
00280 
00282         void push( const T& element )
00283             {
00284                 _cond.lock();
00285                 while( _queue.size() >= _maxSize )
00286                     _cond.wait();
00287                 _queue.push_back( element );
00288                 _cond.signal();
00289                 _cond.unlock();
00290             }
00291 
00293         void push( const std::vector< T >& elements )
00294             {
00295                 _cond.lock();
00296                 LBASSERT( elements.size() <= _maxSize );
00297                 while( (_maxSize - _queue.size( )) < elements.size( ))
00298                     _cond.wait();
00299                 _queue.insert( _queue.end(), elements.begin(), elements.end( ));
00300                 _cond.signal();
00301                 _cond.unlock();
00302             }
00303 
00305         void pushFront( const T& element )
00306             {
00307                 _cond.lock();
00308                 while( _queue.size() >= _maxSize )
00309                     _cond.wait();
00310                 _queue.push_front( element );
00311                 _cond.signal();
00312                 _cond.unlock();
00313             }
00314 
00316         void pushFront( const std::vector< T >& elements )
00317             {
00318                 _cond.lock();
00319                 LBASSERT( elements.size() <= _maxSize );
00320                 while( (_maxSize - _queue.size( )) < elements.size( ))
00321                     _cond.wait();
00322                 _queue.insert(_queue.begin(), elements.begin(), elements.end());
00323                 _cond.signal();
00324                 _cond.unlock();
00325             }
00326 
00327 
00328     private:
00329         std::deque< T > _queue;
00330         mutable Condition _cond;
00331         size_t _maxSize;
00332     };
00333 }
00334 #endif //LUNCHBOX_MTQUEUE_H