mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: eliminate reliance on SLList during reading
- fully implement DynamicList::readList() instead of simply redirecting to List::readList(). This also benefits DynamicField. Leverage DynamicList reading to simplify and improve CircularBuffer reading. - bracket lists are now read chunk-wise instead of using a singly-linked list. For integral and vector-space types (eg, scalar, vector, etc) this avoids intermediate allocations for each element. ENH: add CircularBuffer emplace_front/emplace_back STYLE: isolate to-be-deprecated construct/assign forms - still have construct/assign FixedList from a C-array. This is not really needed, can use std::initializer_list - still have construct/assign List from SLList. Prefer to avoid these in the future. DEFEATURE: remove construct/assign FixedList from SLList - never used DEFEATURE: remove move construct/assign List from SLList - now unused. Retain copy construct/assign from SLList for transition purposes.
This commit is contained in:
@ -92,7 +92,10 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
report(buf1);
|
report(buf1);
|
||||||
|
|
||||||
buf1.push_back(identity(5)); report(buf1);
|
buf1.push_back(identity(5));
|
||||||
|
buf1.emplace_front(-1000);
|
||||||
|
buf1.emplace_back(1000);
|
||||||
|
report(buf1);
|
||||||
|
|
||||||
buf1.info(Info);
|
buf1.info(Info);
|
||||||
Info<< buf1 << nl;
|
Info<< buf1 << nl;
|
||||||
|
|||||||
@ -202,14 +202,31 @@ int main(int argc, char *argv[])
|
|||||||
Info<< "get<3>: " << list1.get<3>() << nl;
|
Info<< "get<3>: " << list1.get<3>() << nl;
|
||||||
// Will not compile: Info<< "get<4>: " << list1.get<4>() << nl;
|
// Will not compile: Info<< "get<4>: " << list1.get<4>() << nl;
|
||||||
|
|
||||||
label a[4] = {0, 1, 2, 3};
|
// Test deprecated form
|
||||||
FixedList<label, 4> list2(a);
|
label array2[4] = {0, 1, 2, 3};
|
||||||
|
FixedList<label, 4> list2(array2);
|
||||||
|
|
||||||
Info<< "list2:" << list2
|
Info<< "list2:" << list2
|
||||||
<< " hash:" << FixedList<label, 4>::hasher()(list2) << nl
|
<< " hash:" << FixedList<label, 4>::hasher()(list2) << nl
|
||||||
<< " hash:" << Hash<FixedList<label, 4>>()(list2) << nl;
|
<< " hash:" << Hash<FixedList<label, 4>>()(list2) << nl;
|
||||||
|
|
||||||
|
|
||||||
|
// Test deprecated form
|
||||||
|
SLList<label> sllist3;
|
||||||
|
{
|
||||||
|
sllist3.push_back(0);
|
||||||
|
sllist3.push_back(1);
|
||||||
|
sllist3.push_back(2);
|
||||||
|
sllist3.push_back(3);
|
||||||
|
}
|
||||||
|
FixedList<label, 4> list3(sllist3);
|
||||||
|
|
||||||
|
Info<< "list3:" << list3 << nl;
|
||||||
|
// Test deprecated forms
|
||||||
|
list3 = array2;
|
||||||
|
list2 = sllist3;
|
||||||
|
|
||||||
|
|
||||||
// Using FixedList for content too
|
// Using FixedList for content too
|
||||||
{
|
{
|
||||||
List<FixedList<label, 4>> twolists{list1, list2};
|
List<FixedList<label, 4>> twolists{list1, list2};
|
||||||
|
|||||||
3
applications/test/ListRead1/Make/files
Normal file
3
applications/test/ListRead1/Make/files
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Test-ListRead1.C
|
||||||
|
|
||||||
|
EXE = $(FOAM_USER_APPBIN)/Test-ListRead1
|
||||||
2
applications/test/ListRead1/Make/options
Normal file
2
applications/test/ListRead1/Make/options
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/* EXE_INC = */
|
||||||
|
/* EXE_LIBS = */
|
||||||
234
applications/test/ListRead1/Test-ListRead1.C
Normal file
234
applications/test/ListRead1/Test-ListRead1.C
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2023 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-ListRead1
|
||||||
|
|
||||||
|
Description
|
||||||
|
List reading
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "OSspecific.H"
|
||||||
|
#include "argList.H"
|
||||||
|
#include "wordRes.H"
|
||||||
|
|
||||||
|
#include "IOstreams.H"
|
||||||
|
#include "Fstream.H"
|
||||||
|
#include "StringStream.H"
|
||||||
|
#include "scalar.H"
|
||||||
|
#include "vector.H"
|
||||||
|
|
||||||
|
#include "labelRange.H"
|
||||||
|
#include "scalarList.H"
|
||||||
|
#include "HashOps.H"
|
||||||
|
#include "ListOps.H"
|
||||||
|
#include "IndirectList.H"
|
||||||
|
#include "SubList.H"
|
||||||
|
#include "SliceList.H"
|
||||||
|
#include "ListPolicy.H"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <numeric>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
using namespace Foam;
|
||||||
|
|
||||||
|
label chunkSize = 128;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
bool readBracketList(List<T>& list, Istream& is)
|
||||||
|
{
|
||||||
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
|
||||||
|
token tok(is);
|
||||||
|
|
||||||
|
is.fatalCheck
|
||||||
|
(
|
||||||
|
"List<T>::readBracketList(Istream&) : reading first token"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!tok.isPunctuation(token::BEGIN_LIST))
|
||||||
|
{
|
||||||
|
is.putBack(tok);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// "(...)" : read element-wise.
|
||||||
|
// Uses chunk-wise reading to avoid too many re-allocations
|
||||||
|
// and avoids relocation of contiguous memory until all of the reading
|
||||||
|
// is completed. Chunks are wrapped as unique_ptr to ensure proper
|
||||||
|
// cleanup on failure.
|
||||||
|
|
||||||
|
// The choice of chunk-size is somewhat arbitrary...
|
||||||
|
// constexpr label chunkSize = 128;
|
||||||
|
typedef std::unique_ptr<List<T>> chunkType;
|
||||||
|
|
||||||
|
is >> tok;
|
||||||
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
|
||||||
|
if (tok.isPunctuation(token::END_LIST))
|
||||||
|
{
|
||||||
|
// Trivial case, an empty list
|
||||||
|
list.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use all storage
|
||||||
|
//private:// list.resize(list.capacity());
|
||||||
|
|
||||||
|
// Start with a few slots, recover current memory where possible
|
||||||
|
List<chunkType> chunks(16);
|
||||||
|
if (list.empty())
|
||||||
|
{
|
||||||
|
chunks[0] = chunkType(new List<T>(chunkSize));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chunks[0] = chunkType(new List<T>(std::move(list)));
|
||||||
|
}
|
||||||
|
|
||||||
|
label nChunks = 1; // Active number of chunks
|
||||||
|
label totalCount = 0; // Total number of elements
|
||||||
|
label localIndex = 0; // Chunk-local index
|
||||||
|
|
||||||
|
InfoErr
|
||||||
|
<< nl << "initial chunk: " << chunks[0]->size() << endl;
|
||||||
|
|
||||||
|
while (!tok.isPunctuation(token::END_LIST))
|
||||||
|
{
|
||||||
|
is.putBack(tok);
|
||||||
|
|
||||||
|
if (chunks[nChunks-1]->size() <= localIndex)
|
||||||
|
{
|
||||||
|
// Increase number of slots (doubling)
|
||||||
|
if (nChunks >= chunks.size())
|
||||||
|
{
|
||||||
|
chunks.resize(2*chunks.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoErr<< "new chunk" << endl;
|
||||||
|
chunks[nChunks] = chunkType(new List<T>(chunkSize));
|
||||||
|
++nChunks;
|
||||||
|
localIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
is >> chunks[nChunks-1]->operator[](localIndex);
|
||||||
|
++localIndex;
|
||||||
|
++totalCount;
|
||||||
|
|
||||||
|
InfoErr
|
||||||
|
<< " chunk=" << nChunks
|
||||||
|
<< " index=" << localIndex
|
||||||
|
<< " total=" << totalCount << nl;
|
||||||
|
|
||||||
|
is.fatalCheck
|
||||||
|
(
|
||||||
|
"List<T>::readBracketList(Istream&) : "
|
||||||
|
"reading entry"
|
||||||
|
);
|
||||||
|
|
||||||
|
is >> tok;
|
||||||
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple case
|
||||||
|
if (nChunks == 1)
|
||||||
|
{
|
||||||
|
list = std::move(*(chunks[0]));
|
||||||
|
list.resize(totalCount);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destination
|
||||||
|
//private:// list.setCapacity_nocopy(totalCount);
|
||||||
|
list.resize_nocopy(totalCount);
|
||||||
|
auto dest = list.begin();
|
||||||
|
|
||||||
|
for (label chunki = 0; chunki < nChunks; ++chunki)
|
||||||
|
{
|
||||||
|
List<T> currChunk(std::move(*(chunks[chunki])));
|
||||||
|
chunks[chunki].reset(nullptr);
|
||||||
|
|
||||||
|
const label localLen = min(currChunk.size(), totalCount);
|
||||||
|
|
||||||
|
dest = std::move
|
||||||
|
(
|
||||||
|
currChunk.begin(),
|
||||||
|
currChunk.begin(localLen),
|
||||||
|
dest
|
||||||
|
);
|
||||||
|
|
||||||
|
totalCount -= localLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
// Main program:
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
argList::noBanner();
|
||||||
|
argList::noParallel();
|
||||||
|
argList::noFunctionObjects();
|
||||||
|
argList::addOption("chunk-size", "value", "change read chunk size");
|
||||||
|
argList::addArgument("file1 .. fileN");
|
||||||
|
|
||||||
|
argList args(argc, argv, false, true);
|
||||||
|
|
||||||
|
args.readIfPresent("chunk-size", chunkSize);
|
||||||
|
|
||||||
|
Info<< "chunk-size: " << chunkSize << nl;
|
||||||
|
|
||||||
|
if (args.size() <= 1)
|
||||||
|
{
|
||||||
|
InfoErr<< "Provide a file or files to test" << nl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (label argi=1; argi < args.size(); ++argi)
|
||||||
|
{
|
||||||
|
const auto input = args.get<fileName>(argi);
|
||||||
|
IFstream is(input);
|
||||||
|
|
||||||
|
while (!is.eof())
|
||||||
|
{
|
||||||
|
labelList list;
|
||||||
|
|
||||||
|
readBracketList(list, is);
|
||||||
|
Info<< "read: " << flatOutput(list) << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
17
applications/test/ListRead1/testLists1
Normal file
17
applications/test/ListRead1/testLists1
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
(
|
||||||
|
0 1 2 3 4 5 6 7 8 9
|
||||||
|
10 11 12 13 14 15 16 17 18 19
|
||||||
|
20 21 22 23 24 25 26 27 28 29
|
||||||
|
30 31 32 33 34 35 36 37 38 39
|
||||||
|
40 41 42 43 44 45 46 47 48 49
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
0 1 2 3 4 5 6 7 8 9
|
||||||
|
10 11 12 13 14 15 16 17 18 19
|
||||||
|
20 21 22 23 24 25 26 27 28 29
|
||||||
|
30 31 32 33 34 35 36 37 38 39
|
||||||
|
40 41 42 43 44 45 46 47 48 49
|
||||||
|
)
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
@ -303,12 +303,22 @@ public:
|
|||||||
//- Move prepend an element to the front of the buffer
|
//- Move prepend an element to the front of the buffer
|
||||||
inline void push_front(T&& val);
|
inline void push_front(T&& val);
|
||||||
|
|
||||||
|
//- Construct an element at the front of the buffer,
|
||||||
|
//- return reference to the new element
|
||||||
|
template<class... Args>
|
||||||
|
inline T& emplace_front(Args&&... args);
|
||||||
|
|
||||||
//- Copy append an element to the end of the buffer
|
//- Copy append an element to the end of the buffer
|
||||||
inline void push_back(const T& val);
|
inline void push_back(const T& val);
|
||||||
|
|
||||||
//- Move Append an element to the end of the buffer
|
//- Move append an element to the end of the buffer
|
||||||
inline void push_back(T&& val);
|
inline void push_back(T&& val);
|
||||||
|
|
||||||
|
//- Construct an element at the end of the buffer,
|
||||||
|
//- return reference to the new element
|
||||||
|
template<class... Args>
|
||||||
|
inline T& emplace_back(Args&&... args);
|
||||||
|
|
||||||
//- Shrink by moving the front of the buffer 1 or more times
|
//- Shrink by moving the front of the buffer 1 or more times
|
||||||
inline void pop_front(label n = 1);
|
inline void pop_front(label n = 1);
|
||||||
|
|
||||||
|
|||||||
@ -334,6 +334,21 @@ inline void Foam::CircularBuffer<T>::push_front(T&& val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
template<class... Args>
|
||||||
|
inline T& Foam::CircularBuffer<T>::emplace_front(Args&&... args)
|
||||||
|
{
|
||||||
|
reserve(size() + 2);
|
||||||
|
|
||||||
|
// Never overfilled. Move begin and write
|
||||||
|
|
||||||
|
begin_ = storage_.rcIndex(begin_);
|
||||||
|
storage_[begin_] = T(std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
return storage_[begin_];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline void Foam::CircularBuffer<T>::push_back(const T& val)
|
inline void Foam::CircularBuffer<T>::push_back(const T& val)
|
||||||
{
|
{
|
||||||
@ -358,6 +373,22 @@ inline void Foam::CircularBuffer<T>::push_back(T&& val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
template<class... Args>
|
||||||
|
inline T& Foam::CircularBuffer<T>::emplace_back(Args&&... args)
|
||||||
|
{
|
||||||
|
reserve(size() + 2);
|
||||||
|
|
||||||
|
// Never overfilled, simply write at end_ (one-past position)
|
||||||
|
|
||||||
|
const label backIndex = end_;
|
||||||
|
storage_[end_] = T(std::forward<Args>(args)...);
|
||||||
|
end_ = storage_.fcIndex(end_);
|
||||||
|
|
||||||
|
return storage_[backIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline void Foam::CircularBuffer<T>::pop_front(label n)
|
inline void Foam::CircularBuffer<T>::pop_front(label n)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
\\ / A nd | www.openfoam.com
|
\\ / A nd | www.openfoam.com
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2022 OpenCFD Ltd.
|
Copyright (C) 2022-2023 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -25,7 +25,7 @@ License
|
|||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "List.H"
|
#include "DynamicList.H"
|
||||||
#include "Istream.H"
|
#include "Istream.H"
|
||||||
#include "contiguous.H"
|
#include "contiguous.H"
|
||||||
|
|
||||||
@ -46,8 +46,8 @@ Foam::Ostream& Foam::CircularBuffer<T>::info(Ostream& os) const
|
|||||||
os << "size=" << size() << '/' << capacity()
|
os << "size=" << size() << '/' << capacity()
|
||||||
<< " begin=" << begin_
|
<< " begin=" << begin_
|
||||||
<< " end=" << end_
|
<< " end=" << end_
|
||||||
/// << " one=" << this->range_one() << this->array_one()
|
// << " one=" << this->range_one() << this->array_one()
|
||||||
/// << " two=" << this->range_two() << this->array_two()
|
// << " two=" << this->range_two() << this->array_two()
|
||||||
<< nl;
|
<< nl;
|
||||||
|
|
||||||
return os;
|
return os;
|
||||||
@ -57,91 +57,27 @@ Foam::Ostream& Foam::CircularBuffer<T>::info(Ostream& os) const
|
|||||||
template<class T>
|
template<class T>
|
||||||
Foam::Istream& Foam::CircularBuffer<T>::readList(Istream& is)
|
Foam::Istream& Foam::CircularBuffer<T>::readList(Istream& is)
|
||||||
{
|
{
|
||||||
// Clear list
|
// Delegate to DynamicList for reading
|
||||||
storage_.clear();
|
DynamicList<T> elements(std::move(storage_));
|
||||||
|
elements.readList(is);
|
||||||
|
|
||||||
|
// Reset the list addressing range
|
||||||
begin_ = 0;
|
begin_ = 0;
|
||||||
end_ = 0;
|
end_ = elements.size();
|
||||||
|
|
||||||
// More work than it should be. We avoid completely filled buffers!
|
const label minLen = (end_ + min_size());
|
||||||
|
|
||||||
is.fatalCheck(FUNCTION_NAME);
|
if (!elements.empty() && (elements.capacity() < minLen))
|
||||||
|
|
||||||
token tok(is);
|
|
||||||
|
|
||||||
is.fatalCheck
|
|
||||||
(
|
|
||||||
"CircularBuffer<T>::readList(Istream&) : "
|
|
||||||
"reading first token"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (tok.isCompound())
|
|
||||||
{
|
{
|
||||||
// Compound: simply transfer contents
|
// Avoid full buffer (beg/end ambiguity)
|
||||||
|
// Use setCapacity instead of resize to avoid additional doubling...
|
||||||
storage_.transfer
|
elements.setCapacity(minLen);
|
||||||
(
|
|
||||||
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...
|
// Use the entire storage
|
||||||
|
elements.resize(elements.capacity());
|
||||||
|
|
||||||
UList<T> list(storage_.data(), end_);
|
storage_ = std::move(elements);
|
||||||
|
|
||||||
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;
|
return is;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,6 +105,10 @@ class DynamicList
|
|||||||
// The 'nocopy' option will not attempt to recover old content
|
// The 'nocopy' option will not attempt to recover old content
|
||||||
inline void doResize(const bool nocopy, const label len);
|
inline void doResize(const bool nocopy, const label len);
|
||||||
|
|
||||||
|
//- Read List from Istream between '(' and ')' delimiters.
|
||||||
|
//- The size is not known a priori.
|
||||||
|
bool readBracketList(Istream& is);
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
\\ / A nd | www.openfoam.com
|
\\ / A nd | www.openfoam.com
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2021 OpenCFD Ltd.
|
Copyright (C) 2021-2023 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -28,8 +28,8 @@ License
|
|||||||
#include "List.H"
|
#include "List.H"
|
||||||
#include "Istream.H"
|
#include "Istream.H"
|
||||||
#include "token.H"
|
#include "token.H"
|
||||||
#include "SLList.H"
|
|
||||||
#include "contiguous.H"
|
#include "contiguous.H"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -43,6 +43,133 @@ Foam::DynamicList<T, SizeMin>::DynamicList(Istream& is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
template<class T, int SizeMin>
|
||||||
|
bool Foam::DynamicList<T, SizeMin>::readBracketList(Istream& is)
|
||||||
|
{
|
||||||
|
DynamicList<T, SizeMin>& list = *this;
|
||||||
|
|
||||||
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
|
||||||
|
token tok(is);
|
||||||
|
|
||||||
|
is.fatalCheck
|
||||||
|
(
|
||||||
|
"DynamicList<T>::readBracketList(Istream&) : reading first token"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!tok.isPunctuation(token::BEGIN_LIST))
|
||||||
|
{
|
||||||
|
is.putBack(tok);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// "(...)" : read element-wise.
|
||||||
|
// Uses chunk-wise reading to avoid too many re-allocations
|
||||||
|
// and avoids relocation of contiguous memory until all of the reading
|
||||||
|
// is completed. Chunks are wrapped as unique_ptr to ensure proper
|
||||||
|
// cleanup on failure.
|
||||||
|
|
||||||
|
// The choice of chunk-size is somewhat arbitrary...
|
||||||
|
constexpr label chunkSize = 128;
|
||||||
|
typedef std::unique_ptr<List<T>> chunkType;
|
||||||
|
|
||||||
|
is >> tok;
|
||||||
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
|
||||||
|
if (tok.isPunctuation(token::END_LIST))
|
||||||
|
{
|
||||||
|
// Trivial case, an empty list
|
||||||
|
list.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use all storage
|
||||||
|
list.resize(list.capacity());
|
||||||
|
|
||||||
|
// Start with a few slots, recover current memory where possible
|
||||||
|
List<chunkType> chunks(16);
|
||||||
|
if (list.empty())
|
||||||
|
{
|
||||||
|
chunks[0] = chunkType(new List<T>(chunkSize));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chunks[0] = chunkType(new List<T>(std::move(list)));
|
||||||
|
}
|
||||||
|
|
||||||
|
label nChunks = 1; // Active number of chunks
|
||||||
|
label totalCount = 0; // Total number of elements
|
||||||
|
label localIndex = 0; // Chunk-local index
|
||||||
|
|
||||||
|
while (!tok.isPunctuation(token::END_LIST))
|
||||||
|
{
|
||||||
|
is.putBack(tok);
|
||||||
|
|
||||||
|
if (chunks[nChunks-1]->size() <= localIndex)
|
||||||
|
{
|
||||||
|
// Increase number of slots (doubling)
|
||||||
|
if (nChunks >= chunks.size())
|
||||||
|
{
|
||||||
|
chunks.resize(2*chunks.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
chunks[nChunks] = chunkType(new List<T>(chunkSize));
|
||||||
|
++nChunks;
|
||||||
|
localIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
is >> chunks[nChunks-1]->operator[](localIndex);
|
||||||
|
++localIndex;
|
||||||
|
++totalCount;
|
||||||
|
|
||||||
|
is.fatalCheck
|
||||||
|
(
|
||||||
|
"DynamicList<T>::readBracketList(Istream&) : "
|
||||||
|
"reading entry"
|
||||||
|
);
|
||||||
|
|
||||||
|
is >> tok;
|
||||||
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple case
|
||||||
|
if (nChunks == 1)
|
||||||
|
{
|
||||||
|
list = std::move(*(chunks[0]));
|
||||||
|
list.resize(totalCount);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destination
|
||||||
|
list.setCapacity_nocopy(totalCount);
|
||||||
|
list.resize_nocopy(totalCount);
|
||||||
|
auto dest = list.begin();
|
||||||
|
|
||||||
|
for (label chunki = 0; chunki < nChunks; ++chunki)
|
||||||
|
{
|
||||||
|
List<T> currChunk(std::move(*(chunks[chunki])));
|
||||||
|
chunks[chunki].reset(nullptr);
|
||||||
|
|
||||||
|
const label localLen = min(currChunk.size(), totalCount);
|
||||||
|
|
||||||
|
dest = std::move
|
||||||
|
(
|
||||||
|
currChunk.begin(),
|
||||||
|
currChunk.begin(localLen),
|
||||||
|
dest
|
||||||
|
);
|
||||||
|
|
||||||
|
totalCount -= localLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
template<class T, int SizeMin>
|
template<class T, int SizeMin>
|
||||||
@ -50,12 +177,136 @@ Foam::Istream& Foam::DynamicList<T, SizeMin>::readList(Istream& is)
|
|||||||
{
|
{
|
||||||
DynamicList<T, SizeMin>& list = *this;
|
DynamicList<T, SizeMin>& list = *this;
|
||||||
|
|
||||||
// Needs rewrite (2021-10)
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
// Use entire storage - ie, resize(capacity())
|
|
||||||
(void) list.expandStorage();
|
|
||||||
|
|
||||||
static_cast<List<T>&>(list).readList(is);
|
token tok(is);
|
||||||
list.capacity_ = list.size();
|
|
||||||
|
is.fatalCheck("DynamicList<T>::readList(Istream&) : reading first token");
|
||||||
|
|
||||||
|
if (tok.isCompound())
|
||||||
|
{
|
||||||
|
// Compound: simply transfer contents
|
||||||
|
|
||||||
|
list.clearStorage(); // Remove old contents
|
||||||
|
list.transfer
|
||||||
|
(
|
||||||
|
dynamicCast<token::Compound<List<T>>>
|
||||||
|
(
|
||||||
|
tok.transferCompoundToken(is)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (tok.isLabel())
|
||||||
|
{
|
||||||
|
// Label: could be int(..), int{...} or just a plain '0'
|
||||||
|
|
||||||
|
const label len = tok.labelToken();
|
||||||
|
|
||||||
|
// Resize to length required
|
||||||
|
list.resize_nocopy(len);
|
||||||
|
|
||||||
|
if (is.format() == IOstreamOption::BINARY && is_contiguous<T>::value)
|
||||||
|
{
|
||||||
|
// Binary and contiguous
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
Detail::readContiguous<T>
|
||||||
|
(
|
||||||
|
is,
|
||||||
|
list.data_bytes(),
|
||||||
|
list.size_bytes()
|
||||||
|
);
|
||||||
|
|
||||||
|
is.fatalCheck
|
||||||
|
(
|
||||||
|
"DynamicList<T>::readList(Istream&) : "
|
||||||
|
"reading binary block"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Begin of contents marker
|
||||||
|
const char delimiter = is.readBeginList("List");
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
if (delimiter == token::BEGIN_LIST)
|
||||||
|
{
|
||||||
|
for (label i=0; i<len; ++i)
|
||||||
|
{
|
||||||
|
is >> list[i];
|
||||||
|
|
||||||
|
is.fatalCheck
|
||||||
|
(
|
||||||
|
"DynamicList<T>::readList(Istream&) : "
|
||||||
|
"reading entry"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Uniform content (delimiter == token::BEGIN_BLOCK)
|
||||||
|
|
||||||
|
T elem;
|
||||||
|
is >> elem;
|
||||||
|
|
||||||
|
is.fatalCheck
|
||||||
|
(
|
||||||
|
"DynamicList<T>::readList(Istream&) : "
|
||||||
|
"reading the single entry"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Fill with the value
|
||||||
|
this->fill_uniform(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// End of contents marker
|
||||||
|
is.readEndList("List");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (tok.isPunctuation(token::BEGIN_LIST))
|
||||||
|
{
|
||||||
|
// "(...)" : read read as bracketed list
|
||||||
|
|
||||||
|
is.putBack(tok);
|
||||||
|
this->readBracketList(is);
|
||||||
|
|
||||||
|
// Could also simply be done with emplace_back for each element
|
||||||
|
// but prefer the same mechanism as List::readList to avoid
|
||||||
|
// intermediate resizing
|
||||||
|
|
||||||
|
// // list.clear(); // Clear addressing, leave storage intact
|
||||||
|
// //
|
||||||
|
// // is >> tok;
|
||||||
|
// // is.fatalCheck(FUNCTION_NAME);
|
||||||
|
// //
|
||||||
|
// // while (!tok.isPunctuation(token::END_LIST))
|
||||||
|
// // {
|
||||||
|
// // is.putBack(tok);
|
||||||
|
// // is >> list.emplace_back();
|
||||||
|
// //
|
||||||
|
// // is.fatalCheck
|
||||||
|
// // (
|
||||||
|
// // "DynamicList<T>::readList(Istream&) : "
|
||||||
|
// // "reading entry"
|
||||||
|
// // );
|
||||||
|
// //
|
||||||
|
// // is >> tok;
|
||||||
|
// // is.fatalCheck(FUNCTION_NAME);
|
||||||
|
// // }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list.clear(); // Clear old contents
|
||||||
|
|
||||||
|
FatalIOErrorInFunction(is)
|
||||||
|
<< "incorrect first token, expected <int> or '(', found "
|
||||||
|
<< tok.info() << nl
|
||||||
|
<< exit(FatalIOError);
|
||||||
|
}
|
||||||
|
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,9 +48,9 @@ SourceFiles
|
|||||||
#include "stdFoam.H"
|
#include "stdFoam.H"
|
||||||
#include "autoPtr.H"
|
#include "autoPtr.H"
|
||||||
#include "Hash.H"
|
#include "Hash.H"
|
||||||
#include "SLListFwd.H"
|
|
||||||
#include "ListPolicy.H"
|
#include "ListPolicy.H"
|
||||||
|
|
||||||
|
// <algorithm> already included by stdFoam.H
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@ -154,9 +154,6 @@ public:
|
|||||||
//- Construct and initialize all entries to zero
|
//- Construct and initialize all entries to zero
|
||||||
inline explicit FixedList(const Foam::zero);
|
inline explicit FixedList(const Foam::zero);
|
||||||
|
|
||||||
//- Copy construct from C-array (deprecated)
|
|
||||||
inline explicit FixedList(const T list[N]);
|
|
||||||
|
|
||||||
//- Copy construct
|
//- Copy construct
|
||||||
inline FixedList(const FixedList<T, N>& list);
|
inline FixedList(const FixedList<T, N>& list);
|
||||||
|
|
||||||
@ -185,9 +182,6 @@ public:
|
|||||||
const FixedList<label, N>& indices
|
const FixedList<label, N>& indices
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Construct from SLList. Runtime size check
|
|
||||||
inline explicit FixedList(const SLList<T>& list);
|
|
||||||
|
|
||||||
//- Construct from Istream
|
//- Construct from Istream
|
||||||
explicit FixedList(Istream& is);
|
explicit FixedList(Istream& is);
|
||||||
|
|
||||||
@ -342,15 +336,9 @@ public:
|
|||||||
//- Return element of constant FixedList
|
//- Return element of constant FixedList
|
||||||
inline const T& operator[](const label i) const;
|
inline const T& operator[](const label i) const;
|
||||||
|
|
||||||
//- Assignment to array operator. Takes linear time
|
|
||||||
inline void operator=(const T list[N]);
|
|
||||||
|
|
||||||
//- Assignment to UList operator. Takes linear time
|
//- Assignment to UList operator. Takes linear time
|
||||||
inline void operator=(const UList<T>& list);
|
inline void operator=(const UList<T>& list);
|
||||||
|
|
||||||
//- Assignment to SLList operator. Takes linear time
|
|
||||||
inline void operator=(const SLList<T>& list);
|
|
||||||
|
|
||||||
//- Assignment to an initializer list. Takes linear time
|
//- Assignment to an initializer list. Takes linear time
|
||||||
inline void operator=(std::initializer_list<T> list);
|
inline void operator=(std::initializer_list<T> list);
|
||||||
|
|
||||||
@ -529,6 +517,14 @@ public:
|
|||||||
{
|
{
|
||||||
return this->contains(val, pos);
|
return this->contains(val, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//- Deprecated: copy construct from C-array
|
||||||
|
explicit FixedList(const T list[N]) { std::copy_n(list, N, v_); }
|
||||||
|
|
||||||
|
//- Deprecated: assignment from C-array
|
||||||
|
// \deprecated(2023-08) - use other assignment operators
|
||||||
|
void operator=(const T list[N]) { std::copy_n(list, N, v_); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -27,8 +27,6 @@ License
|
|||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "UList.H"
|
#include "UList.H"
|
||||||
#include "SLList.H"
|
|
||||||
// <algorithm> already included by stdFoam.H
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -55,16 +53,6 @@ inline Foam::FixedList<T, N>::FixedList(const Foam::zero)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T, unsigned N>
|
|
||||||
inline Foam::FixedList<T, N>::FixedList(const T list[N])
|
|
||||||
{
|
|
||||||
for (unsigned i=0; i<N; ++i)
|
|
||||||
{
|
|
||||||
v_[i] = list[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class T, unsigned N>
|
template<class T, unsigned N>
|
||||||
inline Foam::FixedList<T, N>::FixedList(const FixedList<T, N>& list)
|
inline Foam::FixedList<T, N>::FixedList(const FixedList<T, N>& list)
|
||||||
{
|
{
|
||||||
@ -140,20 +128,6 @@ inline Foam::FixedList<T, N>::FixedList
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T, unsigned N>
|
|
||||||
inline Foam::FixedList<T, N>::FixedList(const SLList<T>& list)
|
|
||||||
{
|
|
||||||
checkSize(list.size());
|
|
||||||
|
|
||||||
auto iter = list.begin();
|
|
||||||
for (unsigned i=0; i<N; ++i)
|
|
||||||
{
|
|
||||||
v_[i] = *iter;
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class T, unsigned N>
|
template<class T, unsigned N>
|
||||||
inline Foam::autoPtr<Foam::FixedList<T, N>>
|
inline Foam::autoPtr<Foam::FixedList<T, N>>
|
||||||
Foam::FixedList<T, N>::clone() const
|
Foam::FixedList<T, N>::clone() const
|
||||||
@ -444,15 +418,6 @@ inline const T& Foam::FixedList<T, N>::operator[](const label i) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T, unsigned N>
|
|
||||||
inline void Foam::FixedList<T, N>::operator=(const T list[N])
|
|
||||||
{
|
|
||||||
for (unsigned i=0; i<N; ++i)
|
|
||||||
{
|
|
||||||
v_[i] = list[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T, unsigned N>
|
template<class T, unsigned N>
|
||||||
inline void Foam::FixedList<T, N>::operator=(const UList<T>& list)
|
inline void Foam::FixedList<T, N>::operator=(const UList<T>& list)
|
||||||
{
|
{
|
||||||
@ -464,18 +429,6 @@ inline void Foam::FixedList<T, N>::operator=(const UList<T>& list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, unsigned N>
|
|
||||||
inline void Foam::FixedList<T, N>::operator=(const SLList<T>& list)
|
|
||||||
{
|
|
||||||
checkSize(list.size());
|
|
||||||
|
|
||||||
auto iter = list.begin();
|
|
||||||
for (unsigned i=0; i<N; ++i)
|
|
||||||
{
|
|
||||||
v_[i] = *iter;
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T, unsigned N>
|
template<class T, unsigned N>
|
||||||
inline void Foam::FixedList<T, N>::operator=(std::initializer_list<T> list)
|
inline void Foam::FixedList<T, N>::operator=(std::initializer_list<T> list)
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||||
Copyright (C) 2017-2022 OpenCFD Ltd.
|
Copyright (C) 2017-2023 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -30,7 +30,6 @@ License
|
|||||||
#include "ListLoopM.H"
|
#include "ListLoopM.H"
|
||||||
#include "FixedList.H"
|
#include "FixedList.H"
|
||||||
#include "PtrList.H"
|
#include "PtrList.H"
|
||||||
#include "SLList.H"
|
|
||||||
#include "contiguous.H"
|
#include "contiguous.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
@ -314,13 +313,6 @@ Foam::List<T>::List(const PtrList<T>& list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
Foam::List<T>::List(const SLList<T>& list)
|
|
||||||
:
|
|
||||||
List<T>(list.begin(), list.end(), list.size())
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
template<class Addr>
|
template<class Addr>
|
||||||
Foam::List<T>::List(const IndirectListBase<T, Addr>& list)
|
Foam::List<T>::List(const IndirectListBase<T, Addr>& list)
|
||||||
@ -359,15 +351,6 @@ Foam::List<T>::List(DynamicList<T, SizeMin>&& list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
Foam::List<T>::List(SLList<T>&& list)
|
|
||||||
:
|
|
||||||
UList<T>()
|
|
||||||
{
|
|
||||||
operator=(std::move(list));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
@ -463,28 +446,6 @@ void Foam::List<T>::operator=(const List<T>& list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void Foam::List<T>::operator=(const SLList<T>& list)
|
|
||||||
{
|
|
||||||
const label len = list.size();
|
|
||||||
|
|
||||||
reAlloc(len);
|
|
||||||
|
|
||||||
if (len)
|
|
||||||
{
|
|
||||||
// std::copy(list.begin(), list.end(), this->v_);
|
|
||||||
|
|
||||||
T* iter = this->begin();
|
|
||||||
|
|
||||||
for (const T& val : list)
|
|
||||||
{
|
|
||||||
*iter = val;
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
template<unsigned N>
|
template<unsigned N>
|
||||||
void Foam::List<T>::operator=(const FixedList<T, N>& list)
|
void Foam::List<T>::operator=(const FixedList<T, N>& list)
|
||||||
@ -562,22 +523,6 @@ void Foam::List<T>::operator=(DynamicList<T, SizeMin>&& list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void Foam::List<T>::operator=(SLList<T>&& list)
|
|
||||||
{
|
|
||||||
label len = list.size();
|
|
||||||
|
|
||||||
reAlloc(len);
|
|
||||||
|
|
||||||
for (T* iter = this->begin(); len--; ++iter)
|
|
||||||
{
|
|
||||||
*iter = std::move(list.removeHead());
|
|
||||||
}
|
|
||||||
|
|
||||||
list.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
@ -626,4 +571,36 @@ void Foam::sortedOrder
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Housekeeping * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#include "SLList.H"
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
Foam::List<T>::List(const SLList<T>& list)
|
||||||
|
:
|
||||||
|
List<T>(list.begin(), list.end(), list.size())
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void Foam::List<T>::operator=(const SLList<T>& list)
|
||||||
|
{
|
||||||
|
const label len = list.size();
|
||||||
|
|
||||||
|
reAlloc(len);
|
||||||
|
|
||||||
|
// Cannot use std::copy algorithm
|
||||||
|
// - SLList doesn't define iterator category
|
||||||
|
|
||||||
|
T* iter = this->begin();
|
||||||
|
|
||||||
|
for (const T& val : list)
|
||||||
|
{
|
||||||
|
*iter = val;
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
// ************************************************************************* //
|
||||||
|
|||||||
@ -103,6 +103,19 @@ class List
|
|||||||
const label len
|
const label len
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//- Read List from Istream between '(' and ')' delimiters.
|
||||||
|
//- The size is not known a priori.
|
||||||
|
bool readBracketList(Istream& is);
|
||||||
|
|
||||||
|
|
||||||
|
// Methods as per DynamicList to simplify code maintenance
|
||||||
|
|
||||||
|
//- Stub method for internal naming as per DynamicList
|
||||||
|
label capacity() const noexcept { return UList<T>::size(); }
|
||||||
|
|
||||||
|
//- Stub method for internal naming as per DynamicList
|
||||||
|
void setCapacity_nocopy(const label len) { resize_nocopy(len); }
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -164,9 +177,6 @@ public:
|
|||||||
//- Construct as copy of PtrList<T>
|
//- Construct as copy of PtrList<T>
|
||||||
explicit List(const PtrList<T>& list);
|
explicit List(const PtrList<T>& list);
|
||||||
|
|
||||||
//- Construct as copy of SLList<T>
|
|
||||||
explicit List(const SLList<T>& list);
|
|
||||||
|
|
||||||
//- Construct as copy of IndirectList contents
|
//- Construct as copy of IndirectList contents
|
||||||
template<class Addr>
|
template<class Addr>
|
||||||
explicit List(const IndirectListBase<T, Addr>& list);
|
explicit List(const IndirectListBase<T, Addr>& list);
|
||||||
@ -181,9 +191,6 @@ public:
|
|||||||
template<int SizeMin>
|
template<int SizeMin>
|
||||||
List(DynamicList<T, SizeMin>&& list);
|
List(DynamicList<T, SizeMin>&& list);
|
||||||
|
|
||||||
//- Move construct from SLList
|
|
||||||
List(SLList<T>&& list);
|
|
||||||
|
|
||||||
//- Construct from Istream
|
//- Construct from Istream
|
||||||
List(Istream& is);
|
List(Istream& is);
|
||||||
|
|
||||||
@ -279,9 +286,6 @@ public:
|
|||||||
//- Assignment operator. Takes linear time
|
//- Assignment operator. Takes linear time
|
||||||
void operator=(const List<T>& list);
|
void operator=(const List<T>& list);
|
||||||
|
|
||||||
//- Assignment to SLList operator. Takes linear time
|
|
||||||
void operator=(const SLList<T>& list);
|
|
||||||
|
|
||||||
//- Assignment from IndirectList. Takes linear time
|
//- Assignment from IndirectList. Takes linear time
|
||||||
template<class Addr>
|
template<class Addr>
|
||||||
void operator=(const IndirectListBase<T, Addr>& list);
|
void operator=(const IndirectListBase<T, Addr>& list);
|
||||||
@ -306,9 +310,6 @@ public:
|
|||||||
template<int SizeMin>
|
template<int SizeMin>
|
||||||
void operator=(DynamicList<T, SizeMin>&& list);
|
void operator=(DynamicList<T, SizeMin>&& list);
|
||||||
|
|
||||||
//- Move assignment. Takes constant time
|
|
||||||
void operator=(SLList<T>&& list);
|
|
||||||
|
|
||||||
|
|
||||||
// Reading/writing
|
// Reading/writing
|
||||||
|
|
||||||
@ -389,6 +390,13 @@ public:
|
|||||||
//- Append an element if not already in the list.
|
//- Append an element if not already in the list.
|
||||||
//FOAM_DEPRECATED_FOR(2022-10, "push_uniq()")
|
//FOAM_DEPRECATED_FOR(2022-10, "push_uniq()")
|
||||||
label appendUniq(const T& val) { return this->push_uniq(val); }
|
label appendUniq(const T& val) { return this->push_uniq(val); }
|
||||||
|
|
||||||
|
|
||||||
|
//- Copy construct from SLList
|
||||||
|
explicit List(const SLList<T>& list);
|
||||||
|
|
||||||
|
//- Copy assign from SLList in linear time
|
||||||
|
void operator=(const SLList<T>& list);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -29,21 +29,148 @@ License
|
|||||||
#include "List.H"
|
#include "List.H"
|
||||||
#include "Istream.H"
|
#include "Istream.H"
|
||||||
#include "token.H"
|
#include "token.H"
|
||||||
#include "SLList.H"
|
|
||||||
#include "contiguous.H"
|
#include "contiguous.H"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
Foam::List<T>::List(Istream& is)
|
Foam::List<T>::List(Istream& is)
|
||||||
:
|
:
|
||||||
UList<T>(nullptr, 0)
|
UList<T>()
|
||||||
{
|
{
|
||||||
this->readList(is);
|
this->readList(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
bool Foam::List<T>::readBracketList(Istream& is)
|
||||||
|
{
|
||||||
|
List<T>& list = *this;
|
||||||
|
|
||||||
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
|
||||||
|
token tok(is);
|
||||||
|
|
||||||
|
is.fatalCheck
|
||||||
|
(
|
||||||
|
"List<T>::readBracketList(Istream&) : reading first token"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!tok.isPunctuation(token::BEGIN_LIST))
|
||||||
|
{
|
||||||
|
is.putBack(tok);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// "(...)" : read element-wise.
|
||||||
|
// Uses chunk-wise reading to avoid too many re-allocations
|
||||||
|
// and avoids relocation of contiguous memory until all of the reading
|
||||||
|
// is completed. Chunks are wrapped as unique_ptr to ensure proper
|
||||||
|
// cleanup on failure.
|
||||||
|
|
||||||
|
// The choice of chunk-size is somewhat arbitrary...
|
||||||
|
constexpr label chunkSize = 128;
|
||||||
|
typedef std::unique_ptr<List<T>> chunkType;
|
||||||
|
|
||||||
|
is >> tok;
|
||||||
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
|
||||||
|
if (tok.isPunctuation(token::END_LIST))
|
||||||
|
{
|
||||||
|
// Trivial case, an empty list
|
||||||
|
list.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use all storage
|
||||||
|
list.resize(list.capacity());
|
||||||
|
|
||||||
|
// Start with a few slots, recover current memory where possible
|
||||||
|
List<chunkType> chunks(16);
|
||||||
|
if (list.empty())
|
||||||
|
{
|
||||||
|
chunks[0] = chunkType(new List<T>(chunkSize));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chunks[0] = chunkType(new List<T>(std::move(list)));
|
||||||
|
}
|
||||||
|
|
||||||
|
label nChunks = 1; // Active number of chunks
|
||||||
|
label totalCount = 0; // Total number of elements
|
||||||
|
label localIndex = 0; // Chunk-local index
|
||||||
|
|
||||||
|
while (!tok.isPunctuation(token::END_LIST))
|
||||||
|
{
|
||||||
|
is.putBack(tok);
|
||||||
|
|
||||||
|
if (chunks[nChunks-1]->size() <= localIndex)
|
||||||
|
{
|
||||||
|
// Increase number of slots (doubling)
|
||||||
|
if (nChunks >= chunks.size())
|
||||||
|
{
|
||||||
|
chunks.resize(2*chunks.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
chunks[nChunks] = chunkType(new List<T>(chunkSize));
|
||||||
|
++nChunks;
|
||||||
|
localIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
is >> chunks[nChunks-1]->operator[](localIndex);
|
||||||
|
++localIndex;
|
||||||
|
++totalCount;
|
||||||
|
|
||||||
|
is.fatalCheck
|
||||||
|
(
|
||||||
|
"List<T>::readBracketList(Istream&) : "
|
||||||
|
"reading entry"
|
||||||
|
);
|
||||||
|
|
||||||
|
is >> tok;
|
||||||
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple case
|
||||||
|
if (nChunks == 1)
|
||||||
|
{
|
||||||
|
list = std::move(*(chunks[0]));
|
||||||
|
list.resize(totalCount);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destination
|
||||||
|
list.setCapacity_nocopy(totalCount);
|
||||||
|
list.resize_nocopy(totalCount);
|
||||||
|
auto dest = list.begin();
|
||||||
|
|
||||||
|
for (label chunki = 0; chunki < nChunks; ++chunki)
|
||||||
|
{
|
||||||
|
List<T> currChunk(std::move(*(chunks[chunki])));
|
||||||
|
chunks[chunki].reset(nullptr);
|
||||||
|
|
||||||
|
const label localLen = min(currChunk.size(), totalCount);
|
||||||
|
|
||||||
|
dest = std::move
|
||||||
|
(
|
||||||
|
currChunk.begin(),
|
||||||
|
currChunk.begin(localLen),
|
||||||
|
dest
|
||||||
|
);
|
||||||
|
|
||||||
|
totalCount -= localLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
Foam::Istream& Foam::List<T>::readList(Istream& is)
|
Foam::Istream& Foam::List<T>::readList(Istream& is)
|
||||||
@ -142,15 +269,9 @@ Foam::Istream& Foam::List<T>::readList(Istream& is)
|
|||||||
}
|
}
|
||||||
else if (tok.isPunctuation(token::BEGIN_LIST))
|
else if (tok.isPunctuation(token::BEGIN_LIST))
|
||||||
{
|
{
|
||||||
// "(...)" : read as SLList and transfer contents
|
// "(...)" : read as bracketed list
|
||||||
|
is.putBack(tok);
|
||||||
list.clear(); // Clear old contents
|
this->readBracketList(is);
|
||||||
|
|
||||||
is.putBack(tok); // Putback the opening bracket
|
|
||||||
SLList<T> sll(is); // Read as singly-linked list
|
|
||||||
|
|
||||||
// Reallocate and move assign list elements
|
|
||||||
list = std::move(sll);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -29,7 +29,6 @@ License
|
|||||||
#include "UList.H"
|
#include "UList.H"
|
||||||
#include "Ostream.H"
|
#include "Ostream.H"
|
||||||
#include "token.H"
|
#include "token.H"
|
||||||
#include "SLList.H"
|
|
||||||
#include "contiguous.H"
|
#include "contiguous.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
|
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
|
||||||
@ -275,25 +274,46 @@ Foam::Istream& Foam::UList<T>::readList(Istream& is)
|
|||||||
}
|
}
|
||||||
else if (tok.isPunctuation(token::BEGIN_LIST))
|
else if (tok.isPunctuation(token::BEGIN_LIST))
|
||||||
{
|
{
|
||||||
// "(...)" : read as SLList and transfer contents
|
// "(...)" : read into list, handling size-mismatch after
|
||||||
|
|
||||||
is.putBack(tok); // Putback the opening bracket
|
is >> tok;
|
||||||
SLList<T> sll(is); // Read as singly-linked list
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
|
||||||
|
label inputLen = 0;
|
||||||
|
|
||||||
|
while (!tok.isPunctuation(token::END_LIST))
|
||||||
|
{
|
||||||
|
is.putBack(tok);
|
||||||
|
if (inputLen < len)
|
||||||
|
{
|
||||||
|
is >> list[inputLen];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Read and discard
|
||||||
|
T dummy;
|
||||||
|
is >> dummy;
|
||||||
|
}
|
||||||
|
++inputLen;
|
||||||
|
|
||||||
|
is.fatalCheck
|
||||||
|
(
|
||||||
|
"UList<T>::readList(Istream&) : "
|
||||||
|
"reading entry"
|
||||||
|
);
|
||||||
|
|
||||||
|
is >> tok;
|
||||||
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
// List lengths must match
|
// List lengths must match
|
||||||
if (sll.size() != len)
|
if (inputLen != len)
|
||||||
{
|
{
|
||||||
FatalIOErrorInFunction(is)
|
FatalIOErrorInFunction(is)
|
||||||
<< "incorrect length for UList. Read "
|
<< "incorrect length for UList. Read "
|
||||||
<< sll.size() << " expected " << len
|
<< inputLen << " expected " << len
|
||||||
<< exit(FatalIOError);
|
<< exit(FatalIOError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move assign each list element
|
|
||||||
for (label i = 0; i < len; ++i)
|
|
||||||
{
|
|
||||||
list[i] = std::move(sll.removeHead());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -50,9 +50,6 @@ Istream& List<char>::readList(Istream& is)
|
|||||||
{
|
{
|
||||||
List<char>& list = *this;
|
List<char>& list = *this;
|
||||||
|
|
||||||
// Anull list
|
|
||||||
list.clear();
|
|
||||||
|
|
||||||
is.fatalCheck(FUNCTION_NAME);
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
|
||||||
token tok(is);
|
token tok(is);
|
||||||
@ -63,6 +60,7 @@ Istream& List<char>::readList(Istream& is)
|
|||||||
{
|
{
|
||||||
// Compound: simply transfer contents
|
// Compound: simply transfer contents
|
||||||
|
|
||||||
|
list.clear(); // Clear old contents
|
||||||
list.transfer
|
list.transfer
|
||||||
(
|
(
|
||||||
dynamicCast<token::Compound<List<char>>>
|
dynamicCast<token::Compound<List<char>>>
|
||||||
@ -77,8 +75,8 @@ Istream& List<char>::readList(Istream& is)
|
|||||||
|
|
||||||
const label len = tok.labelToken();
|
const label len = tok.labelToken();
|
||||||
|
|
||||||
// Resize to actual length read
|
// Resize to length required
|
||||||
list.resize(len);
|
list.resize_nocopy(len);
|
||||||
|
|
||||||
// Binary, always contiguous
|
// Binary, always contiguous
|
||||||
|
|
||||||
@ -100,6 +98,8 @@ Istream& List<char>::readList(Istream& is)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
list.clear(); // Clear old contents
|
||||||
|
|
||||||
FatalIOErrorInFunction(is)
|
FatalIOErrorInFunction(is)
|
||||||
<< "incorrect first token, expected <int>, found "
|
<< "incorrect first token, expected <int>, found "
|
||||||
<< tok.info() << nl
|
<< tok.info() << nl
|
||||||
|
|||||||
@ -35,10 +35,11 @@ SourceFiles
|
|||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#ifndef blockMeshTools_H
|
#ifndef Foam_blockMeshTools_H
|
||||||
#define blockMeshTools_H
|
#define Foam_blockMeshTools_H
|
||||||
|
|
||||||
#include "dictionary.H"
|
#include "dictionary.H"
|
||||||
|
#include "DynamicList.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2016 OpenFOAM Foundation
|
Copyright (C) 2016 OpenFOAM Foundation
|
||||||
Copyright (C) 2021 OpenCFD Ltd.
|
Copyright (C) 2021-2023 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -40,12 +40,14 @@ void Foam::blockMeshTools::read
|
|||||||
|
|
||||||
if (tok.isLabel())
|
if (tok.isLabel())
|
||||||
{
|
{
|
||||||
|
// Label: should be int(..)
|
||||||
|
|
||||||
const label len = tok.labelToken();
|
const label len = tok.labelToken();
|
||||||
|
|
||||||
// Set list length to that read
|
// Resize to length required
|
||||||
list.resize(len);
|
list.resize_nocopy(len);
|
||||||
|
|
||||||
// Read beginning of contents
|
// Begin of contents marker
|
||||||
const char delimiter = is.readBeginList("List");
|
const char delimiter = is.readBeginList("List");
|
||||||
|
|
||||||
if (len)
|
if (len)
|
||||||
@ -59,12 +61,15 @@ void Foam::blockMeshTools::read
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read end of contents
|
// End of contents marker
|
||||||
is.readEndList("List");
|
is.readEndList("List");
|
||||||
}
|
}
|
||||||
else if (tok.isPunctuation(token::BEGIN_LIST))
|
else if (tok.isPunctuation(token::BEGIN_LIST))
|
||||||
{
|
{
|
||||||
SLList<T> sll;
|
// "(...)" : read with DynamicList and transfer contents
|
||||||
|
|
||||||
|
DynamicList<T> elements(std::move(list));
|
||||||
|
elements.clear(); // Reset addressing only
|
||||||
|
|
||||||
is >> tok;
|
is >> tok;
|
||||||
is.fatalCheck(FUNCTION_NAME);
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
@ -73,16 +78,14 @@ void Foam::blockMeshTools::read
|
|||||||
{
|
{
|
||||||
is.putBack(tok);
|
is.putBack(tok);
|
||||||
|
|
||||||
T elem;
|
read(is, elements.emplace_back(), dict);
|
||||||
read(is, elem, dict);
|
|
||||||
sll.append(elem);
|
|
||||||
|
|
||||||
is >> tok;
|
is >> tok;
|
||||||
is.fatalCheck(FUNCTION_NAME);
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the singly-linked list to this list
|
// Transfer back to regular list
|
||||||
list = std::move(sll);
|
list = std::move(elements);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user