CircularBuffer.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 Class
27  Foam::CircularBuffer
28 
29 Description
30  A simple list of objects of type <T> that is intended to be used
31  as a circular buffer (eg, a FIFO) when the alloc/free overhead
32  associated with a linked-list approach is to be avoided.
33 
34  The internal storage is addressed by independent begin/end markers.
35  - The %begin marker points to the \em front.
36  - The %end marker is a one-past the \em back.
37  .
38  This results in a variety ofr different possible buffer states:
39  -# \em empty (\em begin == \em end)
40 
41  -# \em simple/linear (\em begin < \em end) has no wrapping:
42  \verbatim
43  |.|.|.|a|b|c|d|.|.|.|
44  beg ___^
45  end ___________^
46  \endverbatim
47 
48  -# \em split (\em begin > \em end):
49  \verbatim
50  |f|g|h|i|.|.|.|a|b|c|d|e|
51  end _____^
52  beg ___________^
53  \endverbatim
54  .
55 
56  The methods range_one(), range_two() return the internal indexing and
57  the methods array_one(), array_two() provide direct access to the
58  internal contents.
59 
60  When filling the buffer, the internal storage will be resized
61  (doubling strategy) as required. When this occurs, the new list
62  will be linearized with \em begin = 0.
63 
64  Simultaneously when filling, the storage buffer will be over-allocated
65  to avoid ambiguity when (\em begin == \em end), which represents an
66  \em %empty buffer and not a \em %full buffer. Eg,
67  \verbatim
68  |c|d|.|a|b|
69  end _^
70  beg ___^
71  \endverbatim
72  after appending one more, it would be incorrect to simply fill
73  the available space:
74  \verbatim
75  |c|d|e|a|b|
76  end ___^ WRONG : would represent empty!
77  beg ___^
78  \endverbatim
79  the storage is instead increased (doubled) and rebalanced before
80  the append occurs (old capacity 5, new capacity 10):
81  \verbatim
82  |a|b|c|d|e|.|.|.|.|.|
83  _^_ beg
84  end _______^
85  \endverbatim
86 
87 SourceFiles
88  CircularBuffer.C
89  CircularBufferI.H
90  CircularBufferIO.C
91 
92 \*---------------------------------------------------------------------------*/
93 
94 #ifndef Foam_CircularBuffer_H
95 #define Foam_CircularBuffer_H
96 
97 #include "List.H"
98 #include "SubList.H"
99 
100 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
102 namespace Foam
103 {
104 
105 // Forward Declarations
106 template<class T> class CircularBuffer;
107 
108 template<class T>
110 
111 template<class T>
112 Ostream& operator<<(Ostream& os, const CircularBuffer<T>& rhs);
113 
114 
115 /*---------------------------------------------------------------------------*\
116  Class CircularBuffer Declaration
117 \*---------------------------------------------------------------------------*/
118 
119 template<class T>
120 class CircularBuffer
121 {
122  // Private Data
123 
124  //- The allocated buffer storage
125  List<T> storage_;
126 
127  //- The first addressable element
128  label begin_;
129 
130  //- One past last addressable element
131  label end_;
132 
133 
134  // Private Member Functions
135 
136  //- Map the logical location to the buffer location
137  inline label toGlobal(const label i) const;
138 
139  //- Length of array one
140  inline label size_one() const noexcept;
141 
142  //- Length of array two
143  inline label size_two() const noexcept;
144 
145  //- Reserve allocation space for at least this size.
146  // Never shrinks the allocated size, use setCapacity() for that.
147  // The 'nocopy' option will not attempt to recover old content
148  void doReserve(const bool nocopy, const label len);
149 
150  //- Copy all list contents
151  template<class OtherListType>
152  inline void copyList(const OtherListType& rhs);
153 
154 
155 public:
156 
157  // STL type definitions
158 
159  //- The value type the list contains
160  typedef T value_type;
161 
162  //- The pointer type for non-const access to value_type items
163  typedef T* pointer;
164 
165  //- The pointer type for const access to value_type items
166  typedef const T* const_pointer;
167 
168  //- The type used for storing into value_type objects
169  typedef T& reference;
170 
171  //- The type used for reading from constant value_type objects
172  typedef const T& const_reference;
173 
174  //- The type to represent the size of a buffer
175  typedef label size_type;
176 
177  //- The difference between iterator objects
178  typedef label difference_type;
180  //- Forward iterator with const access
181  class const_iterator;
182 
183 
184  // Constructors
185 
186  //- Default construct, empty buffer without allocation
187  inline constexpr CircularBuffer() noexcept;
188 
189  //- Construct an empty buffer with given reserve size
190  inline explicit CircularBuffer(const label len);
191 
192  //- Copy construct
193  inline CircularBuffer(const CircularBuffer<T>& list);
195  //- Move construct
196  inline CircularBuffer(CircularBuffer<T>&& list);
197 
198  //- Construct from Istream - uses readList
199  explicit CircularBuffer(Istream& is);
200 
201 
202  // Member Functions
203 
204  // Characteristics
205 
206  //- Lower capacity limit
207  static constexpr label min_size() noexcept { return 16; }
208 
209  //- Size of the underlying storage.
210  inline label capacity() const noexcept;
211 
212  //- Empty or exhausted buffer
213  inline bool empty() const noexcept;
214 
215  //- The current number of buffer items
216  inline label size() const noexcept;
217 
218 
219  // Internal Access
220 
221  //- The nominal space available to fill.
222  //- Subtract 1 for the number to append before re-balancing is needed.
223  inline label space() const noexcept;
224 
225  //- The addressing range covered by array_one()
226  inline labelRange range_one() const noexcept;
227 
228  //- The addressing range covered by array_two()
229  inline labelRange range_two() const noexcept;
230 
231  //- The contents of the first internal array
232  SubList<T> array_one();
233 
234  //- The contents of the second internal array
235  SubList<T> array_two();
236 
237  //- The contents of the first internal array
238  const SubList<T> array_one() const;
239 
240  //- The contents of the second internal array
241  const SubList<T> array_two() const;
242 
243 
244  // Access
245 
246  //- Access the first element (front). Requires !empty().
247  T& front();
248 
249  //- Access the last element (back). Requires !empty().
250  T& back();
251 
252  //- Const access to the first element (front). Requires !empty().
253  const T& front() const;
254 
255  //- Const access to the last element (back). Requires !empty().
256  const T& back() const;
257 
258 
259  // Sizing
260 
261  //- Reserve allocation space for at least this size, allocating new
262  //- space if required and \em retaining old content.
263  // Never shrinks.
264  inline void reserve(const label len);
265 
266  //- Reserve allocation space for at least this size, allocating new
267  //- space if required \em without retaining old content.
268  // Never shrinks.
269  inline void reserve_nocopy(const label len);
270 
271  //- Clear the addressed buffer, does not change allocation
272  inline void clear() noexcept;
273 
274  //- Clear the buffer and delete storage.
275  inline void clearStorage();
276 
277  //- Swap content, independent of sizing parameter
278  inline void swap(CircularBuffer<T>& other);
279 
280 
281  // Search
282 
283  //- True if the value is contained in the list.
284  inline bool contains(const T& val) const;
285 
286  //- Is the value contained in the list?
287  // \param val The value to search for
288  // \param pos The first position to examine (no-op if -ve)
289  // \return true if found.
290  inline bool contains(const T& val, label pos) const;
291 
292  //- Find index of the first occurrence of the value.
293  // Any occurrences before the start pos are ignored.
294  // Linear search.
295  // \return position in list or -1 if not found.
296  label find(const T& val, label pos = 0) const;
297 
298 
299  // Stack-like Operations
300 
301  //- Copy prepend an element to the front of the buffer
302  inline void push_front(const T& val);
303 
304  //- Move prepend an element to the front of the buffer
305  inline void push_front(T&& val);
306 
307  //- Construct an element at the front of the buffer,
308  //- return reference to the new element
309  template<class... Args>
310  inline T& emplace_front(Args&&... args);
311 
312  //- Copy append an element to the end of the buffer
313  inline void push_back(const T& val);
314 
315  //- Move append an element to the end of the buffer
316  inline void push_back(T&& val);
317 
318  //- Construct an element at the end of the buffer,
319  //- return reference to the new element
320  template<class... Args>
321  inline T& emplace_back(Args&&... args);
322 
323  //- Shrink by moving the front of the buffer 1 or more times
324  inline void pop_front(label n = 1);
325 
326  //- Shrink by moving the end of the buffer 1 or more times
327  inline void pop_back(label n = 1);
328 
329  //- Copy append multiple elements the end of the buffer
330  inline void push_back(const UList<T>& list);
331 
332  //- Copy append IndirectList elements the end of the buffer
333  template<class Addr>
334  inline void push_back(const IndirectListBase<T, Addr>& list);
335 
336  //- Append an element if not already in the buffer.
337  // \return the change in the buffer length
338  inline label push_uniq(const T& val);
339 
340 
341  // Other Operations
342 
343  //- Return a copy of the buffer flattened into a single List.
344  //- Use sparingly!
345  List<T> list() const;
346 
347  //- Reverse the buffer order, swapping elements
348  void reverse();
349 
350 
351  // Member Operators
352 
353  //- Non-const access to an element in the list.
354  // The index is allowed to wrap in both directions
355  inline T& operator[](const label i);
356 
357  //- Const access to an element in the list
358  // The index is allowed to wrap in both directions
359  inline const T& operator[](const label i) const;
360 
361  //- Copy construct
362  inline void operator=(const CircularBuffer<T>& list);
363 
364  //- Move construct
365  inline void operator=(CircularBuffer<T>&& list);
366 
367  //- Assign all addressed elements to the given value
368  inline void operator=(const T& val);
369 
370  //- Assignment of all entries to zero
371  inline void operator=(Foam::zero);
372 
373  //- Deep copy values from a list of the addressed elements
374  inline void operator=(const UList<T>& rhs);
375 
376  //- Deep copy values from a list of the addressed elements
377  template<class AnyAddr>
378  inline void operator=(const IndirectListBase<T, AnyAddr>& rhs);
379 
380 
381  // IOstream Operators
382 
383  //- Print information
384  Ostream& info(Ostream& os) const;
385 
386  //- Read buffer contents from Istream.
387  Istream& readList(Istream& is);
388 
389  //- Write buffer contents with line-breaks in ASCII
390  //- when length exceeds shortLen.
391  // Using '0' suppresses line-breaks entirely.
392  Ostream& writeList(Ostream& os, const label shortLen=0) const;
393 
394  //- Use the readList() method to read contents from Istream.
395  friend Istream& operator>> <T>
396  (
397  Istream& is,
399  );
400 
401  //- Write to Ostream
402  friend Ostream& operator<< <T>
403  (
404  Ostream& os,
405  const CircularBuffer<T>& list
406  );
407 
408 
409  // Iterators
410 
411  //- A simple forward const iterator for a circular buffer
412  class const_iterator
413  {
414  const CircularBuffer<T>* container_;
415  label iter_;
416 
417  public:
418 
419  using difference_type = label;
420  using value_type = const T;
421  using pointer = const T*;
422  using reference = const T&;
423  using iterator_category = std::forward_iterator_tag;
424 
425  const_iterator(const const_iterator&) = default;
426  const_iterator& operator=(const const_iterator&) = default;
427 
428  const_iterator
429  (
430  const CircularBuffer<T>* buffer,
431  label i
432  )
433  :
434  container_(buffer),
435  iter_(i)
436  {}
437 
438  reference operator*() const
439  {
440  return (*container_)[iter_];
441  }
442 
443  const_iterator& operator++()
444  {
445  ++iter_;
446  return *this;
447  }
448 
449  const_iterator operator++(int)
450  {
451  auto old(*this);
452  ++iter_;
453  return old;
454  }
455 
456  bool operator==(const const_iterator& rhs) const
457  {
458  return iter_ == rhs.iter_;
459  }
460 
461  bool operator!=(const const_iterator& rhs) const
462  {
463  return iter_ != rhs.iter_;
464  }
465  };
466 
467 
468  // Iterator (const)
469 
470  //- Return a const_iterator at begin of buffer
471  inline const_iterator cbegin() const
472  {
473  return const_iterator(this, 0);
474  }
475 
476  //- Return a const_iterator at end of buffer
477  inline const_iterator cend() const
478  {
479  return const_iterator(this, this->size());
480  }
481 
482  //- Return a const_iterator at begin of buffer
483  inline const_iterator begin() const { return cbegin(); }
484 
485  //- Return a const_iterator at end of buffer
486  inline const_iterator end() const { return cend(); }
487 };
488 
489 
490 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
491 
492 //- Read buffer contents from Istream
493 template<class T>
494 Istream& operator>>(Istream& is, CircularBuffer<T>& rhs)
495 {
496  return rhs.readList(is);
497 }
498 
499 
500 //- Write buffer contents to Ostream,
501 //- as per CircularBuffer::writeList() with default length.
502 template<class T>
503 Ostream& operator<<(Ostream& os, const CircularBuffer<T>& rhs)
504 {
505  return rhs.writeList(os);
506 }
507 
508 
509 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
510 
511 } // End namespace Foam
512 
513 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
514 
515 #include "CircularBufferI.H"
516 
517 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
518 
519 #ifdef NoRepository
520  #include "CircularBuffer.C"
521  #include "CircularBufferIO.C"
522 #endif
523 
524 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
525 
526 #endif
527 
528 // ************************************************************************* //
void swap(CircularBuffer< T > &other)
Swap content, independent of sizing parameter.
Ostream & writeList(Ostream &os, const label shortLen=0) const
Write buffer contents with line-breaks in ASCII when length exceeds shortLen.
label size_type
The type to represent the size of a buffer.
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.
label difference_type
The difference between iterator objects.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:56
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:63
void clear() noexcept
Clear the addressed buffer, does not change allocation.
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
void push_front(const T &val)
Copy prepend an element to the front of the buffer.
const T & const_reference
The type used for reading from constant value_type objects.
const_iterator end() const
Return a const_iterator at end of 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...
const_iterator cend() const
Return a const_iterator at end of buffer.
const_iterator begin() const
Return a const_iterator at begin of buffer.
bool empty() const noexcept
Empty or exhausted buffer.
const_iterator cbegin() const
Return a const_iterator at begin of buffer.
void rhs(fvMatrix< typename Expr::value_type > &m, const Expr &expression)
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.
dimensionedScalar pos(const dimensionedScalar &ds)
Istream & readList(Istream &is)
Read buffer contents from Istream.
List< T > list() const
Return a copy of the buffer flattened into a single List. Use sparingly!
A non-owning sub-view of a List (allocated or unallocated storage).
Definition: SubList.H:44
tmp< faMatrix< Type > > operator*(const areaScalarField::Internal &, const faMatrix< Type > &)
A simple list of objects of type <T> that is intended to be used as a circular buffer (eg...
Istream & operator>>(Istream &, directionInfo &)
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()
T & emplace_back(Args &&... args)
Construct an element at the end of the buffer, return reference to the new element.
friend Ostream & operator(Ostream &os, const CircularBuffer< T > &list)
Write to Ostream.
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
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
const direction noexcept
Definition: scalarImpl.H:265
T & front()
Access the first element (front). Requires !empty().
static constexpr label min_size() noexcept
Lower capacity limit.
T & reference
The type used for storing into value_type objects.
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.
T * pointer
The pointer type for non-const access to value_type items.
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.
const T * const_pointer
The pointer type for const access to value_type items.
bool operator!=(const eddy &a, const eddy &b)
Definition: eddy.H:297
tmp< faMatrix< Type > > operator==(const faMatrix< Type > &, const faMatrix< Type > &)
Ostream & info(Ostream &os) const
Print information.
T value_type
The value type the list contains.
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.
void reverse()
Reverse the buffer order, swapping elements.
label find(const T &val, label pos=0) const
Find index of the first occurrence of the value.
Namespace for OpenFOAM.
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...