Loading...
Searching...
No Matches
DynamicListIO.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2021-2025 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
11 This file is part of OpenFOAM.
12
13 OpenFOAM is free software: you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25
26\*---------------------------------------------------------------------------*/
27
28#include "List.H"
29#include "Istream.H"
30#include "token.H"
31
32// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
33
34template<class T, int SizeMin>
36:
37 List<T>(),
38 capacity_(0)
39{
40 this->readList(is);
41}
42
43
44// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
45
46template<class T, int SizeMin>
47bool Foam::DynamicList<T, SizeMin>::readBracketList(Istream& is)
48{
49 DynamicList<T, SizeMin>& list = *this;
50
52
53 token tok(is);
54
55 is.fatalCheck
56 (
57 "DynamicList<T>::readBracketList(Istream&) : reading first token"
58 );
59
60 if (!tok.isPunctuation(token::BEGIN_LIST))
61 {
62 is.putBack(tok);
63 return false;
64 }
65
66 {
67 // "(...)" : read element-wise.
68 // Uses chunk-wise reading to avoid too many re-allocations
69 // and avoids relocation of contiguous memory until all of the reading
70 // is completed. Chunks are wrapped as unique_ptr to ensure proper
71 // cleanup on failure.
72
73 // The choice of chunk-size is somewhat arbitrary...
74 constexpr label chunkSize = 128;
75 typedef std::unique_ptr<List<T>> chunkType;
76
77 is >> tok;
79
80 if (tok.isPunctuation(token::END_LIST))
81 {
82 // Trivial case, an empty list
83 list.clear();
84 return true;
85 }
86
87 // Use all storage
88 list.resize(list.capacity());
89
90 // Start with a few slots, recover current memory where possible
91 List<chunkType> chunks(16);
92 if (list.empty())
93 {
94 chunks[0] = chunkType(new List<T>(chunkSize));
95 }
96 else
97 {
98 chunks[0] = chunkType(new List<T>(std::move(list)));
99 }
100
101 label nChunks = 1; // Active number of chunks
102 label totalCount = 0; // Total number of elements
103 label localIndex = 0; // Chunk-local index
104
105 while (!tok.isPunctuation(token::END_LIST))
106 {
107 is.putBack(tok);
108
109 if (chunks[nChunks-1]->size() <= localIndex)
110 {
111 // Increase number of slots (doubling)
112 if (nChunks >= chunks.size())
113 {
114 chunks.resize(2*chunks.size());
115 }
116
117 chunks[nChunks] = chunkType(new List<T>(chunkSize));
118 ++nChunks;
119 localIndex = 0;
120 }
121
122 is >> chunks[nChunks-1]->operator[](localIndex);
123 ++localIndex;
124 ++totalCount;
125
126 is.fatalCheck
127 (
128 "DynamicList<T>::readBracketList(Istream&) : "
129 "reading entry"
130 );
131
132 is >> tok;
134 }
135
136 // Simple case
137 if (nChunks == 1)
138 {
139 list = std::move(*(chunks[0]));
140 list.resize(totalCount);
141 return true;
142 }
143
144 // Destination
145 list.setCapacity_nocopy(totalCount);
146 list.resize_nocopy(totalCount);
147 auto dest = list.begin();
148
149 for (label chunki = 0; chunki < nChunks; ++chunki)
150 {
151 List<T> currChunk(std::move(*(chunks[chunki])));
152 chunks[chunki].reset(nullptr);
153
154 const label localLen = Foam::min(currChunk.size(), totalCount);
155
156 dest = std::move
157 (
158 currChunk.begin(),
159 currChunk.begin(localLen),
160 dest
161 );
162
163 totalCount -= localLen;
164 }
165 }
166
167 return true;
168}
169
170
171// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
172
173template<class T, int SizeMin>
175{
176 DynamicList<T, SizeMin>& list = *this;
177
179
180 token tok(is);
181
182 is.fatalCheck("DynamicList<T>::readList(Istream&) : reading first token");
183
184 if (tok.isCompound())
185 {
186 // Compound: simply transfer contents
187
188 list.clearStorage(); // Remove old contents
189 list.transfer
190 (
192 );
193 }
194 else if (tok.isLabel())
195 {
196 // Label: could be int(..), int{...} or just a plain '0'
197
198 const label len = tok.labelToken();
199
200 // Resize to length required
201 list.resize_nocopy(len);
202
203 if constexpr (std::is_same_v<char, std::remove_cv_t<T>>)
204 {
205 // Special treatment for char data (binary I/O only)
206 const auto oldFmt = is.format(IOstreamOption::BINARY);
207
208 if (len)
209 {
210 // read(...) includes surrounding start/end delimiters
211 is.read(list.data_bytes(), list.size_bytes());
212
213 is.fatalCheck
214 (
215 "DynamicList<char>::readList(Istream&) : [binary block]"
216 );
217 }
218
219 is.format(oldFmt);
220 }
221 else
222 {
224 {
225 // Binary and contiguous
226
227 if (len)
228 {
230 (
231 is,
232 list.data_bytes(),
233 list.size_bytes()
234 );
235
236 is.fatalCheck
237 (
238 "DynamicList<T>::readList(Istream&) : [binary block]"
239 );
240 }
241 }
242 else
243 {
244 // Begin of contents marker
245 const char delimiter = is.readBeginList("List");
246
247 if (len)
248 {
249 if (delimiter == token::BEGIN_LIST)
250 {
251 auto iter = list.begin();
252 const auto last = list.end();
253
254 // Contents
255 for (/*nil*/; (iter != last); (void)++iter)
256 {
257 is >> *iter;
258
259 is.fatalCheck
260 (
261 "DynamicList<T>::readList(Istream&) : "
262 "reading entry"
263 );
264 }
265 }
266 else
267 {
268 // Uniform content (delimiter == token::BEGIN_BLOCK)
269
270 T elem;
271 is >> elem;
272
273 is.fatalCheck
274 (
275 "DynamicList<T>::readList(Istream&) : "
276 "reading the single entry"
277 );
278
279 // Fill with the value
281 }
282 }
283
284 // End of contents marker
285 is.readEndList("List");
286 }
287 }
288 }
289 else if (tok.isPunctuation(token::BEGIN_LIST))
290 {
291 // "(...)" : read read as bracketed list
292
293 is.putBack(tok);
294 this->readBracketList(is);
295
296 // Could also simply be done with emplace_back for each element
297 // but prefer the same mechanism as List::readList to avoid
298 // intermediate resizing
299
300 // // list.clear(); // Clear addressing, leave storage intact
301 // //
302 // // is >> tok;
303 // // is.fatalCheck(FUNCTION_NAME);
304 // //
305 // // while (!tok.isPunctuation(token::END_LIST))
306 // // {
307 // // is.putBack(tok);
308 // // is >> list.emplace_back();
309 // //
310 // // is.fatalCheck
311 // // (
312 // // "DynamicList<T>::readList(Istream&) : "
313 // // "reading entry"
314 // // );
315 // //
316 // // is >> tok;
317 // // is.fatalCheck(FUNCTION_NAME);
318 // // }
319 }
320 else
321 {
322 list.clear(); // Clear old contents
323
325 << "incorrect first token, expected <int> or '(', found "
326 << tok.info() << nl
327 << exit(FatalIOError);
328 }
329
330 return is;
331}
332
333
334// ************************************************************************* //
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
constexpr DynamicList() noexcept
Default construct, an empty list without allocation.
void transfer(List< T > &list)
Transfer contents of the argument List into this.
void resize_nocopy(const label len)
Alter addressable list size, allocating new space if required without necessarily recovering old cont...
void setCapacity_nocopy(const label len)
Alter the size of the underlying storage, without retaining old content.
void clearStorage()
Clear the list and delete storage.
label capacity() const noexcept
Size of the underlying storage.
void resize(const label len)
Alter addressable list size, allocating new space if required while recovering old content.
Istream & readList(Istream &is)
Read from Istream, discarding existing contents.
streamFormat format() const noexcept
Get the current stream format.
bool fatalCheck(const char *operation) const
Check IOstream status for given operation.
Definition IOstream.C:51
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition Istream.H:60
char readEndList(const char *funcName)
End read of list data, ends with ')' or '}'.
Definition Istream.C:192
char readBeginList(const char *funcName)
Begin read of list data, starts with '(' or '{'.
Definition Istream.C:171
void putBack(const token &tok)
Put back a token (copy). Only a single put back is permitted.
Definition Istream.C:71
virtual Istream & read(token &)=0
Return next token from stream.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition UListI.H:410
char * data_bytes() noexcept
Return pointer to the underlying array serving as data storage,.
Definition UListI.H:288
bool empty() const noexcept
True if List is empty (ie, size() is zero).
Definition UList.H:701
iterator end() noexcept
Return an iterator to end traversing the UList.
Definition UListI.H:454
std::streamsize size_bytes() const noexcept
Number of contiguous bytes for the List data.
Definition UListI.H:295
T & last()
Access last element of the list, position [size()-1].
Definition UList.H:971
UList< T > & operator=(const UList< T > &)=delete
No copy assignment (default: shallow copy).
A token holds an item read from Istream.
Definition token.H:70
bool isPunctuation() const noexcept
Token is PUNCTUATION.
Definition tokenI.H:650
@ BEGIN_LIST
Begin list [isseparator].
Definition token.H:174
@ END_LIST
End list [isseparator].
Definition token.H:175
bool isLabel() const noexcept
Integral token is convertible to Foam::label.
Definition tokenI.H:843
label labelToken() const
Return integer type as label value or Error.
Definition tokenI.H:869
compound & transferCompoundToken(const Istream *is=nullptr)
Return reference to compound and mark internally as released.
Definition token.C:157
bool isCompound() const noexcept
Token is COMPOUND.
Definition tokenI.H:1096
InfoProxy< token > info() const noexcept
Return info proxy, for printing token information to a stream.
Definition token.H:1253
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition error.H:629
#define FUNCTION_NAME
void readContiguous(Istream &is, char *data, std::streamsize byteCount)
Read binary block of contiguous data, possibly with conversion.
Definition Istream.H:322
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
IOerror FatalIOError
Error stream (stdout output on all processes), with additional 'FOAM FATAL IO ERROR' header text and ...
constexpr bool is_contiguous_v
The is_contiguous value of Type (after stripping of qualifiers).
Definition contiguous.H:77
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50