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

Generated for GearBox by  doxygen 1.4.5