circular_buffer.hpp 20 KB

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