RingDeque.hpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. ///
  2. /// \file Util/RingDeque.hpp
  3. ///
  4. /// A templated double ended queue implemented on top of a vector.
  5. ///
  6. /// \copyright
  7. /// Copyright (c) 2013-2017 Josh Blum
  8. /// SPDX-License-Identifier: BSL-1.0
  9. ///
  10. #pragma once
  11. #include <Pothos/Config.hpp>
  12. #include <cstdlib> //size_t
  13. #include <utility> //forward
  14. #include <memory> //allocator
  15. #include <cassert>
  16. namespace Pothos {
  17. namespace Util {
  18. /*!
  19. * RingDeque is a templated deque using an underlying vector.
  20. * The API of RingDeque is very similar to the std::deque<T>.
  21. * RingDeque is here because I wanted the efficiency of
  22. * boost::circular_buffer without the boost requirement.
  23. * The ring deque does not have a specific capacity limit.
  24. */
  25. template <typename T, typename Allocator = std::allocator<T>>
  26. class RingDeque
  27. {
  28. public:
  29. /*!
  30. * Construct a new ring deque
  31. * \param capacity the maximum space available
  32. * \param allocator an optional custom allocator
  33. */
  34. RingDeque(const size_t capacity = 1, const Allocator &allocator = Allocator());
  35. //! Copy constructor
  36. RingDeque(const RingDeque<T, Allocator> &other);
  37. //! Move constructor
  38. RingDeque(RingDeque<T, Allocator> &&other);
  39. //! Copy assignment
  40. RingDeque &operator=(const RingDeque<T, Allocator> &other);
  41. //! Move assignment
  42. RingDeque &operator=(RingDeque<T, Allocator> &&other);
  43. //! Destruct the ring queue and any elements held
  44. ~RingDeque(void);
  45. //! Get a const ref at, where front == 0, back == size() - 1
  46. const T &operator[](const size_t offset) const;
  47. //! Get a ref at, where front == 0, back == size() - 1
  48. T &operator[](const size_t offset);
  49. //! Push an element onto the front of the queue
  50. template <typename U>
  51. void push_front(U &&elem);
  52. //! Emplace an element onto the front of the queue
  53. template <typename... Args>
  54. T &emplace_front(Args&&... args);
  55. //! Pop and element from the front of the queue
  56. void pop_front(void);
  57. //! Get a const reference to the front element
  58. const T &front(void) const;
  59. //! Get a reference to the front element
  60. T &front(void);
  61. //! Push an element onto the back of the queue
  62. template <typename U>
  63. void push_back(U &&elem);
  64. //! Emplace an element onto the back of the queue
  65. template <typename... Args>
  66. T &emplace_back(Args&&... args);
  67. //! Pop and element from the back of the queue
  68. void pop_back(void);
  69. //! Get a const reference to the back element
  70. const T &back(void) const;
  71. //! Get a reference to the back element
  72. T &back(void);
  73. //! Is the deque empty? -- no elements
  74. bool empty(void) const;
  75. //! Is the deque full? -- num elements == capacity
  76. bool full(void) const;
  77. //! How many elements are in the deque
  78. size_t size(void) const;
  79. //! How many elements can be stored?
  80. size_t capacity(void) const;
  81. //! Set the deque capacity if too small
  82. void set_capacity(const size_t capacity);
  83. //! Empty the contents of this queue
  84. void clear(void);
  85. typedef T value_type; //!< The element type
  86. typedef Allocator allocator_type; //!< The allocator type
  87. private:
  88. Allocator _allocator;
  89. size_t _mask;
  90. size_t _capacity;
  91. size_t _frontIndex;
  92. size_t _numElements;
  93. T *_container;
  94. };
  95. namespace Detail {
  96. template <typename T>
  97. T nextPow2(const T &in)
  98. {
  99. T out(1);
  100. while (out < in) out <<= 1;
  101. return out;
  102. }
  103. } //namespace Detail
  104. template <typename T, typename A>
  105. RingDeque<T, A>::RingDeque(const size_t capacity, const A &allocator):
  106. _allocator(allocator),
  107. _mask(Detail::nextPow2(capacity)-1),
  108. _capacity(capacity),
  109. _frontIndex(0),
  110. _numElements(0),
  111. _container(_allocator.allocate(_mask+1))
  112. {
  113. assert(capacity > 0);
  114. }
  115. template <typename T, typename A>
  116. RingDeque<T, A>::RingDeque(const RingDeque<T, A> &other):
  117. _mask(other._mask),
  118. _capacity(other._capacity),
  119. _frontIndex(0),
  120. _numElements(0),
  121. _container(_allocator.allocate(_mask+1))
  122. {
  123. for (size_t i = 0; i < other.size(); i++)
  124. {
  125. this->push_back(other[i]);
  126. }
  127. }
  128. template <typename T, typename A>
  129. RingDeque<T, A>::RingDeque(RingDeque<T, A> &&other):
  130. _allocator(std::move(other._allocator)),
  131. _mask(std::move(other._mask)),
  132. _capacity(std::move(other._capacity)),
  133. _frontIndex(std::move(other._frontIndex)),
  134. _numElements(std::move(other._numElements)),
  135. _container(std::move(other._container))
  136. {
  137. other._numElements = 0;
  138. other._capacity = 0;
  139. other._container = nullptr;
  140. }
  141. template <typename T, typename A>
  142. RingDeque<T, A> &RingDeque<T, A>::operator=(const RingDeque<T, A> &other)
  143. {
  144. this->clear();
  145. this->set_capacity(other.capacity());
  146. for (size_t i = 0; i < other.size(); i++)
  147. {
  148. this->push_back(other[i]);
  149. }
  150. return *this;
  151. }
  152. template <typename T, typename A>
  153. RingDeque<T, A> &RingDeque<T, A>::operator=(RingDeque<T, A> &&other)
  154. {
  155. this->clear();
  156. _allocator.deallocate(_container, _mask+1);
  157. _allocator = std::move(other._allocator);
  158. _mask = std::move(other._mask);
  159. _capacity = std::move(other._capacity);
  160. _frontIndex = std::move(other._frontIndex);
  161. _numElements = std::move(other._numElements);
  162. _container = std::move(other._container);
  163. other._numElements = 0;
  164. other._capacity = 0;
  165. other._container = nullptr;
  166. return *this;
  167. }
  168. template <typename T, typename A>
  169. RingDeque<T, A>::~RingDeque(void)
  170. {
  171. if (_container == nullptr) return;
  172. this->clear();
  173. _allocator.deallocate(_container, _mask+1);
  174. }
  175. template <typename T, typename A>
  176. const T &RingDeque<T, A>::operator[](const size_t offset) const
  177. {
  178. return _container[(_frontIndex + offset) & _mask];
  179. }
  180. template <typename T, typename A>
  181. T &RingDeque<T, A>::operator[](const size_t offset)
  182. {
  183. return _container[(_frontIndex + offset) & _mask];
  184. }
  185. template <typename T, typename A>
  186. template <typename U>
  187. void RingDeque<T, A>::push_front(U &&elem)
  188. {
  189. this->emplace_front(std::forward<U>(elem));
  190. }
  191. template <typename T, typename A>
  192. template <typename... Args>
  193. T &RingDeque<T, A>::emplace_front(Args&&... args)
  194. {
  195. assert(not this->full());
  196. _frontIndex--;
  197. _numElements++;
  198. return *(new(&front()) T(std::forward<Args>(args)...));
  199. }
  200. template <typename T, typename A>
  201. void RingDeque<T, A>::pop_front(void)
  202. {
  203. assert(not this->empty());
  204. this->front().~T();
  205. _frontIndex++;
  206. _numElements--;
  207. }
  208. template <typename T, typename A>
  209. const T &RingDeque<T, A>::front(void) const
  210. {
  211. assert(not this->empty());
  212. return (*this)[0];
  213. }
  214. template <typename T, typename A>
  215. T &RingDeque<T, A>::front(void)
  216. {
  217. assert(not this->empty());
  218. return (*this)[0];
  219. }
  220. template <typename T, typename A>
  221. template <typename U>
  222. void RingDeque<T, A>::push_back(U &&elem)
  223. {
  224. this->emplace_back(std::forward<U>(elem));
  225. }
  226. template <typename T, typename A>
  227. template <typename... Args>
  228. T &RingDeque<T, A>::emplace_back(Args&&... args)
  229. {
  230. assert(not this->full());
  231. _numElements++;
  232. return *(new(&back()) T(std::forward<Args>(args)...));
  233. }
  234. template <typename T, typename A>
  235. void RingDeque<T, A>::pop_back(void)
  236. {
  237. assert(not this->empty());
  238. this->back().~T();
  239. _numElements--;
  240. }
  241. template <typename T, typename A>
  242. const T &RingDeque<T, A>::back(void) const
  243. {
  244. assert(not this->empty());
  245. return (*this)[size_t(_numElements-1)];
  246. }
  247. template <typename T, typename A>
  248. T &RingDeque<T, A>::back(void)
  249. {
  250. assert(not this->empty());
  251. return (*this)[size_t(_numElements-1)];
  252. }
  253. template <typename T, typename A>
  254. bool RingDeque<T, A>::empty(void) const
  255. {
  256. return _numElements == 0;
  257. }
  258. template <typename T, typename A>
  259. bool RingDeque<T, A>::full(void) const
  260. {
  261. return _numElements == _capacity;
  262. }
  263. template <typename T, typename A>
  264. size_t RingDeque<T, A>::size(void) const
  265. {
  266. return _numElements;
  267. }
  268. template <typename T, typename A>
  269. size_t RingDeque<T, A>::capacity(void) const
  270. {
  271. return _capacity;
  272. }
  273. template <typename T, typename A>
  274. void RingDeque<T, A>::set_capacity(const size_t capacity)
  275. {
  276. if (_numElements > capacity) return;
  277. RingDeque<T, A> newRing(capacity);
  278. while (not this->empty())
  279. {
  280. newRing.push_back(std::move(this->front()));
  281. this->pop_front();
  282. }
  283. *this = std::move(newRing);
  284. }
  285. template <typename T, typename A>
  286. void RingDeque<T, A>::clear(void)
  287. {
  288. while (not this->empty())
  289. {
  290. this->pop_front();
  291. }
  292. }
  293. } //namespace Util
  294. } //namespace Pothos