Virtual Testbed
Ship dynamics simulator for extreme conditions
circular_buffer.hh
1 #ifndef VTESTBED_CORE_CIRCULAR_BUFFER_HH
2 #define VTESTBED_CORE_CIRCULAR_BUFFER_HH
3 
4 #include <algorithm>
5 #include <array>
6 #include <memory>
7 
8 #include <vtestbed/base/multiple_array_iterator.hh>
9 
10 namespace vtb {
11 
12  namespace core {
13 
19  template <class T>
21 
22  public:
23  using value_type = T;
24  using pointer = value_type*;
25  using const_pointer = const value_type*;
26  using size_type = std::size_t;
28  using reference = value_type&;
29  using const_reference = const value_type&;
32 
33  private:
35  pointer _first = nullptr, _last = nullptr, _current = nullptr;
36  size_type _counter = 0;
37 
38  public:
39 
40  Circular_buffer() = default;
41  ~Circular_buffer() = default;
42 
43  inline
44  Circular_buffer(size_type size, const value_type& value):
45  _data(new T[size]{}),
46  _first(_data.get()),
47  _last(_first + size),
48  _current(_first) {
49  std::fill_n(this->data(), this->max_size(), value);
50  }
51 
52  inline explicit
54  _data(new T[size]{}),
55  _first(_data.get()),
56  _last(_first + size),
57  _current(_first) {}
58 
59  inline
61  _data{rhs._data},
62  _first{rhs._first},
63  _last{rhs._last},
64  _current{rhs._current} {
65  rhs._data = nullptr;
66  }
67 
68  inline
69  Circular_buffer(const Circular_buffer& rhs):
70  _data{new T[rhs.max_size()]},
71  _first{_data.get()},
72  _last{_data.get() + rhs.max_size()},
73  _current{_data.get() + (rhs._current - rhs._first)} {
74  std::copy(rhs._first, rhs._last, _first);
75  }
76 
77  inline Circular_buffer&
78  operator=(const Circular_buffer& rhs) {
79  Circular_buffer tmp(rhs);
80  this->swap(tmp);
81  return *this;
82  }
83 
84  inline Circular_buffer&
85  operator=(Circular_buffer&& rhs) {
86  this->swap(rhs);
87  return *this;
88  }
89 
90  inline const_pointer
91  data() const noexcept {
92  return this->_data.get();
93  }
94 
95  inline pointer
96  data() noexcept {
97  return this->_data.get();
98  }
99 
100  inline size_type
101  max_size() const noexcept {
102  return this->_last - this->_first;
103  }
104 
105  inline size_type
106  size() const noexcept {
107  return (this->middle()-this->current()) +
108  (this->current() - this->_first);
109  }
110 
111  inline bool
112  empty() const {
113  return this->size() == 0;
114  }
115 
116  inline size_type
117  counter() const noexcept {
118  return this->_counter;
119  }
120 
121  inline const_iterator
122  cbegin() const noexcept {
123  return const_iterator{
124  std::make_pair(this->_current,this->middle()),
125  std::make_pair(this->_first,this->_current)
126  };
127  }
128 
129  inline const_iterator
130  begin() const noexcept {
131  return this->cbegin();
132  }
133 
134  inline iterator
135  begin() noexcept {
136  return iterator{
137  std::make_pair(this->_current,this->middle()),
138  std::make_pair(this->_first,this->_current)
139  };
140  }
141 
142  inline const_iterator
143  cend() const noexcept {
144  return const_iterator{0,
145  std::make_pair(this->_current,this->middle()),
146  std::make_pair(this->_first,this->_current)
147  };
148  }
149 
150  inline const_iterator
151  end() const noexcept {
152  return this->cend();
153  }
154 
155  inline iterator
156  end() noexcept {
157  return iterator{0,
158  std::make_pair(this->_current,this->middle()),
159  std::make_pair(this->_first,this->_current)
160  };
161  }
162 
163  inline const_pointer
164  current() const noexcept {
165  return this->_current;
166  }
167 
168  inline pointer
169  current() noexcept {
170  return this->_current;
171  }
172 
173  inline const_pointer
174  middle() const {
175  return (this->_counter == this->max_size())
176  ? this->_last : this->_current;
177  }
178 
179  inline pointer
180  middle() {
181  return (this->_counter == this->max_size())
182  ? this->_last : this->_current;
183  }
184 
185  inline value_type&
186  front() noexcept {
187  return *((this->_counter == this->max_size())
188  ? this->_current : this->_first);
189  }
190 
191  inline const value_type&
192  front() const noexcept {
193  return *((this->_counter == this->max_size())
194  ? this->_current : this->_first);
195  }
196 
197  inline value_type&
198  back() noexcept {
199  return *((this->_current == this->_first)
200  ? (this->_last-1) : (this->_current-1));
201  }
202 
203  inline const value_type&
204  back() const noexcept {
205  return *((this->_current == this->_first)
206  ? (this->_last-1) : (this->_current-1));
207  }
208 
209  inline const value_type&
210  operator[](size_type i) const {
211  return this->_first[i];
212  }
213 
214  inline void
215  record(const T& value) {
216  if (this->_counter < this->max_size()) {
217  ++this->_counter;
218  }
219  if (_current == _last) {
220  _current = _first;
221  }
222  *_current = value;
223  ++_current;
224  }
225 
226  inline void
227  record(T&& value) {
228  if (this->_counter < this->max_size()) {
229  ++this->_counter;
230  }
231  if (_current == _last) {
232  _current = _first;
233  }
234  *_current = std::forward<T>(value);
235  ++_current;
236  }
237 
238  inline void
239  resize(size_type new_size) {
240  std::unique_ptr<T[]> new_data(new T[new_size]);
241  size_type offset = 0;
242  if (this->_data) {
243  auto first = this->_first;
244  auto last = first + std::min(new_size, this->max_size());
245  auto result = new_data.get();
246  offset = this->_current - this->_first;
247  while (first != last) {
248  *result = std::move(*first);
249  ++result;
250  ++first;
251  }
252  }
253  this->_data = std::move(new_data);
254  this->_first = this->_data.get();
255  this->_last = this->_first + new_size;
256  this->_current = this->_first + std::min(offset, new_size);
257  this->_counter = std::min(this->_counter, new_size);
258  }
259 
260  inline void
261  swap(Circular_buffer& rhs) {
262  using std::swap;
263  swap(this->_data, rhs._data);
264  swap(this->_first, rhs._first);
265  swap(this->_last, rhs._last);
266  swap(this->_current, rhs._current);
267  swap(this->_counter, rhs._counter);
268  }
269 
270  inline void
271  clear() {
272  size_type n = this->max_size();
273  std::fill_n(this->data(), n, value_type{});
274  this->_first = this->_data.get();
275  this->_last = this->_first + n;
276  this->_current = this->_first;
277  this->_counter = 0;
278  }
279 
280  };
281 
282  template <class T>
283  inline void
284  swap(Circular_buffer<T>& lhs, Circular_buffer<T>& rhs) {
285  lhs.swap(rhs);
286  }
287 
288  }
289 
290 }
291 
292 #endif // vim:filetype=cpp
Main namespace.
Definition: convert.hh:9
Fixed-size circular buffer. Used as time series storage.