JASPL  0.2
Just Another Signal Processing Library
ouroboros.h
1 #ifndef OUROBOROS_H
2 #define OUROBOROS_H
3 
4 // C System-Headers
5 //
6 // C++ System headers
7 #include <mutex>
8 #include <vector>
9 // Boost Headers
10 #include <boost/thread/condition.hpp>
11 #include <boost/thread/mutex.hpp>
12 #include <boost/thread/thread.hpp>
13 #include <boost/circular_buffer.hpp>
14 #include <boost/lexical_cast.hpp>
15 // Project Specific Headers
16 #include "../Debug/debug.h"
17 #include "../jTypeTraits/jtypetraits.h"
18 
19 namespace jaspl {
20 
21 template < typename T >
22 class ouroborus {
23 
24  public:
25  ouroborus();
26  ouroborus( uint buffer_size );
27 
28  template < typename F >
29  friend std::ostream& operator<< (std::ostream& stream, ouroborus<F>& buffer);
30 
31  void HeadInsert( T* to_insert, uint insert_size );
32  void TailInsert( T* to_insert, uint insert_size );
33 
34  std::vector<T> HeadRead( uint read_size );
35  template < typename F >
36  std::vector< F > HeadReadAndConvert( uint read_size );
37  bool CheckHead( uint read_size );
38 
39  std::vector<T> TailRead( uint read_size );
40  template < typename F >
41  std::vector< F > TailReadAndConvert( uint read_size );
42  bool CheckTail( uint read_size );
43 
44  void Reset();
45 
46  uint capacity();
47  uint size();
48 
49  bool overrun();
50 
51  private:
52 
53  void update_counter( int update_value );
54 
55  boost::circular_buffer<T> internal_buffer;
56  boost::shared_mutex monitor;
57 
58  bool overrun_flag = false;
59 
60 };
61 
62 template < typename T >
64  //
65 }
66 
67 template < typename T>
68 ouroborus<T>::ouroborus( uint buffer_size ) : internal_buffer( buffer_size ) {
69  DEBUG_PRINT( "Built new ring_buffer of size " << buffer_size );
70 }
71 
72 template < typename T >
73 std::ostream& operator << (std::ostream& stream, ouroborus<T>& buffer) {
74 
75  stream << "Maximum buffer size: " << buffer.internal_buffer.capacity() << std::endl;
76  stream << "Number of elements in buffer: " << buffer.internal_buffer.size() << std::endl;
77  stream << "Front of buffer: " << buffer.internal_buffer.front() << std::endl;
78  stream << "Back of buffer: " << buffer.internal_buffer.back() << std::endl;
79  stream << "Buffer contents: " << std::endl;
80 
81  for( const auto& elem : buffer.internal_buffer ) {
82  stream << elem << ",";
83  }
84 
85  stream << std::endl;
86 
87  return stream;
88 }
89 
90 template < typename T >
91 bool ouroborus<T>::overrun() {
92  boost::shared_lock<boost::shared_mutex> lock( monitor );
93  return overrun_flag;
94 }
95 
96 template < typename T >
98  boost::shared_lock<boost::shared_mutex> lock( monitor );
99  return internal_buffer.capacity();
100 }
101 
102 template < typename T >
103 uint ouroborus<T>::size() {
104  boost::shared_lock<boost::shared_mutex> lock( monitor );
105  return internal_buffer.size();
106 }
107 
108 template < typename T >
109 void ouroborus<T>::Reset() {
110  boost::shared_lock<boost::shared_mutex> lock( monitor );
111 
112  internal_buffer.clear();
113  overrun_flag = false;
114 }
115 
116 template < typename T >
117 void ouroborus<T>::HeadInsert( T* to_insert, uint insert_size ) {
118 
119  DEBUG_PRINT( "Inserting " << insert_size << " elements into ring buffer" );
120 
121  // get upgradable access
122  boost::upgrade_lock<boost::shared_mutex> lock( monitor );
123  // get exclusive access
124  boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
125 
126  auto head = to_insert;
127  auto tail = head + insert_size;
128 
129  if( (internal_buffer.size() + insert_size) >= internal_buffer.capacity() ) {
130  overrun_flag = true;
131  }
132 
133  internal_buffer.insert( internal_buffer.begin(), head, tail );
134 
135 }
136 
137 template < typename T >
138 void ouroborus<T>::TailInsert( T* to_insert, uint insert_size ) {
139 
140  DEBUG_PRINT( "Inserting " << insert_size << " elements into ring buffer" );
141 
142  // get upgradable access
143  boost::upgrade_lock<boost::shared_mutex> lock( monitor );
144  // get exclusive access
145  boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
146 
147  auto head = to_insert;
148  auto tail = head + insert_size;
149 
150  if( (internal_buffer.size() + insert_size) >= internal_buffer.capacity() ) {
151  overrun_flag = true;
152  }
153 
154  internal_buffer.insert( internal_buffer.end(), head, tail );
155 
156 }
157 
158 template < typename T >
159 bool ouroborus<T>::CheckHead( uint data_size ) {
160 
161  // get upgradable access
162  boost::upgrade_lock<boost::shared_mutex> lock( monitor );
163  // get exclusive access
164  boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
165 
166  auto first = internal_buffer.begin();
167  auto last = internal_buffer.begin() + data_size;
168 
169  //Attempt to read more samples than are current stored in
170  //the ring buffer
171  bool check_condition = (std::distance(first, last) < data_size);
172 
173  if (check_condition) {
174  DEBUG_PRINT( __func__ << " Unable to read, not enough samples in ring buffer" );
175  } else {
176  DEBUG_PRINT( __func__ << " Able to read." );
177  }
178 
179  return !check_condition;
180 }
181 
182 template < typename T >
183 bool ouroborus<T>::CheckTail( uint data_size ) {
184 
185  // get upgradable access
186  boost::upgrade_lock<boost::shared_mutex> lock( monitor );
187  // get exclusive access
188  boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
189 
190  auto first = internal_buffer.end() - data_size;
191  auto last = internal_buffer.end() ;
192 
193  //Attempt to read more samples than are current stored in
194  //the ring buffer
195  bool check_condition = (std::distance(first, last) < data_size);
196 
197  if (check_condition) {
198  DEBUG_PRINT( __func__ << " Unable to read, not enough samples in ring buffer" );
199  } else {
200  DEBUG_PRINT( __func__ << " Able to read." );
201  }
202 
203  return !check_condition;
204 }
205 
206 template < typename T >
207 std::vector<T> ouroborus<T>::TailRead( uint read_size ) {
208 
209  // get shared access
210  boost::shared_lock<boost::shared_mutex> lock( monitor );
211 
212  auto first = internal_buffer.end() - read_size;
213  auto last = internal_buffer.end() ;
214  //Attempt to read more samples than are current stored in
215  //the ring buffer
216  bool check_condition = (std::distance(first, last) < read_size);
217 
218  if (check_condition) {
219  DEBUG_PRINT( __func__ << " Unable to read, not enough samples in ring buffer" );
220 
221  std::string err_str = "Not enough new data in ring buffer: Have ";
222  err_str += boost::lexical_cast<std::string>( internal_buffer.size() );
223  err_str += " new data samples, but ";
224  err_str += boost::lexical_cast<std::string>( read_size );
225  err_str += " were requested.";
226  throw std::ios_base::failure(err_str);
227 
228  } else {
229  DEBUG_PRINT( __func__ << " Able to read." );
230  }
231 
232  auto copy_vec = std::vector< T >( first, last );
233 
234  internal_buffer.erase ( first, last );
235 
236  return copy_vec;
237 }
238 
239 template < typename T >
240 template < typename F >
241 std::vector< F > ouroborus< T >::TailReadAndConvert( uint read_size ) {
242 
243  // get shared access
244  boost::shared_lock<boost::shared_mutex> lock( monitor );
245 
246  auto first = internal_buffer.end() - read_size;
247  auto last = internal_buffer.end() ;
248  //Attempt to read more samples than are current stored in
249  //the ring buffer
250  bool check_condition = (std::distance(first, last) < read_size);
251 
252  if (check_condition) {
253  DEBUG_PRINT( __func__ << " Unable to read, not enough samples in ring buffer" );
254 
255  std::string err_str = "Not enough new data in ring buffer: Have ";
256  err_str += boost::lexical_cast<std::string>( internal_buffer.size() );
257  err_str += " new data samples, but ";
258  err_str += boost::lexical_cast<std::string>( read_size );
259  err_str += " were requested.";
260  throw std::ios_base::failure(err_str);
261 
262  } else {
263  DEBUG_PRINT( __func__ << " Able to read." );
264  }
265 
266  auto copy_vec = std::vector< F >( first, last );
267 
268  internal_buffer.erase ( first, last );
269 
270  return copy_vec;
271 }
272 
273 template < typename T >
274 std::vector<T> ouroborus<T>::HeadRead( uint read_size ) {
275 
276  // get shared access
277  boost::shared_lock<boost::shared_mutex> lock( monitor );
278 
279  auto first = internal_buffer.begin() + 0;
280  auto last = internal_buffer.begin() + read_size;
281 
282  //Attempt to read more samples than are current stored in
283  //the ring buffer
284  bool check_condition = (std::distance(first, last) < read_size);
285 
286  if (check_condition) {
287  DEBUG_PRINT( __func__ << " Unable to read, not enough samples in ring buffer" );
288 
289  std::string err_str = "Not enough new data in ring buffer: Have ";
290  err_str += boost::lexical_cast<std::string>( internal_buffer.size() );
291  err_str += " new data samples, but ";
292  err_str += boost::lexical_cast<std::string>( read_size );
293  err_str += " were requested.";
294  throw std::ios_base::failure(err_str);
295  } else {
296  DEBUG_PRINT( __func__ << " Able to read." );
297  }
298 
299  auto copy_vec = std::vector< T >( first, last );
300 
301  internal_buffer.erase ( first, last );
302 
303  return copy_vec;
304 }
305 
306 template < typename T >
307 template < typename F >
308 std::vector< F > ouroborus<T>::HeadReadAndConvert ( uint read_size ) {
309 
310  // get shared access
311  boost::shared_lock<boost::shared_mutex> lock( monitor );
312 
313  auto first = internal_buffer.begin() + 0;
314  auto last = internal_buffer.begin() + read_size;
315 
316  //Attempt to read more samples than are current stored in
317  //the ring buffer
318  bool check_condition = (std::distance(first, last) < read_size);
319 
320  if (check_condition) {
321  DEBUG_PRINT( __func__ << " Unable to read, not enough samples in ring buffer" );
322 
323  std::string err_str = "Not enough new data in ring buffer: Have ";
324  err_str += boost::lexical_cast<std::string>( internal_buffer.size());
325  err_str += " new data samples, but ";
326  err_str += boost::lexical_cast<std::string>( read_size );
327  err_str += " were requested.";
328  throw std::ios_base::failure(err_str);
329  } else {
330  DEBUG_PRINT( __func__ << " Able to read." );
331  }
332 
333  auto copy_vec = std::vector< F >( first, last );
334 
335  internal_buffer.erase ( first, last );
336 
337  return copy_vec;
338 }
339 
340 
341 }
342 
343 #endif // OUROBOROS_H