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-2010 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 <gbxutilacfr/exceptions.h> 00016 00017 #include <IceUtil/Monitor.h> 00018 #include <IceUtil/Mutex.h> 00019 #include <IceUtil/Time.h> 00020 00021 namespace gbxiceutilacfr { 00022 00024 enum BufferType 00025 { 00028 BufferTypeCircular, 00031 BufferTypeQueue 00032 }; 00033 00044 template<class Type> 00045 class Buffer : public IceUtil::Monitor<IceUtil::Mutex> 00046 { 00047 public: 00048 00055 Buffer( int depth = -1, BufferType type = BufferTypeQueue ); 00056 00057 virtual ~Buffer(); 00058 00063 void configure( int depth, BufferType type=BufferTypeCircular ); 00064 00066 int depth() const; 00067 00069 BufferType type() const; 00070 00072 bool isEmpty() const; 00073 00075 int size() const; 00076 00078 void purge(); 00079 00086 void push( const Type & obj ); 00087 00092 void pop(); 00093 00100 void get( Type & obj ) const; 00101 00106 void get( Type & obj, unsigned int n ) const; 00107 00111 void getAndPop( Type & obj ); 00112 00124 int getWithTimeout( Type & obj, int timeoutMs=-1 ); 00125 00129 int getAndPopWithTimeout( Type & obj, int timeoutMs=-1 ); 00130 00131 protected: 00132 00133 // The buffer itself 00134 std::deque<Type> queue_; 00135 00136 // Reimplement this function for non-standard types. 00137 virtual void internalGet( Type & obj ) const ; 00138 00139 // Reimplement this function for non-standard types. 00140 virtual void internalGet( Type & obj, unsigned int n ) const ; 00141 00142 // Reimplement this function for non-standard types. 00143 virtual void internalPush( const Type & obj ); 00144 00145 private: 00146 00147 // buffer depth: 00148 // positive numbers to specify finite depth, 00149 // negative numbers for infinite depth (memory size), 00150 // zero is undefined 00151 int depth_; 00152 00153 // buffer type (see type definitions in BufferType enum) 00154 BufferType type_; 00155 00156 // internal implementation of getWithTimeout( obj, -1 ); 00157 void getWithInfiniteWait( Type & obj ); 00158 }; 00159 00160 00162 00163 00164 template<class Type> 00165 Buffer<Type>::Buffer( int depth, BufferType type ) 00166 : depth_(depth), 00167 type_(type) 00168 { 00169 purge(); 00170 } 00171 00172 template<class Type> 00173 Buffer<Type>::~Buffer() 00174 { 00175 } 00176 00177 template<class Type> 00178 void Buffer<Type>::configure( int depth, BufferType type ) 00179 { 00180 // all data is lost! 00181 purge(); 00182 00183 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00184 depth_ = depth; 00185 type_ = type; 00186 } 00187 00188 template<class Type> 00189 int 00190 Buffer<Type>::depth() const 00191 { 00192 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00193 return depth_; 00194 } 00195 00196 template<class Type> 00197 BufferType 00198 Buffer<Type>::type() const 00199 { 00200 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00201 return type_; 00202 } 00203 00204 template<class Type> 00205 void Buffer<Type>::purge() 00206 { 00207 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00208 queue_.resize(0); 00209 } 00210 00211 template<class Type> 00212 bool Buffer<Type>::isEmpty() const 00213 { 00214 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00215 return queue_.empty(); 00216 } 00217 00218 template<class Type> 00219 int Buffer<Type>::size() const 00220 { 00221 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00222 return queue_.size(); 00223 } 00224 00225 template<class Type> 00226 void Buffer<Type>::pop() 00227 { 00228 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00229 if ( queue_.empty() ) { 00230 return; 00231 } 00232 // must check for empty queue above, otherwise get seg fault! 00233 queue_.pop_front(); 00234 } 00235 00236 template<class Type> 00237 void Buffer<Type>::get( Type &obj ) const 00238 { 00239 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00240 if ( !queue_.empty() ) 00241 { 00242 internalGet( obj ); 00243 } 00244 else 00245 { 00246 throw gbxutilacfr::Exception( ERROR_INFO, "trying to read from an empty buffer." ); 00247 } 00248 } 00249 00250 template<class Type> 00251 void Buffer<Type>::get( Type &obj, unsigned int n ) const 00252 { 00253 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00254 if ( queue_.empty() ){ 00255 throw gbxutilacfr::Exception( ERROR_INFO, "trying to read from an empty buffer." ); 00256 } 00257 else if( n >= queue_.size()){ 00258 throw gbxutilacfr::Exception( ERROR_INFO, "index out of bounds while trying to read buffer." ); 00259 } 00260 else{ 00261 internalGet( obj ,n ); 00262 } 00263 } 00264 00265 template<class Type> 00266 void Buffer<Type>::getAndPop( Type &obj ) 00267 { 00268 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00269 if ( !queue_.empty() ) 00270 { 00271 internalGet( obj ); 00272 } 00273 else 00274 { 00275 throw gbxutilacfr::Exception( ERROR_INFO, "trying to read from an empty buffer." ); 00276 } 00277 queue_.pop_front(); 00278 } 00279 00280 template<class Type> 00281 int Buffer<Type>::getWithTimeout( Type &obj, int timeoutMs ) 00282 { 00283 // special case: infinite wait time 00284 if ( timeoutMs == -1 ) 00285 { 00286 getWithInfiniteWait( obj ); 00287 return 0; 00288 } 00289 00290 // finite wait time 00291 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00292 00293 // if already have data in the buffer, return it and get out 00294 if ( !queue_.empty() ) 00295 { 00296 internalGet( obj ); 00297 return 0; 00298 } 00299 00300 // empty buffer: figure out when to wake up 00301 // notice that we are still holding the lock, so it's ok to call timedWait() 00302 if ( this->timedWait( IceUtil::Time::milliSeconds( timeoutMs ) ) ) 00303 { 00304 // someone woke us up, we are holding the lock again 00305 // check new data again (could be a spurious wakeup) 00306 if ( !queue_.empty() ) 00307 { 00308 internalGet( obj ); 00309 return 0; 00310 } 00311 else { 00312 // spurious wakup, don't wait again, just return 00313 return 1; 00314 } 00315 } 00316 else { 00317 // wait timedout, nobody woke us up 00318 return -1; 00319 } 00320 } 00321 00322 template<class Type> 00323 int Buffer<Type>::getAndPopWithTimeout( Type &obj, int timeoutMs ) 00324 { 00325 int ret = getWithTimeout( obj, timeoutMs ); 00326 if ( ret==0 ) { 00327 pop(); 00328 } 00329 return ret; 00330 } 00331 00332 // internal utility function (waits for update infinitely) 00333 template<class Type> 00334 void Buffer<Type>::getWithInfiniteWait( Type &obj ) 00335 { 00336 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00337 00338 // check the condition before and after waiting to deal with spurious wakeups 00339 // (see Ice manual sec. 28.9.2) 00340 while ( queue_.empty() ) 00341 { 00342 this->wait(); 00343 } 00344 00345 internalGet( obj ); 00346 } 00347 00348 // NOTE: see notes on efficient notification in Ice sec. 28.9.3 00349 template<class Type> 00350 void Buffer<Type>::push( const Type & obj ) 00351 { 00352 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00353 00354 // buffer is not full, or buffer is configured to be of infinite size (at least for STL) 00355 if ( (int)queue_.size() < depth_ || depth_<0 ) 00356 { 00357 internalPush( obj ); 00358 } 00359 else if ( type_ == BufferTypeCircular ) 00360 { 00361 // pop the oldest entry 00362 queue_.pop_front(); 00363 // push the new enty 00364 internalPush( obj ); 00365 } 00366 else // we have a full, non-circular buffer 00367 { 00368 // do nothing, the new object is lost 00369 } 00370 00371 // wakeup someone who's waiting for an update 00372 this->notify(); 00373 } 00374 00375 template<class Type> 00376 void Buffer<Type>::internalGet( Type & obj ) const 00377 { 00378 obj = queue_.front(); 00379 } 00380 00381 template<class Type> 00382 void Buffer<Type>::internalGet( Type & obj, unsigned int n ) const 00383 { 00384 obj = queue_[n]; 00385 } 00386 00387 template<class Type> 00388 void Buffer<Type>::internalPush( const Type & obj ) 00389 { 00390 queue_.push_back( obj ); 00391 } 00392 00393 } // end namespace 00394 00395 #endif |