• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //----------------------------------------------------------------------------
2 /// @file   circular_buffer.hpp
3 /// @brief  This file contains the implementation of the circular buffer
4 ///
5 /// @author Copyright (c) 2010 2015 Francisco José Tapia (fjtapia@gmail.com )\n
6 ///         Distributed under the Boost Software License, Version 1.0.\n
7 ///         ( See accompanyingfile LICENSE_1_0.txt or copy at
8 ///           http://www.boost.org/LICENSE_1_0.txt  )
9 /// @version 0.1
10 ///
11 /// @remarks
12 //-----------------------------------------------------------------------------
13 #ifndef __BOOST_SORT_COMMON_UTIL_CIRCULAR_BUFFER_HPP
14 #define __BOOST_SORT_COMMON_UTIL_CIRCULAR_BUFFER_HPP
15 
16 #include <memory>
17 #include <cassert>
18 #include <exception>
19 #include <boost/sort/common/util/algorithm.hpp>
20 #include <boost/sort/common/util/traits.hpp>
21 
22 namespace boost
23 {
24 namespace sort
25 {
26 namespace common
27 {
28 namespace util
29 {
30 
31 //---------------------------------------------------------------------------
32 /// @class  circular_buffer
33 /// @brief  This class implement a circular buffer
34 /// @remarks
35 //---------------------------------------------------------------------------
36 template <class Value_t, uint32_t Power2 = 11>
37 struct circular_buffer
38 {
39     //------------------------------------------------------------------------
40     //                          STATIC CHECK
41     //------------------------------------------------------------------------
42     static_assert ( Power2 != 0, "Wrong Power2");
43 
44     //------------------------------------------------------------------------
45     //                          DEFINITIONS
46     //------------------------------------------------------------------------
47     typedef Value_t value_t;
48 
49     //------------------------------------------------------------------------
50     //                          VARIABLES
51     //------------------------------------------------------------------------
52     const size_t NMAX = (size_t) 1 << Power2;
53     const size_t MASK = (NMAX - 1);
54     const size_t BLOCK_SIZE = NMAX >> 1;
55     const size_t LOG_BLOCK = Power2 - 1;
56     Value_t * ptr = nullptr;
57 
58     //------------------------------------------------------------------------
59     // first and last are  the position of the first and last elements
60     // always are in the range [0, NMAX - 1]
61     //------------------------------------------------------------------------
62     size_t nelem, first_pos;
63     bool initialized;
64 
65     //
66     //------------------------------------------------------------------------
67     //  function : circular_buffer
68     /// @brief  constructor of the class
69     //-----------------------------------------------------------------------
circular_bufferboost::sort::common::util::circular_buffer70     circular_buffer(void)
71     : ptr(nullptr), nelem(0), first_pos(0), initialized(false)
72     {
73         ptr = std::get_temporary_buffer < Value_t > (NMAX).first;
74         if (ptr == nullptr) throw std::bad_alloc();
75     };
76     //
77     //------------------------------------------------------------------------
78     //  function : ~circular_buffer
79     /// @brief destructor of the class
80     //-----------------------------------------------------------------------
~circular_bufferboost::sort::common::util::circular_buffer81     ~circular_buffer()
82     {
83         if (initialized)
84         {   for (size_t i = 0; i < NMAX; ++i) (ptr + i)->~Value_t();
85             initialized = false;
86         };
87         std::return_temporary_buffer(ptr);
88     }
89     ;
90     //
91     //------------------------------------------------------------------------
92     //  function : initialize
93     /// @brief : initialize the memory of the buffer from the uninitialize
94     //           memory obtained from the temporary buffer
95     /// @param val : value used to initialize the memory
96     //-----------------------------------------------------------------------
initializeboost::sort::common::util::circular_buffer97     void initialize(Value_t & val)
98     {
99         assert (initialized == false);
100         ::new (static_cast<void*>(ptr)) Value_t(std::move(val));
101         for (size_t i = 1; i < NMAX; ++i)
102             ::new (static_cast<void*>(ptr + i)) Value_t(std::move(ptr[i - 1]));
103         val = std::move(ptr[NMAX - 1]);
104         initialized = true;
105     };
106     //
107     //------------------------------------------------------------------------
108     //  function : destroy_all
109     /// @brief : destroy all the objects in the internal memory
110     //-----------------------------------------------------------------------
destroy_allboost::sort::common::util::circular_buffer111     void destroy_all(void) { destroy(ptr, ptr + NMAX); };
112     //
113     //------------------------------------------------------------------------
114     //  function : get_buffer
115     /// @brief return the internal memory of the circular buffer
116     /// @return pointer to the internal memory of the buffer
117     //-----------------------------------------------------------------------
get_bufferboost::sort::common::util::circular_buffer118     Value_t * get_buffer(void) { return ptr; };
119     //
120     //------------------------------------------------------------------------
121     //  function : empty
122     /// @brief return if the buffer is empty
123     /// @return true : empty
124     //-----------------------------------------------------------------------
emptyboost::sort::common::util::circular_buffer125     bool empty(void) const {return (nelem == 0); };
126     //
127     //------------------------------------------------------------------------
128     //  function : full
129     /// @brief return if the buffer is full
130     /// @return true : full
131     //-----------------------------------------------------------------------
fullboost::sort::common::util::circular_buffer132     bool full(void) const { return (nelem == NMAX); };
133     //
134     //------------------------------------------------------------------------
135     //  function : size
136     /// @brief return the number of elements stored in the buffer
137     /// @return number of elements stored
138     //-----------------------------------------------------------------------
sizeboost::sort::common::util::circular_buffer139     size_t size(void) const { return nelem;};
140     //
141     //------------------------------------------------------------------------
142     //  function : capacity
143     /// @brief : return the maximun capacity of the buffer
144     /// @return number of elements
145     //-----------------------------------------------------------------------
capacityboost::sort::common::util::circular_buffer146     size_t capacity(void) const { return NMAX;};
147     //
148     //------------------------------------------------------------------------
149     //  function : free_size
150     /// @brief return the free positions in the buffer
151     /// @return number of elements
152     //-----------------------------------------------------------------------
free_sizeboost::sort::common::util::circular_buffer153     size_t free_size(void) const  { return (NMAX - nelem); };
154     //
155     //------------------------------------------------------------------------
156     //  function : clear
157     /// @brief clear the buffer
158     //-----------------------------------------------------------------------
clearboost::sort::common::util::circular_buffer159     void clear(void)  { nelem = first_pos = 0; };
160     //
161     //------------------------------------------------------------------------
162     //  function : front
163     /// @brief return the first element of the buffer
164     /// @return reference to the first value
165     //-----------------------------------------------------------------------
frontboost::sort::common::util::circular_buffer166     Value_t & front(void)
167     {
168 #ifdef __BS_DEBUG
169         assert (nelem > 0);
170 #endif
171         return (ptr[first_pos]);
172     };
173     //
174     //------------------------------------------------------------------------
175     //  function :front
176     /// @brief return the first element of the buffer
177     /// @return const reference to the first value
178     //-----------------------------------------------------------------------
frontboost::sort::common::util::circular_buffer179     const Value_t & front(void) const
180     {
181 #ifdef __BS_DEBUG
182         assert ( nelem > 0 );
183 #endif
184         return (ptr[first_pos]);
185     };
186     //
187     //------------------------------------------------------------------------
188     //  function : back
189     /// @brief reference to the last value of the buffer
190     /// @return reference to the last value
191     //-----------------------------------------------------------------------
backboost::sort::common::util::circular_buffer192     Value_t & back(void)
193     {
194 #ifdef __BS_DEBUG
195         assert ( nelem > 0 );
196 #endif
197         return (ptr[(first_pos + nelem - 1) & MASK]);
198     };
199     //
200     //------------------------------------------------------------------------
201     //  function : back
202     /// @brief reference to the last value of the buffer
203     /// @return const reference to the last value
204     //-----------------------------------------------------------------------
backboost::sort::common::util::circular_buffer205     const Value_t & back(void) const
206     {
207 #ifdef __BS_DEBUG
208         assert ( nelem > 0 );
209 #endif
210         return (ptr[(first_pos + nelem - 1) & MASK]);
211     };
212     //
213     //------------------------------------------------------------------------
214     //  function : operator []
215     /// @brief positional access to the elements
216     /// @param pos rquested
217     /// @return reference to the element
218     //-----------------------------------------------------------------------
operator []boost::sort::common::util::circular_buffer219     Value_t & operator[](uint32_t pos)
220     {
221 #ifdef __BS_DEBUG
222         assert ( nelem > 0 );
223 #endif
224         return ptr[(first_pos + pos) & MASK];
225     };
226     //
227     //------------------------------------------------------------------------
228     //  function : operator []
229     /// @brief positional access to the elements
230     /// @param pos rquested
231     /// @return const reference to the element
232     //-----------------------------------------------------------------------
operator []boost::sort::common::util::circular_buffer233     const Value_t & operator[](uint32_t pos) const
234     {
235 
236 #ifdef __BS_DEBUG
237         assert ( nelem > 0 );
238 #endif
239         return ptr[(first_pos + pos) & MASK];
240     };
241     //
242     //------------------------------------------------------------------------
243     //  function : push_front
244     /// @brief insert an element in the first position of the buffer
245     /// @param val : const value to insert
246     //-----------------------------------------------------------------------
push_frontboost::sort::common::util::circular_buffer247     void push_front(const Value_t & val)
248     {
249 #ifdef __BS_DEBUG
250         assert ( nelem != NMAX);
251 #endif
252         ++nelem;
253         first_pos = ((first_pos + MASK) & MASK);
254         ptr[first_pos] = val;
255 
256     };
257     //
258     //------------------------------------------------------------------------
259     //  function : push_front
260     /// @brief insert an element in the first position of the buffer
261     /// @param val : rvalue to insert
262     //-----------------------------------------------------------------------
push_frontboost::sort::common::util::circular_buffer263     void push_front(Value_t && val)
264     {
265 #ifdef __BS_DEBUG
266         assert ( nelem != NMAX);
267 #endif
268         ++nelem;
269         first_pos = ((first_pos + MASK) & MASK);
270         ptr[first_pos] = val;
271     };
272     //
273     //------------------------------------------------------------------------
274     //  function : push_back
275     /// @brief insert an element in the last position of the buffer
276     /// @param val : value to insert
277     //-----------------------------------------------------------------------
push_backboost::sort::common::util::circular_buffer278     void push_back(const Value_t & val)
279     {
280 #ifdef __BS_DEBUG
281         assert ( nelem != NMAX);
282 #endif
283         ptr[(first_pos + (nelem++)) & MASK] = val;
284     };
285     //
286     //------------------------------------------------------------------------
287     //  function : push_back
288     /// @brief insert an element in the last position of the buffer
289     /// @param val : value to insert
290     //-----------------------------------------------------------------------
push_backboost::sort::common::util::circular_buffer291     void push_back(Value_t && val)
292     {
293 #ifdef __BS_DEBUG
294         assert ( nelem != NMAX);
295 #endif
296         ptr[(first_pos + (nelem++)) & MASK] = std::move(val);
297     };
298     //
299     //------------------------------------------------------------------------
300     //  function : pop_front
301     /// @brief remove the first element of the buffer
302     //-----------------------------------------------------------------------
pop_frontboost::sort::common::util::circular_buffer303     void pop_front(void)
304     {
305 #ifdef __BS_DEBUG
306         assert ( nelem > 0 );
307 #endif
308         --nelem;
309         (++first_pos) &= MASK;
310     };
311     //
312     //------------------------------------------------------------------------
313     //  function : pop_back
314     /// @brief remove the last element of the buffer
315     //-----------------------------------------------------------------------
pop_backboost::sort::common::util::circular_buffer316     void pop_back(void)
317     {
318 #ifdef __BS_DEBUG
319         assert ( nelem > 0 );
320 #endif
321         --nelem;
322     };
323 
324     template<class iter_t>
325     void pop_copy_front(iter_t it_dest, size_t num);
326 
327     template<class iter_t>
328     void pop_move_front(iter_t it_dest, size_t num);
329 
330     template<class iter_t>
331     void pop_copy_back(iter_t it_dest, size_t num);
332 
333     template<class iter_t>
334     void pop_move_back(iter_t it_dest, size_t num);
335 
336     template<class iter_t>
337     void push_copy_front(iter_t it_src, size_t num);
338 
339     template<class iter_t>
340     void push_move_front(iter_t it_src, size_t num);
341 
342     template<class iter_t>
343     void push_copy_back(iter_t it_src, size_t num);
344 
345     template<class iter_t>
346     void push_move_back(iter_t it_src, size_t num);
347 
348 //---------------------------------------------------------------------------
349 };//               End of class circular_buffer
350 //---------------------------------------------------------------------------
351 //
352 //
353 //############################################################################
354 //                                                                          ##
355 //             N O N    I N L I N E    F U N C T I O N S                    ##
356 //                                                                          ##
357 //############################################################################
358 //
359 //------------------------------------------------------------------------
360 //  function : pop_copy_front
361 /// @brief copy and delete num elements from the front of the buffer
362 /// @param it_dest : iterator to the first position where copy the elements
363 /// @param num : number of elements to copy
364 //-----------------------------------------------------------------------
365 template <class Value_t, uint32_t Power2>
366 template<class iter_t>
367 void circular_buffer<Value_t, Power2>
pop_copy_front(iter_t it_dest,size_t num)368 ::pop_copy_front(iter_t it_dest, size_t num)
369 {
370     static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
371                     "Incompatible iterator");
372     if (num == 0) return;
373 #ifdef __BS_DEBUG
374     assert ( num <= nelem);
375 #endif
376     nelem -= num;
377     size_t pos = first_pos;
378     first_pos = (first_pos + num) & MASK;
379     for (size_t i = 0; i < num; ++i)
380     {
381         *(it_dest++) = ptr[pos++ & MASK];
382     };
383     first_pos &= MASK;
384 };
385 //
386 //------------------------------------------------------------------------
387 //  function : pop_move_front
388 /// @brief move num elements from the front of the buffer to the place
389 //         pointed by it_dest
390 /// @param it_dest : iterator to the first position where move the elements
391 /// @param num : number of elements to move
392 //-----------------------------------------------------------------------
393 template <class Value_t, uint32_t Power2>
394 template<class iter_t>
395 void circular_buffer<Value_t, Power2>
pop_move_front(iter_t it_dest,size_t num)396 :: pop_move_front(iter_t it_dest, size_t num)
397 {
398     static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
399                     "Incompatible iterator");
400     if (num == 0) return;
401 #ifdef __BS_DEBUG
402     assert ( num <= nelem);
403 #endif
404     nelem -= num;
405     size_t pos = first_pos;
406     first_pos = (first_pos + num) & MASK;
407     for (size_t i = 0; i < num; ++i)
408     {
409         *(it_dest++) = std::move(ptr[pos++ & MASK]);
410     };
411     first_pos &= MASK;
412 };
413 //
414 //------------------------------------------------------------------------
415 //  function : pop_copy_back
416 /// @brief copy and delete num elements from the back of the buffer
417 /// @param p1 : iterator where begin to copy the elements
418 /// @param num : number of elements to copy
419 //-----------------------------------------------------------------------
420 template <class Value_t, uint32_t Power2>
421 template<class iter_t>
422 void circular_buffer<Value_t, Power2>
pop_copy_back(iter_t it_dest,size_t num)423 ::pop_copy_back(iter_t it_dest, size_t num)
424 {
425     static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
426                     "Incompatible iterator");
427     if (num == 0) return;
428 #ifdef __BS_DEBUG
429     assert ( num <= nelem);
430 #endif
431     nelem -= num;
432     size_t pos = (first_pos + nelem) & MASK;
433     for (size_t i = 0; i < num; ++i)
434     {
435         *(it_dest++) = ptr[pos++ & MASK];
436     };
437 };
438 //
439 //------------------------------------------------------------------------
440 //  function : pop_move_back
441 /// @brief move and delete num elements from the back of the buffer
442 /// @param p1 : iterator where begin to move the elements
443 /// @param num : number of elements to move
444 //-----------------------------------------------------------------------
445 template <class Value_t, uint32_t Power2>
446 template<class iter_t>
447 void circular_buffer<Value_t, Power2>
pop_move_back(iter_t it_dest,size_t num)448 ::pop_move_back(iter_t it_dest, size_t num)
449 {
450     static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
451                     "Incompatible iterator");
452     if (num == 0) return;
453 #ifdef __BS_DEBUG
454     assert ( num <= nelem);
455 #endif
456     nelem -= num;
457     size_t pos = (first_pos + nelem) & MASK;
458     for (size_t i = 0; i < num; ++i)
459     {
460         *(it_dest++) = std::move(ptr[pos++ & MASK]);
461     };
462 };
463 //
464 //------------------------------------------------------------------------
465 //  function : push_copy_front
466 /// @brief copy num elements in the front of the buffer
467 /// @param it_src : iterator from where begin to copy the elements
468 /// @param mun : number of element to copy
469 //-----------------------------------------------------------------------
470 template <class Value_t, uint32_t Power2>
471 template<class iter_t>
472 void circular_buffer<Value_t, Power2>
push_copy_front(iter_t it_src,size_t num)473 ::push_copy_front(iter_t it_src, size_t num)
474 {
475     static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
476                     "Incompatible iterator");
477     if (num == 0) return;
478 #ifdef __BS_DEBUG
479     assert ( free_size() >= num);
480 #endif
481     nelem += num;
482 
483     first_pos = (first_pos + NMAX - num) & MASK;
484     size_t pos = first_pos;
485     for (size_t i = 0; i < num; ++i)
486     {
487         ptr[(pos++) & MASK] = *(it_src++);
488     };
489 };
490 //
491 //------------------------------------------------------------------------
492 //  function : push_move_front
493 /// @brief move num elements in the front of the buffer
494 /// @param p1 : iterator from where begin to move the elements
495 /// @param mun : number of element to move
496 //-----------------------------------------------------------------------
497 template <class Value_t, uint32_t Power2>
498 template<class iter_t>
499 void circular_buffer<Value_t, Power2>
push_move_front(iter_t it_src,size_t num)500 ::push_move_front(iter_t it_src, size_t num)
501 {
502     static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
503                     "Incompatible iterator");
504     if (num == 0) return;
505 #ifdef __BS_DEBUG
506     assert ( free_size() >= num);
507 #endif
508     nelem += num;
509     size_t pos = first_pos;
510     for (size_t i = 0; i < num; ++i)
511     {
512         ptr[(pos++) & MASK] = std::move(*(it_src++));
513     };
514 };
515 //
516 //------------------------------------------------------------------------
517 //  function : push_copy_back
518 /// @brief copy num elements in the back of the buffer
519 /// @param p1 : iterator from where begin to copy the elements
520 /// @param mun : number of element to copy
521 //-----------------------------------------------------------------------
522 template <class Value_t, uint32_t Power2>
523 template<class iter_t>
524 void circular_buffer<Value_t, Power2>
push_copy_back(iter_t it_src,size_t num)525 ::push_copy_back(iter_t it_src, size_t num)
526 {
527     static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
528                     "Incompatible iterator");
529     if (num == 0) return;
530 #ifdef __BS_DEBUG
531     assert ( free_size() >= num);
532 #endif
533     size_t pos = first_pos + nelem;
534     nelem += num;
535     for (size_t i = 0; i < num; ++i)
536     {
537         ptr[(pos++) & MASK] = *(it_src++);
538     };
539 };
540 //
541 //------------------------------------------------------------------------
542 //  function : push_move_back
543 /// @brief move num elements in the back of the buffer
544 /// @param p1 : iterator from where begin to move the elements
545 /// @param mun : number of element to move
546 //-----------------------------------------------------------------------
547 template <class Value_t, uint32_t Power2>
548 template<class iter_t>
549 void circular_buffer<Value_t, Power2>
push_move_back(iter_t it_src,size_t num)550 ::push_move_back(iter_t it_src, size_t num)
551 {
552     static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
553                     "Incompatible iterator");
554     if (num == 0) return;
555 #ifdef __BS_DEBUG
556     assert ( free_size() >= num);
557 #endif
558     size_t pos = first_pos + nelem;
559     nelem += num;
560     for (size_t i = 0; i < num; ++i)
561     {
562         ptr[(pos++) & MASK] = std::move(*(it_src++));
563     };
564 };
565 
566 //****************************************************************************
567 };// End namespace util
568 };// End namespace common
569 };// End namespace sort
570 };// End namespace boost
571 //****************************************************************************
572 #endif
573