INTRODUCTION Overview Download and Install Documentation Publications REPOSITORY Libraries DEVELOPER Dev Guide Dashboard PEOPLE Contributors Users Project Download Mailing lists
|
buffer.h00001 /* 00002 * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics 00003 * http://gearbox.sf.net/ 00004 * Copyright (c) 2004-2008 Alex Brooks, Alexei Makarenko, Tobias Kaupp 00005 * 00006 * This distribution is licensed to you under the terms described in 00007 * the LICENSE file included in this distribution. 00008 * 00009 */ 00010 00011 #ifndef GBXICEUTILACFR_BUFFER_H 00012 #define GBXICEUTILACFR_BUFFER_H 00013 00014 #include <queue> 00015 #include <gbxsickacfr/gbxutilacfr/exceptions.h> 00016 00017 #include <IceUtil/Monitor.h> 00018 #include <IceUtil/Mutex.h> 00019 #include <IceUtil/Time.h> 00020 00021 namespace gbxsickacfr { 00022 namespace gbxiceutilacfr { 00023 00025 enum BufferType 00026 { 00029 BufferTypeCircular, 00032 BufferTypeQueue 00033 }; 00034 00063 template<class Type> 00064 class Buffer : public IceUtil::Monitor<IceUtil::Mutex> 00065 { 00066 public: 00067 00074 Buffer( int depth, BufferType type ); 00075 00076 virtual ~Buffer(); 00077 00082 void configure( int depth, BufferType type=BufferTypeCircular ); 00083 00085 int depth() const; 00086 00088 BufferType type() const; 00089 00091 bool isEmpty() const; 00092 00094 int size() const; 00095 00097 void purge(); 00098 00105 void push( const Type & obj ); 00106 00111 void pop(); 00112 00119 void get( Type & obj ) const; 00120 00125 void get( Type & obj, unsigned int n ) const; 00126 00130 void getAndPop( Type & obj ); 00131 00143 int getNext( Type & obj, int timeoutMs=-1 ); 00144 00148 int getAndPopNext( Type & obj, int timeoutMs=-1 ); 00149 00150 protected: 00151 00152 // The buffer itself 00153 std::deque<Type> queue_; 00154 00155 // Reimplement this function for non-standard types. 00156 virtual void internalGet( Type & obj ) const ; 00157 00158 // Reimplement this function for non-standard types. 00159 virtual void internalGet( Type & obj, unsigned int n ) const ; 00160 00161 // Reimplement this function for non-standard types. 00162 virtual void internalPush( const Type & obj ); 00163 00164 private: 00165 00166 // buffer depth: 00167 // positive numbers to specify finite depth, 00168 // negative numbers for infinite depth (memory size), 00169 // zero is undefined 00170 int depth_; 00171 00172 // buffer type (see type definitions in BufferType enum) 00173 BufferType type_; 00174 00175 // internal implementation of front( obj, -1 ); returns 0. 00176 int getNextNoWait( Type & obj ); 00177 }; 00178 00179 00181 00182 00183 template<class Type> 00184 Buffer<Type>::Buffer( int depth, BufferType type ) 00185 : depth_(depth), 00186 type_(type) 00187 { 00188 purge(); 00189 } 00190 00191 template<class Type> 00192 Buffer<Type>::~Buffer() 00193 { 00194 } 00195 00196 template<class Type> 00197 void Buffer<Type>::configure( int depth, BufferType type ) 00198 { 00199 // all data is lost! 00200 purge(); 00201 00202 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00203 depth_ = depth; 00204 type_ = type; 00205 } 00206 00207 template<class Type> 00208 int 00209 Buffer<Type>::depth() const 00210 { 00211 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00212 return depth_; 00213 } 00214 00215 template<class Type> 00216 BufferType 00217 Buffer<Type>::type() const 00218 { 00219 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00220 return type_; 00221 } 00222 00223 template<class Type> 00224 void Buffer<Type>::purge() 00225 { 00226 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00227 queue_.resize(0); 00228 } 00229 00230 template<class Type> 00231 bool Buffer<Type>::isEmpty() const 00232 { 00233 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00234 return queue_.empty(); 00235 } 00236 00237 template<class Type> 00238 int Buffer<Type>::size() const 00239 { 00240 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00241 return queue_.size(); 00242 } 00243 00244 template<class Type> 00245 void Buffer<Type>::pop() 00246 { 00247 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00248 if ( queue_.empty() ) { 00249 return; 00250 } 00251 // must check for empty queue above, otherwise get seg fault! 00252 queue_.pop_front(); 00253 } 00254 00255 template<class Type> 00256 void Buffer<Type>::get( Type &obj ) const 00257 { 00258 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00259 if ( !queue_.empty() ) 00260 { 00261 internalGet( obj ); 00262 } 00263 else 00264 { 00265 throw gbxutilacfr::Exception( ERROR_INFO, "trying to read from an empty buffer." ); 00266 } 00267 } 00268 00269 template<class Type> 00270 void Buffer<Type>::get( Type &obj, unsigned int n ) const 00271 { 00272 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00273 if ( queue_.empty() ){ 00274 throw gbxutilacfr::Exception( ERROR_INFO, "trying to read from an empty buffer." ); 00275 } 00276 else if( n >= queue_.size()){ 00277 throw gbxutilacfr::Exception( ERROR_INFO, "index out of bounds while trying to read buffer." ); 00278 } 00279 else{ 00280 internalGet( obj ,n ); 00281 } 00282 } 00283 00284 template<class Type> 00285 void Buffer<Type>::getAndPop( Type &obj ) 00286 { 00287 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00288 if ( !queue_.empty() ) 00289 { 00290 internalGet( obj ); 00291 } 00292 else 00293 { 00294 throw gbxutilacfr::Exception( ERROR_INFO, "trying to read from an empty buffer." ); 00295 } 00296 queue_.pop_front(); 00297 } 00298 00299 template<class Type> 00300 int Buffer<Type>::getNext( Type &obj, int timeoutMs ) 00301 { 00302 // special case: infinite wait time 00303 if ( timeoutMs == -1 ) 00304 { 00305 return getNextNoWait( obj ); 00306 } 00307 00308 // finite wait time 00309 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00310 00311 // if already have data in the buffer, return it and get out 00312 if ( !queue_.empty() ) 00313 { 00314 internalGet( obj ); 00315 return 0; 00316 } 00317 00318 // empty buffer: figure out when to wake up 00319 // notice that we are still holding the lock, so it's ok to call timedWait() 00320 if ( this->timedWait( IceUtil::Time::milliSeconds( timeoutMs ) ) ) 00321 { 00322 // someone woke us up, we are holding the lock again 00323 // check new data again (could be a spurious wakeup) 00324 if ( !queue_.empty() ) 00325 { 00326 internalGet( obj ); 00327 return 0; 00328 } 00329 else { 00330 // spurious wakup, don't wait again, just return 00331 return 1; 00332 } 00333 } 00334 else { 00335 // wait timedout, nobody woke us up 00336 return -1; 00337 } 00338 } 00339 00340 template<class Type> 00341 int Buffer<Type>::getAndPopNext( Type &obj, int timeoutMs ) 00342 { 00343 int ret = getNext( obj, timeoutMs ); 00344 if ( ret==0 ) { 00345 pop(); 00346 } 00347 return ret; 00348 } 00349 00350 // internal utility function (waits for update infinitely) 00351 template<class Type> 00352 int Buffer<Type>::getNextNoWait( Type &obj ) 00353 { 00354 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00355 00356 // check the condition before and after waiting to deal with spurious wakeups 00357 // (see Ice manual sec. 28.9.2) 00358 while ( queue_.empty() ) 00359 { 00360 this->wait(); 00361 } 00362 00363 internalGet( obj ); 00364 return 0; 00365 } 00366 00367 // NOTE: see notes on efficient notification in Ice sec. 28.9.3 00368 template<class Type> 00369 void Buffer<Type>::push( const Type & obj ) 00370 { 00371 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00372 00373 // buffer is not full, or buffer is configured to be of infinite size (at least for STL) 00374 if ( (int)queue_.size() < depth_ || depth_<0 ) 00375 { 00376 internalPush( obj ); 00377 } 00378 else if ( type_ == BufferTypeCircular ) 00379 { 00380 // pop the oldest entry 00381 queue_.pop_front(); 00382 // push the new enty 00383 internalPush( obj ); 00384 } 00385 else // we have a full, non-circular buffer 00386 { 00387 // do nothing, the new object is lost 00388 } 00389 00390 // wakeup someone who's waiting for an update 00391 this->notify(); 00392 } 00393 00394 template<class Type> 00395 void Buffer<Type>::internalGet( Type & obj ) const 00396 { 00397 obj = queue_.front(); 00398 } 00399 00400 template<class Type> 00401 void Buffer<Type>::internalGet( Type & obj, unsigned int n ) const 00402 { 00403 obj = queue_[n]; 00404 } 00405 00406 template<class Type> 00407 void Buffer<Type>::internalPush( const Type & obj ) 00408 { 00409 queue_.push_back( obj ); 00410 } 00411 00412 } 00413 } // end namespace 00414 00415 #endif |