mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: add CircularBuffer container
This commit is contained in:
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
Reference in New Issue
Block a user