CircularBufferI.H
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2022-2023 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
29 
30 template<class T>
31 inline Foam::label Foam::CircularBuffer<T>::toGlobal(label i) const
32 {
33  const label len = this->size();
34 
35  if (!len)
36  {
37  // Bounds error
38  return -1;
39  }
40  else if (i < 0)
41  {
42  // Wrap any number of times
43  while (i < 0) i += len;
44  }
45  else
46  {
47  // Wrap any number of times
48  while (i >= len) i -= len;
49  }
50 
51  i += begin_;
52 
53  if (i >= storage_.size())
54  {
55  i -= storage_.size();
56  }
57 
58  return i;
59 }
60 
61 
62 template<class T>
63 inline Foam::label Foam::CircularBuffer<T>::size_one() const noexcept
64 {
65  return
66  (
67  (end_ >= begin_)
68  ? (end_ - begin_)
69  : (storage_.size() - begin_)
70  );
71 }
72 
73 
74 template<class T>
75 inline Foam::label Foam::CircularBuffer<T>::size_two() const noexcept
76 {
77  return
78  (
79  (end_ && end_ < begin_)
80  ? end_
81  : static_cast<label>(0)
82  );
83 }
84 
85 
86 template<class T>
87 template<class OtherListType>
88 inline void Foam::CircularBuffer<T>::copyList(const OtherListType& rhs)
89 {
90  this->clear();
91 
92  const label len = rhs.size();
93 
94  if (len)
95  {
96  reserve(len + 1);
97 
98  // Never overfilled, simply write at end_ (one-past position)
99 
100  // - after clear(), begin_ and end_ are both 0
101 
102  for (label i = 0; i < len; ++i)
103  {
104  storage_[end_] = rhs[i]; // copy element
105  ++end_;
106  }
107  }
108 }
109 
110 
111 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
112 
113 template<class T>
115 :
116  storage_(),
117  begin_(0),
118  end_(0)
119 {}
120 
121 
122 template<class T>
123 inline Foam::CircularBuffer<T>::CircularBuffer(const label len)
124 :
125  storage_(max(min_size(), len + 1)),
126  begin_(0),
127  end_(0)
128 {}
129 
130 
131 template<class T>
133 (
134  const CircularBuffer<T>& list
135 )
136 :
137  storage_(list.storage_),
138  begin_(list.begin_),
139  end_(list.end_)
140 {}
141 
142 
143 template<class T>
145 (
146  CircularBuffer<T>&& list
147 )
148 :
149  storage_(std::move(list.storage_)),
150  begin_(list.begin_),
151  end_(list.end_)
152 {
153  list.begin_ = 0;
154  list.end_ = 0;
155 }
156 
157 
158 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
159 
160 template<class T>
161 inline Foam::label Foam::CircularBuffer<T>::capacity() const noexcept
162 {
163  // or storage_.capacity();
164  return storage_.size();
165 }
166 
167 
168 template<class T>
170 {
171  return storage_.empty() || (begin_ == end_);
172 }
173 
174 
175 template<class T>
176 inline Foam::label Foam::CircularBuffer<T>::size() const noexcept
177 {
178  const label diff(end_ - begin_);
179 
180  if (diff < 0)
181  {
182  return (storage_.size() + diff);
183  }
184 
185  return diff;
186 }
187 
188 
189 template<class T>
190 inline Foam::label Foam::CircularBuffer<T>::space() const noexcept
191 {
192  return (storage_.size() - size());
193 }
194 
195 
196 template<class T>
198 {
199  return
200  (
201  (begin_ == end_)
203  : labelRange(begin_, this->size_one())
204  );
205 }
206 
207 
208 template<class T>
210 {
211  return labelRange(0, this->size_two());
212 }
213 
214 
215 template<class T>
217 {
218  begin_ = end_ = 0;
219 }
220 
221 
222 template<class T>
224 {
225  storage_.clear();
226  begin_ = end_ = 0;
227 }
228 
229 
230 template<class T>
232 {
233  if (this == &other)
234  {
235  return; // Self-swap is a no-op
236  }
237 
238  // Swap storage and addressing
239  storage_.swap(other.storage_);
240  std::swap(begin_, other.begin_);
241  std::swap(end_, other.end_);
242 }
243 
244 
245 template<class T>
246 inline void Foam::CircularBuffer<T>::reserve(const label len)
247 {
248  this->doReserve(false, len);
249 }
250 
251 
252 template<class T>
253 inline void Foam::CircularBuffer<T>::reserve_nocopy(const label len)
254 {
255  this->doReserve(true, len);
256 }
257 
258 
259 template<class T>
260 bool Foam::CircularBuffer<T>::contains(const T& val) const
261 {
262  return (this->array_one().contains(val) || this->array_two().contains(val));
263 }
264 
265 
266 template<class T>
267 inline bool Foam::CircularBuffer<T>::contains(const T& val, label pos) const
268 {
269  return (this->find(val, pos) >= 0);
270 }
271 
272 
273 template<class T>
275 {
276  if (empty())
277  {
278  FatalErrorInFunction << "Buffer is empty" << abort(FatalError);
279  }
280 
281  return storage_[begin_];
282 }
283 
284 
285 template<class T>
286 inline const T& Foam::CircularBuffer<T>::front() const
287 {
288  if (empty())
289  {
290  FatalErrorInFunction << "Buffer is empty" << abort(FatalError);
291  }
292 
293  return storage_[begin_];
294 }
295 
296 
297 template<class T>
299 {
300  if (empty())
301  {
302  FatalErrorInFunction << "Buffer is empty" << abort(FatalError);
303  }
304 
305  return storage_.rcValue(end_);
306 }
307 
308 
309 template<class T>
310 inline const T& Foam::CircularBuffer<T>::back() const
311 {
312  if (empty())
313  {
314  FatalErrorInFunction << "Buffer is empty" << abort(FatalError);
315  }
316 
317  return storage_.rcValue(end_);
318 }
319 
320 
321 template<class T>
322 inline void Foam::CircularBuffer<T>::push_front(const T& val)
323 {
324  reserve(size() + 2);
325 
326  // Never overfilled. Move begin and write
328  begin_ = storage_.rcIndex(begin_);
329  storage_[begin_] = val; // copy assign element
330 }
331 
332 
333 template<class T>
334 inline void Foam::CircularBuffer<T>::push_front(T&& val)
335 {
336  reserve(size() + 2);
337 
338  // Never overfilled. Move begin and write
339 
340  begin_ = storage_.rcIndex(begin_);
341  storage_[begin_] = std::move(val); // move assign element
342 }
343 
344 
345 template<class T>
346 template<class... Args>
348 {
349  reserve(size() + 2);
350 
351  // Never overfilled. Move begin and write
352 
353  begin_ = storage_.rcIndex(begin_);
354  storage_[begin_] = T(std::forward<Args>(args)...);
355 
356  return storage_[begin_];
357 }
358 
359 
360 template<class T>
361 inline void Foam::CircularBuffer<T>::push_back(const T& val)
362 {
363  reserve(size() + 2);
364 
365  // Never overfilled, simply write at end_ (one-past position)
367  storage_[end_] = val; // copy assign element
368  end_ = storage_.fcIndex(end_);
369 }
370 
371 
372 template<class T>
373 inline void Foam::CircularBuffer<T>::push_back(T&& val)
374 {
375  reserve(size() + 2);
376 
377  // Never overfilled, simply write at end_ (one-past position)
378 
379  storage_[end_] = std::move(val); // move assign element
380  end_ = storage_.fcIndex(end_);
381 }
382 
383 
384 template<class T>
385 template<class... Args>
387 {
388  reserve(size() + 2);
389 
390  // Never overfilled, simply write at end_ (one-past position)
391 
392  const label backIndex = end_;
393  storage_[end_] = T(std::forward<Args>(args)...);
394  end_ = storage_.fcIndex(end_);
395 
396  return storage_[backIndex];
397 }
398 
399 
400 template<class T>
401 inline void Foam::CircularBuffer<T>::pop_front(label n)
402 {
403  if (n >= size())
404  {
405  begin_ = end_;
406  }
407  else
408  {
409  while (n-- > 0)
410  {
411  begin_ = storage_.fcIndex(begin_);
412  }
413  }
414 }
415 
416 
417 template<class T>
418 inline void Foam::CircularBuffer<T>::pop_back(label n)
419 {
420  if (n >= size())
421  {
422  end_ = begin_;
423  }
424  else
425  {
426  while (n-- > 0)
427  {
428  end_ = storage_.rcIndex(end_);
429  }
430  }
431 }
432 
433 
434 template<class T>
435 inline Foam::label Foam::CircularBuffer<T>::push_uniq(const T& val)
436 {
437  if (this->contains(val))
438  {
439  return 0;
440  }
441  else
442  {
443  this->push_back(val);
444  return 1; // Increased list length by one
445  }
446 }
447 
448 
449 template<class T>
450 inline void Foam::CircularBuffer<T>::push_back(const UList<T>& rhs)
451 {
452  const label len = rhs.size();
453 
454  if (len)
455  {
456  reserve(size() + len + 1);
457 
458  // Never overfilled, simply write at end_ (one-past position)
459 
460  for (label i = 0; i < len; ++i)
461  {
462  storage_[end_] = rhs[i]; // copy element
463  end_ = storage_.fcIndex(end_);
464  }
465  }
466 }
467 
468 
469 template<class T>
470 template<class Addr>
472 (
473  const IndirectListBase<T, Addr>& rhs
474 )
475 {
476  const label len = rhs.size();
477 
478  if (len)
479  {
480  reserve(size() + len + 1);
481 
482  // Never overfilled, simply write at end_ (one-past position)
483 
484  for (label i = 0; i < len; ++i)
485  {
486  storage_[end_] = rhs[i]; // copy element
487  end_ = storage_.fcIndex(end_);
488  }
489  }
490 }
491 
492 
493 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
494 
495 template<class T>
496 inline T& Foam::CircularBuffer<T>::operator[](label i)
497 {
498  const label idx = this->toGlobal(i);
499  return storage_[idx];
500 }
501 
502 
503 template<class T>
504 inline const T& Foam::CircularBuffer<T>::operator[](label i) const
505 {
506  const label idx = this->toGlobal(i);
507  return storage_[idx];
508 }
509 
510 
511 template<class T>
513 {
514  if (this == &rhs)
515  {
516  return; // Self-assignment is a no-op
517  }
518 
519  this->clear();
520 
521  const auto list1 = rhs.array_one();
522  const auto list2 = rhs.array_two();
523  const label len = (list1.size() + list2.size());
524 
525  if (len)
526  {
527  reserve(len + 1);
528 
529  // Never overfilled, simply write at end_ (one-past position)
530 
531  // - after clear(), begin_ and end_ are both 0
532 
533  for (const T& val : list1)
534  {
535  storage_[end_] = val;
536  ++end_;
537  }
538 
539  for (const T& val : list2)
540  {
541  storage_[end_] = val;
542  ++end_;
543  }
544  }
545 }
546 
547 
548 template<class T>
549 inline void Foam::CircularBuffer<T>::operator=(CircularBuffer<T>&& rhs)
550 {
551  if (this == &rhs)
552  {
553  return; // Self-assignment is a no-op
554  }
556  this->clearStorage();
557  this->swap(rhs);
558 }
559 
560 
561 template<class T>
562 inline void Foam::CircularBuffer<T>::operator=(const T& val)
563 {
564  this->array_one() = val;
565  this->array_two() = val;
566 }
567 
568 
569 template<class T>
571 {
572  this->array_one() = Foam::zero{};
573  this->array_two() = Foam::zero{};
574 }
575 
576 
577 template<class T>
578 inline void Foam::CircularBuffer<T>::operator=(const UList<T>& rhs)
579 {
580  this->copyList(rhs);
581 }
582 
583 
584 template<class T>
585 template<class AnyAddr>
587 (
589 )
590 {
591  this->copyList(rhs);
592 }
593 
594 
595 // ************************************************************************* //
void swap(CircularBuffer< T > &other)
Swap content, independent of sizing parameter.
label find(const ListType &input, const UnaryPredicate &pred, const label start=0)
Same as ListOps::find_if.
Definition: ListOps.H:795
scalar diff(const triad &A, const triad &B)
Return a quantity of the difference between two triads.
Definition: triad.C:373
void pop_front(label n=1)
Shrink by moving the front of the buffer 1 or more times.
constexpr CircularBuffer() noexcept
Default construct, empty buffer without allocation.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
labelRange range_two() const noexcept
The addressing range covered by array_two()
A range or interval of labels defined by a start and a size.
Definition: labelRange.H:52
void clear() noexcept
Clear the addressed buffer, does not change allocation.
void push_front(const T &val)
Copy prepend an element to the front of the buffer.
label size() const noexcept
The current number of buffer items.
T & back()
Access the last element (back). Requires !empty().
Base for lists with indirect addressing, templated on the list contents type and the addressing type...
bool empty() const noexcept
Empty or exhausted buffer.
T & emplace_front(Args &&... args)
Construct an element at the front of the buffer, return reference to the new element.
void clearStorage()
Clear the buffer and delete storage.
T & operator[](const label i)
Non-const access to an element in the list.
dimensionedScalar pos(const dimensionedScalar &ds)
List< T > list() const
Return a copy of the buffer flattened into a single List. Use sparingly!
A simple list of objects of type <T> that is intended to be used as a circular buffer (eg...
void pop_back(label n=1)
Shrink by moving the end of the buffer 1 or more times.
labelRange range_one() const noexcept
The addressing range covered by array_one()
patchWriters clear()
T & emplace_back(Args &&... args)
Construct an element at the end of the buffer, return reference to the new element.
errorManip< error > abort(error &err)
Definition: errorManip.H:139
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:105
const direction noexcept
Definition: Scalar.H:258
T & front()
Access the first element (front). Requires !empty().
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
bool contains(const T &val) const
True if the value is contained in the list.
label space() const noexcept
The nominal space available to fill. Subtract 1 for the number to append before re-balancing is neede...
SubList< T > array_one()
The contents of the first internal array.
void reserve_nocopy(const label len)
Reserve allocation space for at least this size, allocating new space if required without retaining o...
void operator=(const CircularBuffer< T > &list)
Copy construct.
triangles reserve(surf.size())
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition: zero.H:57
label n
void push_back(const T &val)
Copy append an element to the end of the buffer.
Foam::argList args(argc, argv)
label capacity() const noexcept
Size of the underlying storage.
SubList< T > array_two()
The contents of the second internal array.
label push_uniq(const T &val)
Append an element if not already in the buffer.
void reserve(const label len)
Reserve allocation space for at least this size, allocating new space if required and retaining old c...