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 first internal array
236  SubList<T> array_two();
237 
238  //- The contents of the second 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 
246  // Access
247 
248  //- Access the first element (front). Requires !empty().
249  T& front();
250 
251  //- Access the last element (back). Requires !empty().
252  T& back();
253 
254  //- Const access to the first element (front). Requires !empty().
255  const T& front() const;
256 
257  //- Const access to the last element (back). Requires !empty().
258  const T& back() const;
259 
260 
261  // Sizing
262 
263  //- Reserve allocation space for at least this size, allocating new
264  //- space if required and \em retaining old content.
265  // Never shrinks.
266  inline void reserve(const label len);
267 
268  //- Reserve allocation space for at least this size, allocating new
269  //- space if required \em without retaining old content.
270  // Never shrinks.
271  inline void reserve_nocopy(const label len);
272 
273  //- Clear the addressed buffer, does not change allocation
274  inline void clear() noexcept;
275 
276  //- Clear the buffer and delete storage.
277  inline void clearStorage();
278 
279  //- Swap content, independent of sizing parameter
280  inline void swap(CircularBuffer<T>& other);
281 
282 
283  // Search
284 
285  //- Find index of the first occurrence of the value.
286  // Any occurrences before the start pos are ignored.
287  // Linear search.
288  // \return position in list or -1 if not found.
289  label find(const T& val, label pos = 0) const;
290 
291  //- Is the value contained in the list?
292  // Linear search from start pos until the end of the list.
293  // Any occurrences before the start pos are ignored.
294  // \return true if found.
295  inline bool contains(const T& val, label pos = 0) const;
296 
297 
298  // Stack-like Operations
299 
300  //- Copy prepend an element to the front of the buffer
301  inline void push_front(const T& val);
302 
303  //- Move prepend an element to the front of the buffer
304  inline void push_front(T&& val);
305 
306  //- Copy append an element to the end of the buffer
307  inline void push_back(const T& val);
308 
309  //- Move Append an element to the end of the buffer
310  inline void push_back(T&& val);
311 
312  //- Shrink by moving the front of the buffer 1 or more times
313  inline void pop_front(label n = 1);
314 
315  //- Shrink by moving the end of the buffer 1 or more times
316  inline void pop_back(label n = 1);
317 
318  //- Copy append multiple elements the end of the buffer
319  inline void push_back(const UList<T>& list);
320 
321  //- Copy append IndirectList elements the end of the buffer
322  template<class Addr>
323  inline void push_back(const IndirectListBase<T, Addr>& list);
324 
325  //- Append an element if not already in the buffer.
326  // \return the change in the buffer length
327  inline label push_uniq(const T& val);
328 
329 
330  // Other Operations
331 
332  //- Return a copy of the buffer flattened into a single List.
333  //- Use sparingly!
334  List<T> list() const;
335 
336  //- Reverse the buffer order, swapping elements
337  void reverse();
338 
339 
340  // Member Operators
341 
342  //- Return the buffer flattened as a single List. Use sparingly!
343  List<T> operator()() const { return this->list(); }
344 
345  //- Non-const access to an element in the list.
346  // The index is allowed to wrap in both directions
347  inline T& operator[](const label i);
348 
349  //- Const access to an element in the list
350  // The index is allowed to wrap in both directions
351  inline const T& operator[](const label i) const;
352 
353  //- Copy construct
354  inline void operator=(const CircularBuffer<T>& list);
355 
356  //- Move construct
357  inline void operator=(CircularBuffer<T>&& list);
358 
359  //- Assign all addressed elements to the given value
360  inline void operator=(const T& val);
361 
362  //- Assignment of all entries to zero
363  inline void operator=(const Foam::zero);
364 
365  //- Deep copy values from a list of the addressed elements
366  inline void operator=(const UList<T>& rhs);
367 
368  //- Deep copy values from a list of the addressed elements
369  template<class AnyAddr>
370  inline void operator=(const IndirectListBase<T, AnyAddr>& rhs);
371 
372 
373  // IOstream Operators
374 
375  //- Print information
376  Ostream& info(Ostream& os) const;
377 
378  //- Read buffer contents from Istream.
379  Istream& readList(Istream& is);
380 
381  //- Write buffer contents with line-breaks in ASCII
382  //- when length exceeds shortLen.
383  // Using '0' suppresses line-breaks entirely.
384  Ostream& writeList(Ostream& os, const label shortLen=0) const;
385 
386  //- Use the readList() method to read contents from Istream.
387  friend Istream& operator>> <T>
388  (
389  Istream& is,
391  );
392 
393  //- Write to Ostream
394  friend Ostream& operator<< <T>
395  (
396  Ostream& os,
397  const CircularBuffer<T>& list
398  );
399 
400 
401  // Iterators
402 
403  //- A simple forward const iterator for a circular buffer
404  class const_iterator
405  {
406  const CircularBuffer<T>* container_;
407  label iter_;
408 
409  public:
410 
411  using difference_type = label;
412  using value_type = const T;
413  using pointer = const T*;
414  using reference = const T&;
415  using iterator_category = std::forward_iterator_tag;
416 
417  const_iterator(const const_iterator&) = default;
418  const_iterator& operator=(const const_iterator&) = default;
419 
421  (
422  const CircularBuffer<T>* buffer,
423  label i
424  )
425  :
426  container_(buffer),
427  iter_(i)
428  {}
429 
430  reference operator*() const
431  {
432  return (*container_)[iter_];
433  }
434 
436  {
437  ++iter_;
438  return *this;
439  }
440 
442  {
443  auto old(*this);
444  ++iter_;
445  return old;
446  }
447 
448  bool operator==(const const_iterator& rhs) const
449  {
450  return iter_ == rhs.iter_;
451  }
452 
453  bool operator!=(const const_iterator& rhs) const
454  {
455  return iter_ != rhs.iter_;
456  }
457  };
458 
459 
460  // Iterator (const)
461 
462  //- Return a const_iterator at begin of buffer
463  inline const_iterator cbegin() const
464  {
465  return const_iterator(this, 0);
466  }
467 
468  //- Return a const_iterator at end of buffer
469  inline const_iterator cend() const
470  {
471  return const_iterator(this, this->size());
472  }
473 
474  //- Return a const_iterator at begin of buffer
475  inline const_iterator begin() const { return cbegin(); }
476 
477  //- Return a const_iterator at end of buffer
478  inline const_iterator end() const { return cend(); }
479 
480 
481  // Housekeeping
482 
483  //- Same as contains()
484  bool found(const T& val, label pos = 0) const
485  {
486  return contains(val, pos);
487  }
488 
489  //- Access the first element (front). Requires !empty().
490  //FOAM_DEPRECATED_FOR(2022-10, "front()")
491  T& first() { return front(); }
492 
493  //- Access the first element (front). Requires !empty().
494  //FOAM_DEPRECATED_FOR(2022-10, "front()")
495  const T& first() const { return front(); }
496 
497  //- Access the last element (back). Requires !empty().
498  //FOAM_DEPRECATED_FOR(2022-10, "back()")
499  T& last() { return back(); }
500 
501  //- Access the last element (back). Requires !empty().
502  //FOAM_DEPRECATED_FOR(2022-10, "back()")
503  const T& last() const { return back(); }
504 
505  //- Copy append an element to the end of the buffer
506  //FOAM_DEPRECATED_FOR(2022-10, "push_back()")
507  void append(const T& val) { this->push_back(val); }
508 
509  //- Move append an element to the end of the buffer
510  //FOAM_DEPRECATED_FOR(2022-10, "push_back()")
511  void append(T&& val) { this->push_back(std::move(val)); }
512 
513  //- Copy append multiple elements the end of the buffer
514  //FOAM_DEPRECATED_FOR(2022-10, "push_back()")
515  void append(const UList<T>& list) { this->push_back(list); }
516 
517  //- Append an element if not already in the buffer.
518  //FOAM_DEPRECATED_FOR(2022-10, "push_uniq()")
519  label appendUniq(const T& val) { return this->push_uniq(val); }
520 };
521 
522 
523 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
524 
525 //- Read buffer contents from Istream
526 template<class T>
527 Istream& operator>>(Istream& is, CircularBuffer<T>& rhs)
528 {
529  return rhs.readList(is);
530 }
531 
532 
533 //- Write buffer contents to Ostream,
534 //- as per CircularBuffer::writeList() with default length.
535 template<class T>
536 Ostream& operator<<(Ostream& os, const CircularBuffer<T>& rhs)
537 {
538  return rhs.writeList(os);
539 }
540 
541 
542 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
543 
544 } // End namespace Foam
545 
546 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
547 
548 #include "CircularBufferI.H"
549 
550 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
551 
552 #ifdef NoRepository
553  #include "CircularBuffer.C"
555 #endif
557 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
558 
559 #endif
560 
561 // ************************************************************************* //
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.
const_iterator(const const_iterator &)=default
label size_type
The type to represent the size of a buffer.
std::forward_iterator_tag iterator_category
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:51
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.
bool found(const T &val, label pos=0) const
Same as contains()
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 contains(const T &val, label pos=0) const
Is the value contained in the list?
bool empty() const noexcept
Empty or exhausted buffer.
const_iterator cbegin() const
Return a const_iterator at begin of buffer.
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)
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
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.
const_iterator & operator=(const const_iterator &)=default
labelRange range_one() const noexcept
The addressing range covered by array_one()
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:99
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:55
const direction noexcept
Definition: Scalar.H:258
OBJstream os(runTime.globalPath()/outputName)
void append(const T &val)
Copy append an element to the end of the buffer.
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)
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 & last()
Access the last element (back). Requires !empty().
A simple forward const iterator for a circular buffer.
T & first()
Access the first element (front). Requires !empty().
T * pointer
The pointer type for non-const access to value_type items.
bool operator!=(const const_iterator &rhs) const
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 const_iterator &rhs) const
Ostream & info(Ostream &os) const
Print information.
T value_type
The value type the list contains.
label capacity() const noexcept
Size of the underlying storage.
SubList< T > array_two()
The contents of the first 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.
label appendUniq(const T &val)
Append an element if not already in the buffer.
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...