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