circular_buffer.hpp 20 KB

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