Loading...
Searching...
No Matches
CompactIOField.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) 2011-2017 OpenFOAM Foundation
9 Copyright (C) 2018-2025 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "CompactIOField.H"
30
31// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
32
33template<class T>
34bool Foam::CompactIOField<T>::readIOcontents(bool readOnProc)
35{
36 typedef IOField<T> plain_type;
37
38 if (isReadRequired() || (isReadOptional() && headerOk()))
39 {
40 Istream& is = readStream(word::null, readOnProc);
41
42 if (!readOnProc)
43 {
44 // no-op
45 }
46 else if (isHeaderClass(typeName))
47 {
48 // Compact form
49 is >> *this; // or: this->readCompact(is);
50 }
51 else if (isHeaderClass<plain_type>())
52 {
53 // Non-compact form
54 is >> static_cast<content_type&>(*this);
55 }
56 else
57 {
59 << "Unexpected class name " << headerClassName()
60 << " expected " << typeName
61 << " or " << plain_type::typeName << nl
62 << " while reading object " << name()
63 << exit(FatalIOError);
64 }
65
66 close();
67 return true;
68 }
69
70 return false;
71}
72
73
74template<class T>
75Foam::label Foam::CompactIOField<T>::readIOsize(bool readOnProc)
76{
77 typedef IOField<T> plain_type;
78
79 label count(-1);
80
81 if (isReadRequired() || (isReadOptional() && headerOk()))
82 {
83 Istream& is = readStream(word::null, readOnProc);
84
85 if (!readOnProc)
86 {
87 // no-op
88 }
89 else
90 {
91 token tok(is);
92
93 if (tok.isLabel())
94 {
95 // The majority of files will have lists with sizing prefix
96 count = tok.labelToken();
97
98 if (isHeaderClass(typeName))
99 {
100 // Compact form: read offsets, not content
101 if (--count < 0)
102 {
103 count = 0;
104 }
105 }
106 }
107 else
108 {
109 is.putBack(tok);
110
111 if (isHeaderClass(typeName))
112 {
113 // Compact form: can just read the offsets
114 labelList offsets(is);
115 count = Foam::max(0, (offsets.size()-1));
116 }
117 else if (isHeaderClass<plain_type>())
118 {
119 // Non-compact form: need to read everything
120 Field<T> list(is);
121 count = list.size();
122 }
123 else
124 {
126 << "Unexpected class name " << headerClassName()
127 << " expected " << typeName
128 << " or " << plain_type::typeName << endl
129 << " while reading object " << name()
130 << exit(FatalIOError);
131 }
132 }
133 }
134 close();
135 }
136
137 return count;
138}
139
140
141template<class T>
142bool Foam::CompactIOField<T>::overflows() const
143{
144 // Can safely assume that int64 will not overflow
145 if constexpr (sizeof(label) < sizeof(int64_t))
146 {
147 const UList<T>& lists = *this;
148
149 label total = 0;
150 for (const auto& sublist : lists)
151 {
152 const label prev = total;
153 total += sublist.size();
154 if (total < prev)
155 {
156 return true;
157 }
158 }
159 }
160 return false;
161}
162
163
164// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
165
166template<class T>
168:
170{
171 readIOcontents();
172}
173
174
175template<class T>
177(
178 const IOobject& io,
179 const bool readOnProc
180)
181:
183{
184 readIOcontents(readOnProc);
185}
186
187
188template<class T>
190(
191 const IOobject& io,
193)
194:
196{
197 readIOcontents();
198}
199
200
201template<class T>
203(
204 const IOobject& io,
205 const label len
206)
207:
209{
210 if (!readIOcontents())
212 Field<T>::resize(len);
213 }
214}
215
216
217template<class T>
219(
220 const IOobject& io,
221 const UList<T>& content
222)
223:
224 regIOobject(io)
225{
226 if (!readIOcontents())
228 Field<T>::operator=(content);
229 }
230}
231
232
233template<class T>
235(
236 const IOobject& io,
237 Field<T>&& content
238)
239:
240 regIOobject(io)
241{
242 Field<T>::transfer(content);
243
244 readIOcontents();
245}
246
247
248// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
249
250template<class T>
252{
254 if (rio.readOpt() == IOobjectOption::READ_MODIFIED)
255 {
256 rio.readOpt(IOobjectOption::MUST_READ);
257 }
258 rio.resetHeader();
259
260 // Construct NO_READ, changing after construction
261 const auto rOpt = rio.readOpt(IOobjectOption::NO_READ);
262
263 CompactIOField<T> reader(rio);
264 reader.readOpt(rOpt);
265
266 return reader.readIOsize();
267}
268
269
270template<class T>
272{
275 {
277 }
278 rio.resetHeader();
279
280 CompactIOField<T> reader(rio);
281
282 return Field<T>(std::move(static_cast<Field<T>&>(reader)));
283}
284
285
286// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
287
288template<class T>
290(
291 IOstreamOption streamOpt,
292 const bool writeOnProc
293) const
294{
295 if
296 (
297 streamOpt.format() == IOstreamOption::BINARY
298 && overflows()
299 )
300 {
301 streamOpt.format(IOstreamOption::ASCII);
302
304 << "Overall number of elements of CompactIOField (size:"
305 << this->size() << ") overflows a label (int"
306 << (8*sizeof(label)) << ')' << nl
307 << " Switching to ascii writing" << endl;
308 }
309
310 if (streamOpt.format() != IOstreamOption::BINARY)
311 {
312 // Change type to be non-compact format type
313 const word oldTypeName(typeName);
314
315 const_cast<word&>(typeName) = IOField<T>::typeName;
316
317 bool good = regIOobject::writeObject(streamOpt, writeOnProc);
318
319 // Restore type
320 const_cast<word&>(typeName) = oldTypeName;
321
322 return good;
324
325 return regIOobject::writeObject(streamOpt, writeOnProc);
326}
327
328
329template<class T>
330bool Foam::CompactIOField<T>::writeData(Ostream& os) const
331{
332 return (os << *this).good();
333}
334
335
336// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
337
338template<class T>
340{
341 Field<T>& lists = *this;
342
343 // The base type for packed values
344 typedef typename T::value_type base_type;
345
346 // Read compact: offsets + packed values
347 const labelList offsets(is);
348 Field<base_type> values(is);
349
350 // Transcribe
351 const label len = Foam::max(0, (offsets.size()-1));
352 lists.resize_nocopy(len);
353
354 auto iter = values.begin();
355
356 for (label i = 0; i < len; ++i)
357 {
358 auto& list = lists[i];
359 const label count = (offsets[i+1] - offsets[i]);
360
361 list.resize_nocopy(count);
362
363 std::move(iter, iter + count, list.begin());
364
365 iter += count;
367
368 return is;
369}
370
371
372template<class T>
374{
375 const Field<T>& lists = *this;
376
377 // The base type for packed values
378 typedef typename T::value_type base_type;
379
380 // Convert to compact format
381 label total = 0;
382 const label len = lists.size();
383
384 // offsets
385 {
386 labelList offsets(len+1);
387
388 for (label i = 0; i < len; ++i)
389 {
390 offsets[i] = total;
391 total += lists[i].size();
392
393 if (total < offsets[i])
394 {
396 << "Overall number of elements of CompactIOField (size:"
397 << len
398 << ") overflows the representation of a label" << nl
399 << "Please recompile with a larger representation"
400 << " for label" << exit(FatalIOError);
401 }
402 }
403 offsets[len] = total;
404 os << offsets;
405 }
406
407 // packed values: make deepCopy for writing
408 {
410
411 auto iter = values.begin();
412
413 for (const auto& list : lists)
414 {
415 iter = std::copy_n(list.begin(), list.size(), iter);
416
417 // With IndirectList? [unlikely]
418 // const label count = list.size();
419 // for (label i = 0; i < count; (void)++i, (void)++iter)
420 // {
421 // *iter = list[i];
422 // }
423 }
424 os << values;
425 }
426
427 return os;
428}
429
430
431// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
432
433template<class T>
434Foam::Istream& Foam::operator>>
435(
436 Foam::Istream& is,
437 Foam::CompactIOField<T>& lists
438)
439{
440 return lists.readCompact(is);
441}
442
443
444template<class T>
445Foam::Ostream& Foam::operator<<
446(
447 Foam::Ostream& os,
448 const Foam::CompactIOField<T>& lists
449)
450{
451 // Keep ASCII writing same
453 {
455 }
456 else
457 {
458 lists.writeCompact(os);
459 }
460
461 return os;
462}
463
464
465// ************************************************************************* //
A Field of objects of type <T> with automated input and output using a compact storage....
virtual bool writeObject(IOstreamOption streamOpt, const bool writeOnProc) const
Write using stream options. Checks for overflow in binary.
static Field< T > readContents(const IOobject &io)
Read and return contents. The IOobject is never registered.
Ostream & writeCompact(Ostream &os) const
Write as offsets/packed-values.
virtual bool writeData(Ostream &os) const
Write as plain or compact content (depends on stream format).
Istream & readCompact(Istream &is)
Read as offsets/packed-values and transcribe into *this.
CompactIOField(const CompactIOField &)=default
Default copy construct.
static label readContentsSize(const IOobject &io)
Read and return content size, -1 if not read.
static const char *const typeName
Typename for Field.
Definition Field.H:93
Generic templated field type that is much like a Foam::List except that it is expected to hold numeri...
Definition Field.H:172
void operator=(const Field< Type > &)
Copy assignment.
Definition Field.C:781
constexpr Field() noexcept
@ NO_REGISTER
Do not request registration (bool: false).
readOption readOpt() const noexcept
Get the read option.
@ NO_READ
Nothing to be read.
@ MUST_READ
Reading required.
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
bool good() const noexcept
Did last readHeader() succeed?
Definition IOobjectI.H:354
void resetHeader(const word &newName=word::null)
Clear various bits (headerClassName, note, sizeof...) that would be obtained when reading from a file...
Definition IOobject.C:644
A simple container for options an IOstream can normally have.
streamFormat format() const noexcept
Get the current stream format.
@ ASCII
"ascii" (normal default)
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition Istream.H:60
void transfer(List< Type > &list)
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition ListI.H:171
void resize(const label len)
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition Ostream.H:59
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition UList.H:89
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
regIOobject is an abstract class derived from IOobject to handle automatic object registration with t...
Definition regIOobject.H:71
virtual bool writeObject(IOstreamOption streamOpt, const bool writeOnProc) const
Write using stream options.
regIOobject(const IOobject &io, const bool isTimeObject=false)
Construct from IOobject. The optional flag adds special handling if the object is the top-level regIO...
Definition regIOobject.C:43
A class for handling words, derived from Foam::string.
Definition word.H:66
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition zero.H:58
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition error.H:629
OBJstream os(runTime.globalPath()/outputName)
const auto & io
auto & name
#define WarningInFunction
Report a warning using Foam::Warning.
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition BitOps.H:73
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition HashOps.H:164
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
List< label > labelList
A List of labels.
Definition List.H:62
const word GlobalIOList< Tuple2< scalar, vector > >::typeName("scalarVectorTable")
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
IOerror FatalIOError
Error stream (stdout output on all processes), with additional 'FOAM FATAL IO ERROR' header text and ...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50