Lunchbox
1.4.0
|
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