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 "labelRange.H"
98 #include "List.H"
99 #include "SubList.H"
100 
101 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
103 namespace Foam
104 {
105 
106 // Forward Declarations
107 template<class T> class CircularBuffer;
108 
109 template<class T>
111 
112 template<class T>
113 Ostream& operator<<(Ostream& os, const CircularBuffer<T>& rhs);
114 
115 
116 /*---------------------------------------------------------------------------*\
117  Class CircularBuffer Declaration
118 \*---------------------------------------------------------------------------*/
119 
120 template<class T>
121 class CircularBuffer
122 {
123  // Private Data
124 
125  //- The allocated buffer storage
126  List<T> storage_;
127 
128  //- The first addressable element
129  label begin_;
130 
131  //- One past last addressable element
132  label end_;
133 
134 
135  // Private Member Functions
136 
137  //- Map the logical location to the buffer location
138  inline label toGlobal(const label i) const;
139 
140  //- Length of array one
141  inline label size_one() const noexcept;
142 
143  //- Length of array two
144  inline label size_two() const noexcept;
145 
146  //- Reserve allocation space for at least this size.
147  // Never shrinks the allocated size, use setCapacity() for that.
148  // The 'nocopy' option will not attempt to recover old content
149  void doReserve(const bool nocopy, const label len);
150 
151  //- Copy all list contents
152  template<class OtherListType>
153  inline void copyList(const OtherListType& rhs);
154 
155 
156 public:
157 
158  // STL type definitions
159 
160  //- The value type the list contains
161  typedef T value_type;
162 
163  //- The pointer type for non-const access to value_type items
164  typedef T* pointer;
165 
166  //- The pointer type for const access to value_type items
167  typedef const T* const_pointer;
168 
169  //- The type used for storing into value_type objects
170  typedef T& reference;
171 
172  //- The type used for reading from constant value_type objects
173  typedef const T& const_reference;
174 
175  //- The type to represent the size of a buffer
176  typedef label size_type;
177 
178  //- The difference between iterator objects
179  typedef label difference_type;
181  //- Forward iterator with const access
182  class const_iterator;
183 
184 
185  // Constructors
186 
187  //- Default construct, empty buffer without allocation
188  inline constexpr CircularBuffer() noexcept;
189 
190  //- Construct an empty buffer with given reserve size
191  inline explicit CircularBuffer(const label len);
192 
193  //- Copy construct
194  inline CircularBuffer(const CircularBuffer<T>& list);
196  //- Move construct
197  inline CircularBuffer(CircularBuffer<T>&& list);
198 
199  //- Construct from Istream - uses readList
200  explicit CircularBuffer(Istream& is);
201 
202 
203  // Member Functions
204 
205  // Characteristics
206 
207  //- Lower capacity limit
208  static constexpr label min_size() noexcept { return 16; }
209 
210  //- Size of the underlying storage.
211  inline label capacity() const noexcept;
212 
213  //- Empty or exhausted buffer
214  inline bool empty() const noexcept;
215 
216  //- The current number of buffer items
217  inline label size() const noexcept;
218 
219 
220  // Internal Access
221 
222  //- The nominal space available to fill.
223  //- Subtract 1 for the number to append before re-balancing is needed.
224  inline label space() const noexcept;
225 
226  //- The addressing range covered by array_one()
227  inline labelRange range_one() const noexcept;
228 
229  //- The addressing range covered by array_two()
230  inline labelRange range_two() const noexcept;
231 
232  //- The contents of the first internal array
233  SubList<T> array_one();
234 
235  //- The contents of the second internal array
236  SubList<T> array_two();
237 
238  //- The contents of the first internal array
239  const SubList<T> array_one() const;
240 
241  //- The contents of the second internal array
242  const SubList<T> array_two() const;
243 
244 
245  // Access
246 
247  //- Access the first element (front). Requires !empty().
248  T& front();
249 
250  //- Access the last element (back). Requires !empty().
251  T& back();
252 
253  //- Const access to the first element (front). Requires !empty().
254  const T& front() const;
255 
256  //- Const access to the last element (back). Requires !empty().
257  const T& back() const;
258 
259 
260  // Sizing
261 
262  //- Reserve allocation space for at least this size, allocating new
263  //- space if required and \em retaining old content.
264  // Never shrinks.
265  inline void reserve(const label len);
266 
267  //- Reserve allocation space for at least this size, allocating new
268  //- space if required \em without retaining old content.
269  // Never shrinks.
270  inline void reserve_nocopy(const label len);
271 
272  //- Clear the addressed buffer, does not change allocation
273  inline void clear() noexcept;
274 
275  //- Clear the buffer and delete storage.
276  inline void clearStorage();
277 
278  //- Swap content, independent of sizing parameter
279  inline void swap(CircularBuffer<T>& other);
280 
281 
282  // Search
283 
284  //- True if the value is contained in the list.
285  inline bool contains(const T& val) const;
286 
287  //- Is the value contained in the list?
288  // \param val The value to search for
289  // \param pos The first position to examine (no-op if -ve)
290  // \return true if found.
291  inline bool contains(const T& val, label pos) const;
292 
293  //- Find index of the first occurrence of the value.
294  // Any occurrences before the start pos are ignored.
295  // Linear search.
296  // \return position in list or -1 if not found.
297  label find(const T& val, label pos = 0) const;
298 
299 
300  // Stack-like Operations
301 
302  //- Copy prepend an element to the front of the buffer
303  inline void push_front(const T& val);
304 
305  //- Move prepend an element to the front of the buffer
306  inline void push_front(T&& val);
307 
308  //- Construct an element at the front of the buffer,
309  //- return reference to the new element
310  template<class... Args>
311  inline T& emplace_front(Args&&... args);
312 
313  //- Copy append an element to the end of the buffer
314  inline void push_back(const T& val);
315 
316  //- Move append an element to the end of the buffer
317  inline void push_back(T&& val);
318 
319  //- Construct an element at the end of the buffer,
320  //- return reference to the new element
321  template<class... Args>
322  inline T& emplace_back(Args&&... args);
323 
324  //- Shrink by moving the front of the buffer 1 or more times
325  inline void pop_front(label n = 1);
326 
327  //- Shrink by moving the end of the buffer 1 or more times
328  inline void pop_back(label n = 1);
329 
330  //- Copy append multiple elements the end of the buffer
331  inline void push_back(const UList<T>& list);
332 
333  //- Copy append IndirectList elements the end of the buffer
334  template<class Addr>
335  inline void push_back(const IndirectListBase<T, Addr>& list);
336 
337  //- Append an element if not already in the buffer.
338  // \return the change in the buffer length
339  inline label push_uniq(const T& val);
340 
341 
342  // Other Operations
343 
344  //- Return a copy of the buffer flattened into a single List.
345  //- Use sparingly!
346  List<T> list() const;
347 
348  //- Reverse the buffer order, swapping elements
349  void reverse();
350 
351 
352  // Member Operators
353 
354  //- Non-const access to an element in the list.
355  // The index is allowed to wrap in both directions
356  inline T& operator[](const label i);
357 
358  //- Const access to an element in the list
359  // The index is allowed to wrap in both directions
360  inline const T& operator[](const label i) const;
361 
362  //- Copy construct
363  inline void operator=(const CircularBuffer<T>& list);
364 
365  //- Move construct
366  inline void operator=(CircularBuffer<T>&& list);
367 
368  //- Assign all addressed elements to the given value
369  inline void operator=(const T& val);
370 
371  //- Assignment of all entries to zero
372  inline void operator=(const Foam::zero);
373 
374  //- Deep copy values from a list of the addressed elements
375  inline void operator=(const UList<T>& rhs);
376 
377  //- Deep copy values from a list of the addressed elements
378  template<class AnyAddr>
379  inline void operator=(const IndirectListBase<T, AnyAddr>& rhs);
380 
381 
382  // IOstream Operators
383 
384  //- Print information
385  Ostream& info(Ostream& os) const;
386 
387  //- Read buffer contents from Istream.
388  Istream& readList(Istream& is);
389 
390  //- Write buffer contents with line-breaks in ASCII
391  //- when length exceeds shortLen.
392  // Using '0' suppresses line-breaks entirely.
393  Ostream& writeList(Ostream& os, const label shortLen=0) const;
394 
395  //- Use the readList() method to read contents from Istream.
396  friend Istream& operator>> <T>
397  (
398  Istream& is,
400  );
401 
402  //- Write to Ostream
403  friend Ostream& operator<< <T>
404  (
405  Ostream& os,
406  const CircularBuffer<T>& list
407  );
408 
409 
410  // Iterators
411 
412  //- A simple forward const iterator for a circular buffer
413  class const_iterator
414  {
415  const CircularBuffer<T>* container_;
416  label iter_;
417 
418  public:
419 
420  using difference_type = label;
421  using value_type = const T;
422  using pointer = const T*;
423  using reference = const T&;
424  using iterator_category = std::forward_iterator_tag;
425 
426  const_iterator(const const_iterator&) = default;
427  const_iterator& operator=(const const_iterator&) = default;
428 
430  (
431  const CircularBuffer<T>* buffer,
432  label i
433  )
434  :
435  container_(buffer),
436  iter_(i)
437  {}
438 
439  reference operator*() const
440  {
441  return (*container_)[iter_];
442  }
443 
444  const_iterator& operator++()
445  {
446  ++iter_;
447  return *this;
448  }
449 
450  const_iterator operator++(int)
451  {
452  auto old(*this);
453  ++iter_;
454  return old;
455  }
456 
457  bool operator==(const const_iterator& rhs) const
458  {
459  return iter_ == rhs.iter_;
460  }
461 
462  bool operator!=(const const_iterator& rhs) const
463  {
464  return iter_ != rhs.iter_;
465  }
466  };
467 
468 
469  // Iterator (const)
470 
471  //- Return a const_iterator at begin of buffer
472  inline const_iterator cbegin() const
473  {
474  return const_iterator(this, 0);
475  }
476 
477  //- Return a const_iterator at end of buffer
478  inline const_iterator cend() const
479  {
480  return const_iterator(this, this->size());
481  }
482 
483  //- Return a const_iterator at begin of buffer
484  inline const_iterator begin() const { return cbegin(); }
485 
486  //- Return a const_iterator at end of buffer
487  inline const_iterator end() const { return cend(); }
488 };
489 
490 
491 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
492 
493 //- Read buffer contents from Istream
494 template<class T>
495 Istream& operator>>(Istream& is, CircularBuffer<T>& rhs)
496 {
497  return rhs.readList(is);
498 }
499 
500 
501 //- Write buffer contents to Ostream,
502 //- as per CircularBuffer::writeList() with default length.
503 template<class T>
504 Ostream& operator<<(Ostream& os, const CircularBuffer<T>& rhs)
505 {
506  return rhs.writeList(os);
507 }
508 
509 
510 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
511 
512 } // End namespace Foam
513 
514 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
515 
516 #include "CircularBufferI.H"
517 
518 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
519 
520 #ifdef NoRepository
521  #include "CircularBuffer.C"
522  #include "CircularBufferIO.C"
523 #endif
524 
525 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
526 
527 #endif
528 
529 // ************************************************************************* //
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:52
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.
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 List obtained as a section of another List.
Definition: SubList.H:50
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: Scalar.H:258
OBJstream os(runTime.globalPath()/outputName)
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.
A simple forward const iterator for a circular buffer.
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...