ENH: add CircularBuffer container
This commit is contained in:
parent
079d5f2771
commit
bf46b589cf
3
applications/test/CircularBuffer/Make/files
Normal file
3
applications/test/CircularBuffer/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
Test-CircularBuffer.C
|
||||
|
||||
EXE = $(FOAM_USER_APPBIN)/Test-CircularBuffer
|
2
applications/test/CircularBuffer/Make/options
Normal file
2
applications/test/CircularBuffer/Make/options
Normal file
@ -0,0 +1,2 @@
|
||||
/* EXE_INC = */
|
||||
/* EXE_LIBS = */
|
136
applications/test/CircularBuffer/Test-CircularBuffer.C
Normal file
136
applications/test/CircularBuffer/Test-CircularBuffer.C
Normal file
@ -0,0 +1,136 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Application
|
||||
Test-CircularBuffer
|
||||
|
||||
Description
|
||||
Basic tests for CircularBuffer behaviour and characteristics
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "ListOps.H"
|
||||
#include "CircularBuffer.H"
|
||||
#include "StringStream.H"
|
||||
#include "FlatOutput.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
template<class T>
|
||||
inline Ostream& report
|
||||
(
|
||||
const CircularBuffer<T>& buf,
|
||||
bool debugOutput = true
|
||||
)
|
||||
{
|
||||
buf.writeList(Info, 0);
|
||||
if (debugOutput)
|
||||
{
|
||||
Info<< " : ";
|
||||
buf.info(Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< nl;
|
||||
}
|
||||
return Info;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
CircularBuffer<label> buf1(1); report(buf1);
|
||||
buf1.append(10); report(buf1);
|
||||
|
||||
Info<< buf1.range_one() << nl;
|
||||
|
||||
buf1.append(20); report(buf1);
|
||||
buf1.append(30); report(buf1);
|
||||
buf1.push_back(40); report(buf1);
|
||||
buf1.push_front(-50); report(buf1);
|
||||
buf1.append(60); report(buf1);
|
||||
buf1.append(labelList({70,80,90})); report(buf1);
|
||||
|
||||
Info<< nl << "access: " << buf1 << nl;
|
||||
|
||||
Info<< buf1[-12] << nl;
|
||||
|
||||
Info<< "found: " << buf1.found(40) << nl;
|
||||
buf1.appendUniq(100); report(buf1);
|
||||
|
||||
buf1 = Zero; report(buf1);
|
||||
|
||||
buf1 = 500; report(buf1);
|
||||
|
||||
while (buf1.size() > 2)
|
||||
{
|
||||
(void) buf1.pop_front();
|
||||
}
|
||||
report(buf1);
|
||||
|
||||
buf1.append(identity(5)); report(buf1);
|
||||
|
||||
buf1.info(Info);
|
||||
Info<< buf1 << nl;
|
||||
|
||||
CircularBuffer<label> buf2(15);
|
||||
report(buf2);
|
||||
|
||||
buf2 = std::move(buf1);
|
||||
Info<< "buf1: "; report(buf1);
|
||||
Info<< "buf2: "; report(buf2);
|
||||
|
||||
Info<< "for-range:";
|
||||
for (const label val : buf2)
|
||||
{
|
||||
Info<< ' ' << val;
|
||||
}
|
||||
Info<< endl;
|
||||
|
||||
{
|
||||
auto iter = buf2.cbegin();
|
||||
auto endIter = buf2.cend();
|
||||
|
||||
Info<< "iterated:";
|
||||
while (iter != endIter)
|
||||
{
|
||||
Info<< ' ' << *(++iter);
|
||||
}
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
Info<< "normal: " << flatOutput(buf2) << nl;
|
||||
buf2.reverse();
|
||||
Info<< "reverse: " << flatOutput(buf2) << nl;
|
||||
|
||||
Info<< nl << "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
143
src/OpenFOAM/containers/Buffers/CircularBuffer.C
Normal file
143
src/OpenFOAM/containers/Buffers/CircularBuffer.C
Normal file
@ -0,0 +1,143 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class T>
|
||||
void Foam::CircularBuffer<T>::doReserve
|
||||
(
|
||||
const bool nocopy,
|
||||
const label len
|
||||
)
|
||||
{
|
||||
if (storage_.size() < len)
|
||||
{
|
||||
// Increase capacity (doubling)
|
||||
const label newCapacity =
|
||||
max(min_size(), max(len+1, label(2*storage_.size())));
|
||||
|
||||
if (nocopy || empty())
|
||||
{
|
||||
// Simple - no content to preserve
|
||||
|
||||
clear(); // Reset begin/end
|
||||
storage_.resize_nocopy(newCapacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Preserve content
|
||||
const labelRange range1 = range_one();
|
||||
const labelRange range2 = range_two();
|
||||
|
||||
List<T> old(newCapacity);
|
||||
storage_.swap(old);
|
||||
begin_ = 0;
|
||||
end_ = 0;
|
||||
|
||||
for (const label i : range1)
|
||||
{
|
||||
storage_[end_++] = std::move(old[i]);
|
||||
}
|
||||
for (const label i : range2)
|
||||
{
|
||||
storage_[end_++] = std::move(old[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
template<class T>
|
||||
Foam::SubList<T> Foam::CircularBuffer<T>::array_one()
|
||||
{
|
||||
const label len = size_one();
|
||||
return (len ? storage_.slice(begin_, len) : SubList<T>());
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
Foam::SubList<T> Foam::CircularBuffer<T>::array_two()
|
||||
{
|
||||
const label len = size_two();
|
||||
return (len ? storage_.slice(0, len) : SubList<T>());
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
const Foam::SubList<T> Foam::CircularBuffer<T>::array_one() const
|
||||
{
|
||||
const label len = size_one();
|
||||
return (len ? storage_.slice(begin_, len) : SubList<T>());
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
const Foam::SubList<T> Foam::CircularBuffer<T>::array_two() const
|
||||
{
|
||||
const label len = size_two();
|
||||
return (len ? storage_.slice(0, len) : SubList<T>());
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
Foam::label Foam::CircularBuffer<T>::find(const T& val, label pos) const
|
||||
{
|
||||
label i = -1;
|
||||
|
||||
const auto list1 = this->array_one();
|
||||
|
||||
if (pos < list1.size())
|
||||
{
|
||||
i = list1.find(val, pos);
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
// Not found - search the second list
|
||||
return this->array_two().find(val, 0);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void Foam::CircularBuffer<T>::reverse()
|
||||
{
|
||||
const label n = this->size();
|
||||
const label nBy2 = n/2;
|
||||
|
||||
for (label i = 0; i < nBy2; ++i)
|
||||
{
|
||||
Foam::Swap(operator[](i), operator[](n-1-i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
518
src/OpenFOAM/containers/Buffers/CircularBuffer.H
Normal file
518
src/OpenFOAM/containers/Buffers/CircularBuffer.H
Normal file
@ -0,0 +1,518 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Class
|
||||
Foam::CircularBuffer
|
||||
|
||||
Description
|
||||
A simple list of objects of type \<T\> that is intended to be used
|
||||
as a circular buffer (eg, a FIFO) when the alloc/free overhead
|
||||
associated with a linked-list approach is to be avoided.
|
||||
|
||||
The internal storage is addressed by independent begin/end markers.
|
||||
- The %begin marker points to the \em front.
|
||||
- The %end marker is a one-past the \em back.
|
||||
.
|
||||
This results in a variety ofr different possible buffer states:
|
||||
-# \em empty (\em begin == \em end)
|
||||
|
||||
-# \em simple/linear (\em begin \< \em end) has no wrapping:
|
||||
\verbatim
|
||||
|.|.|.|a|b|c|d|.|.|.|
|
||||
beg ___^
|
||||
end ___________^
|
||||
\endverbatim
|
||||
|
||||
-# \em split (\em begin \> \em end):
|
||||
\verbatim
|
||||
|f|g|h|i|.|.|.|a|b|c|d|e|
|
||||
end _____^
|
||||
beg ___________^
|
||||
\endverbatim
|
||||
.
|
||||
|
||||
The methods range_one(), range_two() return the internal indexing and
|
||||
the methods array_one(), array_two() provide direct access to the
|
||||
internal contents.
|
||||
|
||||
When filling the buffer, the internal storage will be resized
|
||||
(doubling strategy) as required. When this occurs, the new list
|
||||
will be linearized with \em begin = 0.
|
||||
|
||||
Simultaneously when filling, the storage buffer will be over-allocated
|
||||
to avoid ambiguity when (\em begin == \em end), which represents an
|
||||
\em %empty buffer and not a \em %full buffer. Eg,
|
||||
\verbatim
|
||||
|c|d|.|a|b|
|
||||
end _^
|
||||
beg ___^
|
||||
\endverbatim
|
||||
after appending one more, it would be incorrect to simply fill
|
||||
the available space:
|
||||
\verbatim
|
||||
|c|d|e|a|b|
|
||||
end ___^ WRONG : would represent empty!
|
||||
beg ___^
|
||||
\endverbatim
|
||||
the storage is instead increased (doubled) and rebalanced before
|
||||
the append occurs (old capacity 5, new capacity 10):
|
||||
\verbatim
|
||||
|a|b|c|d|e|.|.|.|.|.|
|
||||
_^_ beg
|
||||
end _______^
|
||||
\endverbatim
|
||||
|
||||
SourceFiles
|
||||
CircularBuffer.C
|
||||
CircularBufferI.H
|
||||
CircularBufferIO.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef Foam_CircularBuffer_H
|
||||
#define Foam_CircularBuffer_H
|
||||
|
||||
#include "labelRange.H"
|
||||
#include "List.H"
|
||||
#include "SubList.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Forward Declarations
|
||||
template<class T> class CircularBuffer;
|
||||
|
||||
template<class T>
|
||||
Istream& operator>>(Istream& is, CircularBuffer<T>& list);
|
||||
|
||||
template<class T>
|
||||
Ostream& operator<<(Ostream& os, const CircularBuffer<T>& list);
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class CircularBuffer Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
template<class T>
|
||||
class CircularBuffer
|
||||
{
|
||||
// Private Data
|
||||
|
||||
//- The allocated buffer storage
|
||||
List<T> storage_;
|
||||
|
||||
//- The first readable element
|
||||
label begin_;
|
||||
|
||||
//- One past last writable element
|
||||
label end_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Map the logical location to the buffer location
|
||||
inline label toGlobal(const label i) const;
|
||||
|
||||
//- Length of array one
|
||||
inline label size_one() const noexcept;
|
||||
|
||||
//- Length of array two
|
||||
inline label size_two() const noexcept;
|
||||
|
||||
//- Reserve allocation space for at least this size.
|
||||
// Never shrinks the allocated size, use setCapacity() for that.
|
||||
// The 'nocopy' option will not attempt to recover old content
|
||||
void doReserve(const bool nocopy, const label len);
|
||||
|
||||
//- Copy all list contents
|
||||
template<class OtherListType>
|
||||
inline void copyList(const OtherListType& rhs);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// STL type definitions
|
||||
|
||||
//- The value type the list contains
|
||||
typedef T value_type;
|
||||
|
||||
//- The pointer type for non-const access to value_type items
|
||||
typedef T* pointer;
|
||||
|
||||
//- The pointer type for const access to value_type items
|
||||
typedef const T* const_pointer;
|
||||
|
||||
//- The type used for storing into value_type objects
|
||||
typedef T& reference;
|
||||
|
||||
//- The type used for reading from constant value_type objects
|
||||
typedef const T& const_reference;
|
||||
|
||||
//- The type to represent the size of a buffer
|
||||
typedef label size_type;
|
||||
|
||||
//- The difference between iterator objects
|
||||
typedef label difference_type;
|
||||
|
||||
//- Forward iterator with const access
|
||||
class const_iterator;
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Default construct, empty buffer without allocation
|
||||
inline constexpr CircularBuffer() noexcept;
|
||||
|
||||
//- Construct an empty buffer with given reserve size
|
||||
inline explicit CircularBuffer(const label len);
|
||||
|
||||
//- Copy construct
|
||||
inline CircularBuffer(const CircularBuffer<T>& list);
|
||||
|
||||
//- Move construct
|
||||
inline CircularBuffer(CircularBuffer<T>&& list);
|
||||
|
||||
//- Construct from Istream - uses readList
|
||||
explicit CircularBuffer(Istream& is);
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
// Characteristics
|
||||
|
||||
//- Lower capacity limit
|
||||
static constexpr label min_size() noexcept { return 16; }
|
||||
|
||||
//- Size of the underlying storage.
|
||||
inline label capacity() const noexcept;
|
||||
|
||||
//- Empty or exhausted buffer
|
||||
inline bool empty() const noexcept;
|
||||
|
||||
//- The current number of buffer items
|
||||
inline label size() const noexcept;
|
||||
|
||||
|
||||
// Internal Access
|
||||
|
||||
//- The nominal space available to fill.
|
||||
//- Subtract 1 for the number to append before re-balancing is needed.
|
||||
inline label space() const noexcept;
|
||||
|
||||
//- The addressing range covered by array_one()
|
||||
inline labelRange range_one() const noexcept;
|
||||
|
||||
//- The addressing range covered by array_two()
|
||||
inline labelRange range_two() const noexcept;
|
||||
|
||||
//- The contents of the first internal array
|
||||
SubList<T> array_one();
|
||||
|
||||
//- The contents of the first internal array
|
||||
SubList<T> array_two();
|
||||
|
||||
//- The contents of the second internal array
|
||||
const SubList<T> array_one() const;
|
||||
|
||||
//- The contents of the second internal array
|
||||
const SubList<T> array_two() const;
|
||||
|
||||
|
||||
|
||||
// Access
|
||||
|
||||
//- Access the first element (front). Requires !empty().
|
||||
T& first();
|
||||
|
||||
//- Access the last element (back). Requires !empty().
|
||||
T& last();
|
||||
|
||||
//- Const access to the first element (front). Requires !empty().
|
||||
const T& first() const;
|
||||
|
||||
//- Const access to the last element (back). Requires !empty().
|
||||
const T& last() const;
|
||||
|
||||
|
||||
// Sizing
|
||||
|
||||
//- Reserve allocation space for at least this size, allocating new
|
||||
//- space if required and \em retaining old content.
|
||||
// Never shrinks.
|
||||
inline void reserve(const label len);
|
||||
|
||||
//- Reserve allocation space for at least this size, allocating new
|
||||
//- space if required \em without retaining old content.
|
||||
// Never shrinks.
|
||||
inline void reserve_nocopy(const label len);
|
||||
|
||||
//- Clear the addressed buffer, does not change allocation
|
||||
inline void clear() noexcept;
|
||||
|
||||
//- Clear the buffer and delete storage.
|
||||
inline void clearStorage();
|
||||
|
||||
//- Swap content, independent of sizing parameter
|
||||
inline void swap(CircularBuffer<T>& other);
|
||||
|
||||
|
||||
// Search
|
||||
|
||||
//- Find index of the first occurrence of the value.
|
||||
// Any occurrences before the start pos are ignored.
|
||||
// Linear search.
|
||||
// \return position in list or -1 if not found.
|
||||
label find(const T& val, label pos = 0) const;
|
||||
|
||||
//- True if the value if found in the list.
|
||||
// Any occurrences before the start pos are ignored.
|
||||
// Linear search.
|
||||
// \return true if found.
|
||||
inline bool found(const T& val, label pos = 0) const;
|
||||
|
||||
|
||||
// Stack-like Operations
|
||||
|
||||
//- Copy prepend an element to the front of the buffer
|
||||
inline void push_front(const T& val);
|
||||
|
||||
//- Move prepend an element to the front of the buffer
|
||||
inline void push_front(T&& val);
|
||||
|
||||
//- Copy append an element to the end of the buffer
|
||||
inline void push_back(const T& val);
|
||||
|
||||
//- Move Append an element to the end of the buffer
|
||||
inline void push_back(T&& val);
|
||||
|
||||
//- Shrink by moving the front of the buffer 1 or more times
|
||||
inline void pop_front(label n = 1);
|
||||
|
||||
//- Shrink by moving the end of the buffer 1 or more times
|
||||
inline void pop_back(label n = 1);
|
||||
|
||||
//- Copy append an element to the end of the buffer
|
||||
void append(const T& val) { this->push_back(val); }
|
||||
|
||||
//- Move append an element to the end of the buffer
|
||||
void append(T&& val) { this->push_back(std::move(val)); }
|
||||
|
||||
//- Copy append multiple elements the end of the buffer
|
||||
inline void append(const UList<T>& list);
|
||||
|
||||
//- Copy append IndirectList elements the end of the buffer
|
||||
template<class Addr>
|
||||
inline void append(const IndirectListBase<T, Addr>& list);
|
||||
|
||||
//- Append an element if not already in the buffer.
|
||||
// \return the change in the buffer length
|
||||
inline label appendUniq(const T& val);
|
||||
|
||||
|
||||
// Other Operations
|
||||
|
||||
//- Reverse the buffer order, swapping elements
|
||||
void reverse();
|
||||
|
||||
|
||||
// Member Operators
|
||||
|
||||
//- Non-const access to an element in the list.
|
||||
// The index is allowed to wrap in both directions
|
||||
inline T& operator[](const label i);
|
||||
|
||||
//- Const access to an element in the list
|
||||
// The index is allowed to wrap in both directions
|
||||
inline const T& operator[](const label i) const;
|
||||
|
||||
//- Copy construct
|
||||
inline void operator=(const CircularBuffer<T>& list);
|
||||
|
||||
//- Move construct
|
||||
inline void operator=(CircularBuffer<T>&& list);
|
||||
|
||||
//- Assign all addressed elements to the given value
|
||||
inline void operator=(const T& val);
|
||||
|
||||
//- Assignment of all entries to zero
|
||||
inline void operator=(const Foam::zero);
|
||||
|
||||
//- Deep copy values from a list of the addressed elements
|
||||
inline void operator=(const UList<T>& rhs);
|
||||
|
||||
//- Deep copy values from a list of the addressed elements
|
||||
template<class AnyAddr>
|
||||
inline void operator=(const IndirectListBase<T, AnyAddr>& rhs);
|
||||
|
||||
|
||||
// IOstream Operators
|
||||
|
||||
//- Print information
|
||||
Ostream& info(Ostream& os) const;
|
||||
|
||||
//- Write List, with line-breaks in ASCII when length exceeds shortLen.
|
||||
// Using '0' suppresses line-breaks entirely.
|
||||
Istream& readList(Istream& is);
|
||||
|
||||
//- Write List, with line-breaks in ASCII when length exceeds shortLen.
|
||||
// Using '0' suppresses line-breaks entirely.
|
||||
Ostream& writeList(Ostream& os, const label shortLen=0) const;
|
||||
|
||||
//- Use the readList() method to read contents from Istream.
|
||||
friend Istream& operator>> <T>
|
||||
(
|
||||
Istream& is,
|
||||
CircularBuffer<T>& list
|
||||
);
|
||||
|
||||
//- Write to Ostream
|
||||
friend Ostream& operator<< <T>
|
||||
(
|
||||
Ostream& os,
|
||||
const CircularBuffer<T>& list
|
||||
);
|
||||
|
||||
|
||||
// Iterators
|
||||
|
||||
//- A simple forward const iterator for a circular buffer
|
||||
class const_iterator
|
||||
{
|
||||
const CircularBuffer<T>* container_;
|
||||
label iter_;
|
||||
|
||||
public:
|
||||
|
||||
using difference_type = label;
|
||||
using value_type = const T;
|
||||
using pointer = const T*;
|
||||
using reference = const T&;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
const_iterator(const const_iterator&) = default;
|
||||
const_iterator& operator=(const const_iterator&) = default;
|
||||
|
||||
const_iterator
|
||||
(
|
||||
const CircularBuffer<T>* buffer,
|
||||
label i
|
||||
)
|
||||
:
|
||||
container_(buffer),
|
||||
iter_(i)
|
||||
{}
|
||||
|
||||
reference operator*() const
|
||||
{
|
||||
return (*container_)[iter_];
|
||||
}
|
||||
|
||||
const_iterator& operator++()
|
||||
{
|
||||
++iter_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator operator++(int)
|
||||
{
|
||||
auto old(*this);
|
||||
++iter_;
|
||||
return old;
|
||||
}
|
||||
|
||||
bool operator==(const const_iterator& rhs) const
|
||||
{
|
||||
return iter_ == rhs.iter_;
|
||||
}
|
||||
|
||||
bool operator!=(const const_iterator& rhs) const
|
||||
{
|
||||
return iter_ != rhs.iter_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Iterator (const)
|
||||
|
||||
//- Return a const_iterator at begin of buffer
|
||||
inline const_iterator cbegin() const
|
||||
{
|
||||
return const_iterator(this, 0);
|
||||
}
|
||||
|
||||
//- Return a const_iterator at end of buffer
|
||||
inline const_iterator cend() const
|
||||
{
|
||||
return const_iterator(this, this->size());
|
||||
}
|
||||
|
||||
//- Return a const_iterator at begin of buffer
|
||||
inline const_iterator begin() const { return cbegin(); }
|
||||
|
||||
//- Return a const_iterator at end of buffer
|
||||
inline const_iterator end() const { return cend(); }
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
|
||||
|
||||
//- Read List contents from Istream
|
||||
template<class T>
|
||||
Istream& operator>>(Istream& is, CircularBuffer<T>& list)
|
||||
{
|
||||
return list.readList(is);
|
||||
}
|
||||
|
||||
|
||||
//- Write List to Ostream, as per UList::writeList() with default length.
|
||||
template<class T>
|
||||
Ostream& operator<<(Ostream& os, const CircularBuffer<T>& list)
|
||||
{
|
||||
return list.writeList(os);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#include "CircularBufferI.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#ifdef NoRepository
|
||||
#include "CircularBuffer.C"
|
||||
#include "CircularBufferIO.C"
|
||||
#endif
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
556
src/OpenFOAM/containers/Buffers/CircularBufferI.H
Normal file
556
src/OpenFOAM/containers/Buffers/CircularBufferI.H
Normal file
@ -0,0 +1,556 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class T>
|
||||
inline Foam::label Foam::CircularBuffer<T>::toGlobal(label i) const
|
||||
{
|
||||
const label len = this->size();
|
||||
|
||||
if (!len)
|
||||
{
|
||||
// Bounds error
|
||||
return -1;
|
||||
}
|
||||
else if (i < 0)
|
||||
{
|
||||
// Wrap any number of times
|
||||
while (i < 0) i += len;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wrap any number of times
|
||||
while (i >= len) i -= len;
|
||||
}
|
||||
|
||||
i += begin_;
|
||||
|
||||
if (i >= storage_.size())
|
||||
{
|
||||
i -= storage_.size();
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::label Foam::CircularBuffer<T>::size_one() const noexcept
|
||||
{
|
||||
return
|
||||
(
|
||||
(end_ >= begin_)
|
||||
? (end_ - begin_)
|
||||
: (storage_.size() - begin_)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::label Foam::CircularBuffer<T>::size_two() const noexcept
|
||||
{
|
||||
return
|
||||
(
|
||||
(end_ && end_ < begin_)
|
||||
? end_
|
||||
: static_cast<label>(0)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
template<class OtherListType>
|
||||
inline void Foam::CircularBuffer<T>::copyList(const OtherListType& rhs)
|
||||
{
|
||||
this->clear();
|
||||
|
||||
const label len = rhs.size();
|
||||
|
||||
if (len)
|
||||
{
|
||||
reserve(len + 1);
|
||||
|
||||
// Never overfilled, simply write at end_ (one-past position)
|
||||
|
||||
// - after clear(), begin_ and end_ are both 0
|
||||
|
||||
for (label i = 0; i < len; ++i)
|
||||
{
|
||||
storage_[end_] = rhs[i]; // copy element
|
||||
++end_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
template<class T>
|
||||
inline constexpr Foam::CircularBuffer<T>::CircularBuffer() noexcept
|
||||
:
|
||||
storage_(),
|
||||
begin_(0),
|
||||
end_(0)
|
||||
{}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::CircularBuffer<T>::CircularBuffer(const label len)
|
||||
:
|
||||
storage_(max(min_size(), len + 1)),
|
||||
begin_(0),
|
||||
end_(0)
|
||||
{}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::CircularBuffer<T>::CircularBuffer
|
||||
(
|
||||
const CircularBuffer<T>& list
|
||||
)
|
||||
:
|
||||
storage_(list.storage_),
|
||||
begin_(list.begin_),
|
||||
end_(list.end_)
|
||||
{}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::CircularBuffer<T>::CircularBuffer
|
||||
(
|
||||
CircularBuffer<T>&& list
|
||||
)
|
||||
:
|
||||
storage_(std::move(list.storage_)),
|
||||
begin_(list.begin_),
|
||||
end_(list.end_)
|
||||
{
|
||||
list.begin_ = 0;
|
||||
list.end_ = 0;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
template<class T>
|
||||
inline Foam::label Foam::CircularBuffer<T>::capacity() const noexcept
|
||||
{
|
||||
return storage_.size();
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline bool Foam::CircularBuffer<T>::empty() const noexcept
|
||||
{
|
||||
return storage_.empty() || (begin_ == end_);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::label Foam::CircularBuffer<T>::size() const noexcept
|
||||
{
|
||||
const label diff(end_ - begin_);
|
||||
|
||||
if (diff < 0)
|
||||
{
|
||||
return (storage_.size() + diff);
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::label Foam::CircularBuffer<T>::space() const noexcept
|
||||
{
|
||||
return (storage_.size() - size());
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::labelRange Foam::CircularBuffer<T>::range_one() const noexcept
|
||||
{
|
||||
return
|
||||
(
|
||||
(begin_ == end_)
|
||||
? labelRange()
|
||||
: labelRange(begin_, this->size_one())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::labelRange Foam::CircularBuffer<T>::range_two() const noexcept
|
||||
{
|
||||
return labelRange(0, this->size_two());
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::clear() noexcept
|
||||
{
|
||||
begin_ = end_ = 0;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::clearStorage()
|
||||
{
|
||||
storage_.clear();
|
||||
begin_ = end_ = 0;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::swap(CircularBuffer<T>& other)
|
||||
{
|
||||
if (this == &other)
|
||||
{
|
||||
return; // Self-swap is a no-op
|
||||
}
|
||||
|
||||
// Swap storage and addressing
|
||||
storage_.swap(other.storage_);
|
||||
std::swap(begin_, other.begin_);
|
||||
std::swap(end_, other.end_);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::reserve(const label len)
|
||||
{
|
||||
this->doReserve(false, len);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::reserve_nocopy(const label len)
|
||||
{
|
||||
this->doReserve(true, len);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline bool Foam::CircularBuffer<T>::found(const T& val, label pos) const
|
||||
{
|
||||
return (this->find(val, pos) >= 0);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline T& Foam::CircularBuffer<T>::first()
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
FatalErrorInFunction << "Buffer is empty" << abort(FatalError);
|
||||
}
|
||||
|
||||
return storage_[begin_];
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline const T& Foam::CircularBuffer<T>::first() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
FatalErrorInFunction << "Buffer is empty" << abort(FatalError);
|
||||
}
|
||||
|
||||
return storage_[begin_];
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline T& Foam::CircularBuffer<T>::last()
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
FatalErrorInFunction << "Buffer is empty" << abort(FatalError);
|
||||
}
|
||||
|
||||
return storage_.rcValue(end_);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline const T& Foam::CircularBuffer<T>::last() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
FatalErrorInFunction << "Buffer is empty" << abort(FatalError);
|
||||
}
|
||||
|
||||
return storage_.rcValue(end_);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::push_front(const T& val)
|
||||
{
|
||||
reserve(size() + 2);
|
||||
|
||||
// Never overfilled. Move begin and write
|
||||
|
||||
begin_ = storage_.rcIndex(begin_);
|
||||
storage_[begin_] = val; // copy assign element
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::push_front(T&& val)
|
||||
{
|
||||
reserve(size() + 2);
|
||||
|
||||
// Never overfilled. Move begin and write
|
||||
|
||||
begin_ = storage_.rcIndex(begin_);
|
||||
storage_[begin_] = std::move(val); // move assign element
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::push_back(const T& val)
|
||||
{
|
||||
reserve(size() + 2);
|
||||
|
||||
// Never overfilled, simply write at end_ (one-past position)
|
||||
|
||||
storage_[end_] = val; // copy assign element
|
||||
end_ = storage_.fcIndex(end_);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::push_back(T&& val)
|
||||
{
|
||||
reserve(size() + 2);
|
||||
|
||||
// Never overfilled, simply write at end_ (one-past position)
|
||||
|
||||
storage_[end_] = std::move(val); // move assign element
|
||||
end_ = storage_.fcIndex(end_);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::pop_front(label n)
|
||||
{
|
||||
if (n >= size())
|
||||
{
|
||||
begin_ = end_;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (n-- > 0)
|
||||
{
|
||||
begin_ = storage_.fcIndex(begin_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::pop_back(label n)
|
||||
{
|
||||
if (n >= size())
|
||||
{
|
||||
end_ = begin_;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (n-- > 0)
|
||||
{
|
||||
end_ = storage_.rcIndex(end_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::label Foam::CircularBuffer<T>::appendUniq(const T& val)
|
||||
{
|
||||
if (this->found(val))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->push_back(val);
|
||||
return 1; // Increased list length by one
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::append(const UList<T>& rhs)
|
||||
{
|
||||
const label len = rhs.size();
|
||||
|
||||
if (len)
|
||||
{
|
||||
reserve(size() + len + 1);
|
||||
|
||||
// Never overfilled, simply write at end_ (one-past position)
|
||||
|
||||
for (label i = 0; i < len; ++i)
|
||||
{
|
||||
storage_[end_] = rhs[i]; // copy element
|
||||
end_ = storage_.fcIndex(end_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
template<class Addr>
|
||||
inline void Foam::CircularBuffer<T>::append
|
||||
(
|
||||
const IndirectListBase<T, Addr>& rhs
|
||||
)
|
||||
{
|
||||
const label len = rhs.size();
|
||||
|
||||
if (len)
|
||||
{
|
||||
reserve(size() + len + 1);
|
||||
|
||||
// Never overfilled, simply write at end_ (one-past position)
|
||||
|
||||
for (label i = 0; i < len; ++i)
|
||||
{
|
||||
storage_[end_] = rhs[i]; // copy element
|
||||
end_ = storage_.fcIndex(end_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
|
||||
|
||||
template<class T>
|
||||
inline T& Foam::CircularBuffer<T>::operator[](label i)
|
||||
{
|
||||
const label idx = this->toGlobal(i);
|
||||
return storage_[idx];
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline const T& Foam::CircularBuffer<T>::operator[](label i) const
|
||||
{
|
||||
const label idx = this->toGlobal(i);
|
||||
return storage_[idx];
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::operator=(const CircularBuffer<T>& rhs)
|
||||
{
|
||||
if (this == &rhs)
|
||||
{
|
||||
return; // Self-assignment is a no-op
|
||||
}
|
||||
|
||||
this->clear();
|
||||
|
||||
const auto list1 = rhs.array_one();
|
||||
const auto list2 = rhs.array_two();
|
||||
const label len = (list1.size() + list2.size());
|
||||
|
||||
if (len)
|
||||
{
|
||||
reserve(len + 1);
|
||||
|
||||
// Never overfilled, simply write at end_ (one-past position)
|
||||
|
||||
// - after clear(), begin_ and end_ are both 0
|
||||
|
||||
for (const T& val : list1)
|
||||
{
|
||||
storage_[end_] = val;
|
||||
++end_;
|
||||
}
|
||||
|
||||
for (const T& val : list2)
|
||||
{
|
||||
storage_[end_] = val;
|
||||
++end_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::operator=(CircularBuffer<T>&& rhs)
|
||||
{
|
||||
if (this == &rhs)
|
||||
{
|
||||
return; // Self-assignment is a no-op
|
||||
}
|
||||
|
||||
this->clearStorage();
|
||||
this->swap(rhs);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::operator=(const T& val)
|
||||
{
|
||||
this->array_one() = val;
|
||||
this->array_two() = val;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::operator=(const Foam::zero)
|
||||
{
|
||||
this->array_one() = Zero;
|
||||
this->array_two() = Zero;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::CircularBuffer<T>::operator=(const UList<T>& rhs)
|
||||
{
|
||||
this->copyList(rhs);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
template<class AnyAddr>
|
||||
inline void Foam::CircularBuffer<T>::operator=
|
||||
(
|
||||
const IndirectListBase<T, AnyAddr>& rhs
|
||||
)
|
||||
{
|
||||
this->copyList(rhs);
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
258
src/OpenFOAM/containers/Buffers/CircularBufferIO.C
Normal file
258
src/OpenFOAM/containers/Buffers/CircularBufferIO.C
Normal file
@ -0,0 +1,258 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "List.H"
|
||||
#include "Istream.H"
|
||||
#include "contiguous.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
template<class T>
|
||||
Foam::CircularBuffer<T>::CircularBuffer(Istream& is)
|
||||
{
|
||||
this->readList(is);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
|
||||
|
||||
template<class T>
|
||||
Foam::Ostream& Foam::CircularBuffer<T>::info(Ostream& os) const
|
||||
{
|
||||
os << "size=" << size() << '/' << capacity()
|
||||
<< " begin=" << begin_
|
||||
<< " end=" << end_
|
||||
/// << " one=" << this->range_one() << this->array_one()
|
||||
/// << " two=" << this->range_two() << this->array_two()
|
||||
<< nl;
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
Foam::Istream& Foam::CircularBuffer<T>::readList(Istream& is)
|
||||
{
|
||||
// Clear list
|
||||
storage_.clear();
|
||||
begin_ = 0;
|
||||
end_ = 0;
|
||||
|
||||
// More work than it should be. We avoid completely filled buffers!
|
||||
|
||||
is.fatalCheck(FUNCTION_NAME);
|
||||
|
||||
token tok(is);
|
||||
|
||||
is.fatalCheck
|
||||
(
|
||||
"CircularBuffer<T>::readList(Istream&) : "
|
||||
"reading first token"
|
||||
);
|
||||
|
||||
if (tok.isCompound())
|
||||
{
|
||||
// Compound: simply transfer contents
|
||||
|
||||
storage_.transfer
|
||||
(
|
||||
dynamicCast<token::Compound<List<T>>>
|
||||
(
|
||||
tok.transferCompoundToken(is)
|
||||
)
|
||||
);
|
||||
|
||||
end_ = storage_.size();
|
||||
if (end_)
|
||||
{
|
||||
// Resize larger to avoid full buffer
|
||||
storage_.resize(end_ + min_size());
|
||||
}
|
||||
}
|
||||
else if (tok.isLabel())
|
||||
{
|
||||
// Label: could be int(..), int{...} or just a plain '0'
|
||||
|
||||
const label len = tok.labelToken();
|
||||
|
||||
end_ = len;
|
||||
if (end_)
|
||||
{
|
||||
// Resize larger to avoid full buffer
|
||||
storage_.resize(end_ + min_size());
|
||||
}
|
||||
|
||||
// Dispatch to UList reading...
|
||||
|
||||
UList<T> list(storage_.data(), end_);
|
||||
|
||||
is.putBack(tok);
|
||||
list.readList(is);
|
||||
}
|
||||
else if (tok.isPunctuation(token::BEGIN_LIST))
|
||||
{
|
||||
// "(...)" : read as SLList and transfer contents
|
||||
|
||||
is.putBack(tok); // Putback the opening bracket
|
||||
SLList<T> sll(is); // Read as singly-linked list
|
||||
|
||||
const label len = sll.size();
|
||||
|
||||
end_ = len;
|
||||
if (end_)
|
||||
{
|
||||
// Resize larger to avoid full buffer
|
||||
storage_.resize(end_ + min_size());
|
||||
|
||||
// Move assign each list element
|
||||
for (label i = 0; i < len; ++i)
|
||||
{
|
||||
storage_[i] = std::move(sll.removeHead());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FatalIOErrorInFunction(is)
|
||||
<< "incorrect first token, expected <int> or '(', found "
|
||||
<< tok.info() << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
Foam::Ostream& Foam::CircularBuffer<T>::writeList
|
||||
(
|
||||
Ostream& os,
|
||||
const label shortLen
|
||||
) const
|
||||
{
|
||||
const label len = this->size();
|
||||
const auto list1 = this->array_one();
|
||||
const auto list2 = this->array_two();
|
||||
|
||||
#ifdef FULLDEBUG
|
||||
if (len != (list1.size() + list2.size()))
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Size check failed"
|
||||
<< abort(FatalError);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (os.format() == IOstream::BINARY && is_contiguous<T>::value)
|
||||
{
|
||||
// Binary and contiguous
|
||||
|
||||
os << nl << len << nl;
|
||||
|
||||
if (len)
|
||||
{
|
||||
// The TOTAL number of bytes to be written.
|
||||
// - possibly add start delimiter
|
||||
// This is much like IndirectListBase output
|
||||
|
||||
os.beginRawWrite(len*sizeof(T));
|
||||
|
||||
if (!list1.empty())
|
||||
{
|
||||
os.writeRaw(list1.cdata_bytes(), list1.size_bytes());
|
||||
}
|
||||
if (!list2.empty())
|
||||
{
|
||||
os.writeRaw(list2.cdata_bytes(), list2.size_bytes());
|
||||
}
|
||||
|
||||
// End delimiter and/or cleanup.
|
||||
os.endRawWrite();
|
||||
}
|
||||
}
|
||||
else if
|
||||
(
|
||||
(len <= 1 || !shortLen)
|
||||
||
|
||||
(
|
||||
(len <= shortLen)
|
||||
&&
|
||||
(
|
||||
is_contiguous<T>::value
|
||||
|| Detail::ListPolicy::no_linebreak<T>::value
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
// Single-line output
|
||||
|
||||
// Size and start delimiter
|
||||
os << len << token::BEGIN_LIST;
|
||||
|
||||
// Contents
|
||||
label i = 0;
|
||||
for (const T& val : list1)
|
||||
{
|
||||
if (i++) os << token::SPACE;
|
||||
os << val;
|
||||
}
|
||||
for (const T& val : list2)
|
||||
{
|
||||
if (i++) os << token::SPACE;
|
||||
os << val;
|
||||
}
|
||||
|
||||
// End delimiter
|
||||
os << token::END_LIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Multi-line output
|
||||
|
||||
// Size and start delimiter
|
||||
os << nl << len << nl << token::BEGIN_LIST << nl;
|
||||
|
||||
// Contents
|
||||
for (const T& val : list1)
|
||||
{
|
||||
os << val << nl;
|
||||
}
|
||||
for (const T& val : list2)
|
||||
{
|
||||
os << val << nl;
|
||||
}
|
||||
|
||||
// End delimiter
|
||||
os << token::END_LIST << nl;
|
||||
}
|
||||
|
||||
os.check(FUNCTION_NAME);
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
Loading…
Reference in New Issue
Block a user