Pothos  0.7.0-gf7fbae99
The Pothos dataflow programming software suite
RingDeque.hpp
Go to the documentation of this file.
1 
11 #pragma once
12 #include <Pothos/Config.hpp>
13 #include <cstdlib> //size_t
14 #include <utility> //forward
15 #include <memory> //allocator
16 #include <cassert>
17 
18 namespace Pothos {
19 namespace Util {
20 
28 template <typename T, typename Allocator = std::allocator<T>>
29 class RingDeque
30 {
31 public:
37  RingDeque(const size_t capacity = 1, const Allocator &allocator = Allocator());
38 
40  RingDeque(const RingDeque<T, Allocator> &other);
41 
44 
47 
50 
52  ~RingDeque(void);
53 
55  const T &operator[](const size_t offset) const;
56 
58  T &operator[](const size_t offset);
59 
61  template <typename U>
62  void push_front(U &&elem);
63 
65  template <typename... Args>
66  T &emplace_front(Args&&... args);
67 
69  void pop_front(void);
70 
72  const T &front(void) const;
73 
75  T &front(void);
76 
78  template <typename U>
79  void push_back(U &&elem);
80 
82  template <typename... Args>
83  T &emplace_back(Args&&... args);
84 
86  void pop_back(void);
87 
89  const T &back(void) const;
90 
92  T &back(void);
93 
95  bool empty(void) const;
96 
98  bool full(void) const;
99 
101  size_t size(void) const;
102 
104  size_t capacity(void) const;
105 
107  void set_capacity(const size_t capacity);
108 
110  void clear(void);
111 
112  typedef T value_type;
113 
114  typedef Allocator allocator_type;
115 
116 private:
117  Allocator _allocator;
118  size_t _mask;
119  size_t _capacity;
120  size_t _frontIndex;
121  size_t _numElements;
122  T *_container;
123 };
124 
125 namespace Detail {
126 
127  template <typename T>
128  T nextPow2(const T &in)
129  {
130  T out(1);
131  while (out < in) out <<= 1;
132  return out;
133  }
134 
135 } //namespace Detail
136 
137 template <typename T, typename A>
138 RingDeque<T, A>::RingDeque(const size_t capacity, const A &allocator):
139  _allocator(allocator),
140  _mask(Detail::nextPow2(capacity)-1),
141  _capacity(capacity),
142  _frontIndex(0),
143  _numElements(0),
144  _container(_allocator.allocate(_mask+1))
145 {
146  assert(capacity > 0);
147 }
148 
149 template <typename T, typename A>
151  _mask(other._mask),
152  _capacity(other._capacity),
153  _frontIndex(0),
154  _numElements(0),
155  _container(_allocator.allocate(_mask+1))
156 {
157  for (size_t i = 0; i < other.size(); i++)
158  {
159  this->push_back(other[i]);
160  }
161 }
162 
163 template <typename T, typename A>
165  _allocator(std::move(other._allocator)),
166  _mask(std::move(other._mask)),
167  _capacity(std::move(other._capacity)),
168  _frontIndex(std::move(other._frontIndex)),
169  _numElements(std::move(other._numElements)),
170  _container(std::move(other._container))
171 {
172  other._numElements = 0;
173  other._capacity = 0;
174  other._container = nullptr;
175 }
176 
177 template <typename T, typename A>
179 {
180  this->clear();
181  this->set_capacity(other.capacity());
182  for (size_t i = 0; i < other.size(); i++)
183  {
184  this->push_back(other[i]);
185  }
186  return *this;
187 }
188 
189 template <typename T, typename A>
191 {
192  this->clear();
193  _allocator.deallocate(_container, _mask+1);
194  _allocator = std::move(other._allocator);
195  _mask = std::move(other._mask);
196  _capacity = std::move(other._capacity);
197  _frontIndex = std::move(other._frontIndex);
198  _numElements = std::move(other._numElements);
199  _container = std::move(other._container);
200  other._numElements = 0;
201  other._capacity = 0;
202  other._container = nullptr;
203  return *this;
204 }
205 
206 template <typename T, typename A>
208 {
209  if (_container == nullptr) return;
210  this->clear();
211  _allocator.deallocate(_container, _mask+1);
212 }
213 
214 template <typename T, typename A>
215 const T &RingDeque<T, A>::operator[](const size_t offset) const
216 {
217  return _container[(_frontIndex + offset) & _mask];
218 }
219 
220 template <typename T, typename A>
221 T &RingDeque<T, A>::operator[](const size_t offset)
222 {
223  return _container[(_frontIndex + offset) & _mask];
224 }
225 
226 template <typename T, typename A>
227 template <typename U>
229 {
230  this->emplace_front(std::forward<U>(elem));
231 }
232 
233 template <typename T, typename A>
234 template <typename... Args>
236 {
237  assert(not this->full());
238  _frontIndex--;
239  _numElements++;
240  return *(new(&front()) T(std::forward<Args>(args)...));
241 }
242 
243 template <typename T, typename A>
245 {
246  assert(not this->empty());
247  this->front().~T();
248  _frontIndex++;
249  _numElements--;
250 }
251 
252 template <typename T, typename A>
253 const T &RingDeque<T, A>::front(void) const
254 {
255  assert(not this->empty());
256  return (*this)[0];
257 }
258 
259 template <typename T, typename A>
261 {
262  assert(not this->empty());
263  return (*this)[0];
264 }
265 
266 template <typename T, typename A>
267 template <typename U>
269 {
270  this->emplace_back(std::forward<U>(elem));
271 }
272 
273 template <typename T, typename A>
274 template <typename... Args>
276 {
277  assert(not this->full());
278  _numElements++;
279  return *(new(&back()) T(std::forward<Args>(args)...));
280 }
281 
282 template <typename T, typename A>
284 {
285  assert(not this->empty());
286  this->back().~T();
287  _numElements--;
288 }
289 
290 template <typename T, typename A>
291 const T &RingDeque<T, A>::back(void) const
292 {
293  assert(not this->empty());
294  return (*this)[size_t(_numElements-1)];
295 }
296 
297 template <typename T, typename A>
299 {
300  assert(not this->empty());
301  return (*this)[size_t(_numElements-1)];
302 }
303 
304 template <typename T, typename A>
305 bool RingDeque<T, A>::empty(void) const
306 {
307  return _numElements == 0;
308 }
309 
310 template <typename T, typename A>
311 bool RingDeque<T, A>::full(void) const
312 {
313  return _numElements == _capacity;
314 }
315 
316 template <typename T, typename A>
317 size_t RingDeque<T, A>::size(void) const
318 {
319  return _numElements;
320 }
321 
322 template <typename T, typename A>
323 size_t RingDeque<T, A>::capacity(void) const
324 {
325  return _capacity;
326 }
327 
328 template <typename T, typename A>
329 void RingDeque<T, A>::set_capacity(const size_t capacity)
330 {
331  if (_numElements > capacity) return;
332  RingDeque<T, A> newRing(capacity);
333  while (not this->empty())
334  {
335  newRing.push_back(std::move(this->front()));
336  this->pop_front();
337  }
338  *this = std::move(newRing);
339 }
340 
341 template <typename T, typename A>
343 {
344  while (not this->empty())
345  {
346  this->pop_front();
347  }
348 }
349 
350 } //namespace Util
351 } //namespace Pothos
void pop_back(void)
Pop and element from the back of the queue.
Definition: RingDeque.hpp:283
bool full(void) const
Is the deque full? – num elements == capacity.
Definition: RingDeque.hpp:311
RingDeque & operator=(const RingDeque< T, Allocator > &other)
Copy assignment.
Definition: RingDeque.hpp:178
void push_front(U &&elem)
Push an element onto the front of the queue.
Definition: RingDeque.hpp:228
T value_type
The element type.
Definition: RingDeque.hpp:112
T & emplace_front(Args &&... args)
Emplace an element onto the front of the queue.
Definition: RingDeque.hpp:235
void pop_front(void)
Pop and element from the front of the queue.
Definition: RingDeque.hpp:244
RingDeque(const size_t capacity=1, const Allocator &allocator=Allocator())
Definition: RingDeque.hpp:138
void set_capacity(const size_t capacity)
Set the deque capacity if too small.
Definition: RingDeque.hpp:329
const T & front(void) const
Get a const reference to the front element.
Definition: RingDeque.hpp:253
Definition: ArchiveEntry.hpp:20
Allocator allocator_type
The allocator type.
Definition: RingDeque.hpp:114
bool empty(void) const
Is the deque empty? – no elements.
Definition: RingDeque.hpp:305
const T & back(void) const
Get a const reference to the back element.
Definition: RingDeque.hpp:291
Definition: RingDeque.hpp:29
size_t capacity(void) const
How many elements can be stored?
Definition: RingDeque.hpp:323
size_t size(void) const
How many elements are in the deque.
Definition: RingDeque.hpp:317
void push_back(U &&elem)
Push an element onto the back of the queue.
Definition: RingDeque.hpp:268
~RingDeque(void)
Destruct the ring queue and any elements held.
Definition: RingDeque.hpp:207
T & emplace_back(Args &&... args)
Emplace an element onto the back of the queue.
Definition: RingDeque.hpp:275
void clear(void)
Empty the contents of this queue.
Definition: RingDeque.hpp:342
const T & operator[](const size_t offset) const
Get a const ref at, where front == 0, back == size() - 1.
Definition: RingDeque.hpp:215