TOBI SignalServer  0.1
/home/breidi/Dropbox/signalserver/include/misc/databuffer.h
Go to the documentation of this file.
00001 /*
00002     This file is part of the TOBI SignalServer.
00003 
00004     Commercial Usage
00005     Licensees holding valid Graz University of Technology Commercial
00006     licenses may use this file in accordance with the Graz University
00007     of Technology Commercial License Agreement provided with the
00008     Software or, alternatively, in accordance with the terms contained in
00009     a written agreement between you and Graz University of Technology.
00010 
00011     --------------------------------------------------
00012 
00013     GNU General Public License Usage
00014     Alternatively, this file may be used under the terms of the GNU
00015     General Public License version 3.0 as published by the Free Software
00016     Foundation and appearing in the file gpl.txt included in the
00017     packaging of this file.  Please review the following information to
00018     ensure the GNU General Public License version 3.0 requirements will be
00019     met: http://www.gnu.org/copyleft/gpl.html.
00020 
00021     In case of GNU General Public License Usage ,the TOBI SignalServer
00022     is distributed in the hope that it will be useful,
00023     but WITHOUT ANY WARRANTY; without even the implied warranty of
00024     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00025     GNU General Public License for more details.
00026 
00027     You should have received a copy of the GNU General Public License
00028     along with the TOBI SignalServer. If not, see <http://www.gnu.org/licenses/>.
00029 
00030     Copyright 2010 Graz University of Technology
00031     Contact: SignalServer@tobi-project.org
00032 */
00033 
00040 #ifndef DATABUFFER_H
00041 #define DATABUFFER_H
00042 
00043 #include <boost/circular_buffer.hpp>
00044 #include <boost/thread/mutex.hpp>
00045 #include <boost/thread/condition_variable.hpp>
00046 
00047 namespace tobiss
00048 {
00049 
00055 template<class T>
00056 class DataBuffer
00057 {
00058 public:
00059   typedef boost::circular_buffer<T> container_type;
00060   typedef typename container_type::size_type size_type;
00061   typedef typename container_type::value_type value_type;
00062   typedef typename boost::call_traits<value_type>::param_type param_type;
00063 
00064   class buffer_overrun : public std::runtime_error { public:  buffer_overrun( ):runtime_error("Attempted to insert into full DataBuffer."){ } };
00065   class buffer_underrun : public std::runtime_error { public:  buffer_underrun( ):runtime_error("Attempted to read from an empty DataBuffer."){ } };
00066 
00071   explicit DataBuffer( size_type capacity ) : unread_(0), container_(capacity) { }  
00072 
00078   void resize( size_type capacity )
00079   {
00080     boost::mutex::scoped_lock lock( mutex_ );
00081     container_.resize( capacity );
00082     lock.unlock( );
00083   }
00084 
00089   size_type getNumAvail(  )
00090   {
00091     boost::mutex::scoped_lock lock( mutex_ );
00092     assert( unread_ <= container_.size() );
00093     return unread_;
00094     // the mutex is unlocked by scoped_lock's destructor.
00095   }
00096 
00100   void blockWhileEmpty( )
00101   {
00102     boost::mutex::scoped_lock lock( mutex_ );
00103     cond_not_empty_.wait( lock, boost::bind( &DataBuffer<value_type>::is_not_empty, this ) );
00104     lock.unlock( );
00105   }
00106 
00110   void blockWhileFull( )
00111   {
00112     boost::mutex::scoped_lock lock( mutex_ );
00113     cond_not_full_.wait( lock, boost::bind( &DataBuffer<value_type>::is_not_full, this ) );
00114     lock.unlock( );
00115   }
00116 
00122   void insert_blocking( param_type item )
00123   {
00124     boost::mutex::scoped_lock lock( mutex_ );
00125     cond_not_full_.wait( lock, boost::bind( &DataBuffer<value_type>::is_not_full, this ) );
00126     container_.push_front( item );
00127     unread_++;
00128     lock.unlock( );
00129     cond_not_empty_.notify_one( );
00130   }
00131 
00137   void insert_throwing( param_type item )
00138   {
00139     boost::mutex::scoped_lock lock( mutex_ );
00140     if( is_not_full() )
00141     {
00142       container_.push_front( item );
00143       unread_++;
00144       lock.unlock( );
00145       cond_not_empty_.notify_one( );
00146     }
00147     else
00148     {
00149       lock.unlock( ); // This unlock() is redundant. The scoped_lock's destructor should take care of unlocking the mutex.
00150       throw buffer_overrun( );
00151     }
00152   }  
00153 
00159   void insert_overwriting( param_type item )
00160   {
00161     boost::mutex::scoped_lock lock( mutex_ );
00162     container_.push_front( item );
00163     if( is_not_full() )
00164       unread_++;
00165     lock.unlock( );
00166     cond_not_empty_.notify_one( );
00167   }
00168 
00174   void getNext_blocking( value_type *pItem )
00175   {
00176     boost::mutex::scoped_lock lock( mutex_ );
00177     cond_not_empty_.wait( lock, boost::bind( &DataBuffer<value_type>::is_not_empty, this ) );
00178     *pItem = container_[--unread_];
00179     lock.unlock( );
00180     cond_not_full_.notify_one( );
00181   }  
00182 
00188   void getNext_throwing( value_type *pItem )
00189   {
00190     boost::mutex::scoped_lock lock( mutex_ );
00191     if( is_not_empty() )
00192     {
00193       *pItem = container_[--unread_];
00194       lock.unlock( );
00195       cond_not_full_.notify_one( );
00196     }
00197     else
00198     {
00199       lock.unlock( ); // This unlock() is redundant. The scoped_lock's destructor should take care of unlocking the mutex.
00200       throw buffer_underrun( );
00201     }
00202   }
00203 
00209   void peekNext_blocking( value_type *pItem )
00210   {
00211     boost::mutex::scoped_lock lock( mutex_ );
00212     cond_not_empty_.wait( lock, boost::bind( &DataBuffer<value_type>::is_not_empty, this ) );
00213     *pItem = container_[unread_-1];
00214     lock.unlock( );
00215   }  
00216 
00222   void peekNext_throwing( value_type *pItem )
00223   {
00224     boost::mutex::scoped_lock lock( mutex_ );
00225     if( is_not_empty() )
00226     {
00227       *pItem = container_[unread_-1];
00228       lock.unlock( );
00229     }
00230     else
00231     {
00232       lock.unlock( ); // This unlock() is redundant. The scoped_lock's destructor should take care of unlocking the mutex.
00233       throw buffer_underrun( );
00234     }
00235   }
00236 
00242   bool dropOldest()
00243   {
00244     boost::mutex::scoped_lock lock( mutex_ );
00245     if( is_not_empty() )
00246     {
00247       unread_--;
00248       lock.unlock( );
00249       cond_not_full_.notify_one( );
00250       return true;
00251     }
00252     lock.unlock( );
00253     return false;
00254   }
00255 
00261   void clearAll()
00262   {
00263     boost::mutex::scoped_lock lock( mutex_ );
00264     unread_ = 0;
00265     lock.unlock( );
00266     cond_not_full_.notify_one( );
00267   }
00268 
00269 private:
00270   DataBuffer( const DataBuffer& );            // No Copy Constructor!
00271   DataBuffer &operator=( const DataBuffer& ); // No Assignment Operator!
00272 
00273   bool is_not_empty( ) const { return unread_ > 0; }
00274   bool is_not_full( ) const { return unread_ < container_.capacity( ); }
00275 
00276   size_type unread_;
00277   container_type container_;
00278 
00279   boost::mutex mutex_;
00280   boost::condition_variable cond_not_empty_;
00281   boost::condition_variable cond_not_full_;
00282 };
00283 
00284 }
00285 
00286 #endif
 All Data Structures Files Functions Variables