TOBI SignalServer
0.1
|
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