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