INTRODUCTION
Overview
Download and Install
Documentation
Publications

REPOSITORY
Libraries

DEVELOPER
Dev Guide
Dashboard

PEOPLE
Contributors
Users

SourceForge.net Logo
Project
Download
Mailing lists

 

         

buffer.h

00001 /*
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
 

Generated for GearBox by  doxygen 1.4.5