Loading...
Searching...
No Matches
exprValue.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-2024 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 "exprValue.H"
29#include "error.H"
30#include "ITstream.H"
31#include "Switch.H"
32#include <cstring> // For memcpy, memset
33
34// * * * * * * * * * * * * * * * * Details * * * * * * * * * * * * * * * * //
35
37(
38 const std::string& msg
39) noexcept
40{
42 << "non-specialized: " << msg.c_str() << endl
43 << abort(FatalError);
44}
45
46
47// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
48
49namespace Foam
50{
51
52#if 0
53// General way to add tokens for fundamental and VectorSpace types
54// (caller excludes none/invalid)
55template<class Type>
56static void addTokens(tokenList& toks, const Type& val)
57{
58 if constexpr (std::is_same_v<bool, Type>)
59 {
60 // For bool
61 toks.emplace_back() = token::boolean(val);
62 }
63 else if constexpr (std::is_arithmetic_v<Type>)
64 {
65 // For label, float, double, ...
66 toks.emplace_back() = val;
67 }
68 else
69 {
71
72 constexpr direction nParen =
73 2*(is_vectorspace_v<Type> || (nCmpt > 1) ? 1 : 0);
74
75 const label nOld = toks.size();
76 toks.resize(nOld + label(nCmpt + nParen));
77
78 auto iter = toks.begin(nOld);
79
80 if (nParen)
81 {
82 *iter = token::BEGIN_LIST;
83 ++iter;
84 }
85
86 for (direction cmpt = 0; cmpt < nCmpt; ++cmpt)
87 {
88 *iter = component(val, cmpt);
89 ++iter;
90 }
91
92 if (nParen)
93 {
94 *iter = token::END_LIST;
95 ++iter;
96 }
97 }
99
100#endif
101
102
103// General output of type (caller excludes none/invalid)
104template<class Type>
105static void putType(Ostream& os, const Type& val)
106{
107 os << val;
108}
110
111//- Specialized for bool.
112//- Write as (true/false) via Switch to avoid bool/label ambiguity
113template<>
114void putType<bool>(Ostream& os, const bool& val)
115{
116 // Note: prefer Switch() vs (std::ios::boolalpha) to avoid any
117 // potential locale issues.
118 os << Switch(val);
119}
120
121
122//- Specialized for scalar.
123//- Write with '.' to avoid scalar/label ambiguity
124template<>
125void putType<scalar>(Ostream& os, const scalar& val)
126{
127 const auto oldflags = os.setf(std::ios::showpoint);
128 os << val;
129 os.flags(oldflags); // Restore
130}
131
132} // End namespace Foam
133
134
135// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
136
139{
141
142 const token& tok0 = is.peek();
143
145 {
146 // Expecting "( content )" - eg, (x y z), (xx xy ...)
147
148 // First component starts after the opening '('.
149 // Can use the current index if the '(' actually came from
150 // the putBack.
151
152 const label firstCmpti = (is.tokenIndex() + (is.hasPutback() ? 0 : 1));
153
154 // Search for closing ')', require all components to be numbers
155 for (label endCmpti = firstCmpti; endCmpti < is.size(); ++endCmpti)
156 {
157 const token& tok = is[endCmpti];
158
162
164 {
165 // Select based on the number of components
166 // cf. pTraits<Type>::nComponents
167
168 switch (endCmpti - firstCmpti)
169 {
170 case 0: // Explicitly provided '()' - ie, none
172 break;
173
174 case 1: // pTraits<sphericalTensor>::nComponents
176 break;
177
178 // FUTURE?
179 // case 2: // pTraits<complex>::nComponents
180 // whichCode = exprTypeTraits<complex>::value;
181 // break;
182
183 case 3: // pTraits<vector>::nComponents
185 break;
186
187 case 6: // pTraits<symmTensor>::nComponents
189 break;
190
191 case 9: // pTraits<tensor>::nComponents
193 break;
194 }
195
196 // Closing ')' terminates peeking
197 break;
198 }
199 else if (!tok.isNumber())
200 {
201 // All components should be numeric
202 break;
203 }
204 }
205 }
206 else if (tok0.good())
207 {
209
210 if (tok0.isScalar())
211 {
213 }
214 else if (tok0.isLabel())
215 {
217 }
218 else if (Switch(tok0).good())
219 {
220 whichCode = exprTypeTraits<bool>::value;
221 }
222
223 // Treat anything else as 'invalid', which also implicitly
224 // includes the token "bad"
225 // else if (tok0.isWord("bad"))
226 // {
227 // whichCode = expressions::valueTypeCode::INVALID;
228 // }
229 }
230
231 return whichCode;
233
234
236(
237 const std::string& str,
238 exprValue& val
239)
240{
241 ITstream is(str);
242
243 // No trailing non-whitespace!
244 return (val.readTokens(is) && !is.nRemainingTokens());
245}
246
248// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
249
251{
252 std::memset(static_cast<void*>(this), '\0', sizeof(*this));
253 // Redundant: typeCode_ = expressions::valueTypeCode::NONE;
254}
255
256
257void Foam::expressions::exprValue::deepCopy(const exprValue& rhs)
258{
259 if (this != &rhs)
260 {
261 // Self-assignment is a no-op
262 std::memcpy(static_cast<void*>(this), &rhs, sizeof(*this));
263 }
264}
265
266
267#if 0
268Foam::tokenList Foam::expressions::exprValue::tokens(bool prune) const
269{
270 // Handling for NONE, INVALID:
271 // - NONE => pair of ( ) brackets
272 // - INVALID => "bad" as a word
273 //
274 // With prune:
275 // - no output for either
276
277 tokenList toks;
278
279 switch (typeCode_)
280 {
282 {
283 if (!prune)
284 {
285 toks.resize(2);
286 toks.front() = token::BEGIN_LIST;
287 toks.back() = token::END_LIST;
288 }
289 break;
290 }
291
293 {
294 if (!prune)
295 {
296 toks.emplace_back(word("bad"));
297 }
298 break;
299 }
300
301 #undef doLocalCode
302 #define doLocalCode(Type, UnusedParam) \
303 \
304 case expressions::valueTypeCode::type_##Type : \
305 { \
306 const Type* dataPtr = data_.get<Type>(); \
307 if (dataPtr) \
308 { \
309 addTokens<Type>(toks, *dataPtr); \
310 } \
311 break; \
312 }
313
315 #undef doLocalCode
316
317 // exprValue may only be a subset of valueTypeCode types
318 default: break;
319 }
320
321 return toks;
322}
323#endif
324
325
326void Foam::expressions::exprValue::write(Ostream& os, bool prune) const
327{
328 // Handling for NONE, INVALID:
329 // - NONE => pair of ( ) brackets
330 // - INVALID => "bad" as a word
331 //
332 // With prune:
333 // - no output for either
334
335 switch (typeCode_)
336 {
338 {
339 if (!prune)
340 {
342 }
343 break;
344 }
345
347 {
348 if (!prune)
349 {
350 os << word("bad");
351 }
352 break;
353 }
354
355 #undef doLocalCode
356 #define doLocalCode(Type, UnusedParam) \
357 \
358 case expressions::valueTypeCode::type_##Type : \
359 { \
360 const Type* dataPtr = data_.get<Type>(); \
361 if (dataPtr) \
362 { \
363 putType(os, *dataPtr); \
364 } \
365 break; \
366 }
367
369 #undef doLocalCode
370
371 // exprValue may only be a subset of valueTypeCode types
372 default: break;
373 }
375
376
378{
379 ITstream* stream = dynamic_cast<ITstream*>(&is);
380
381 // Reading via tokens - simple for now
382 // Expect either a single token (scalar, label, word etc)
383 // or ( ... ) content
384
385 ITstream toks;
386
387 if (!stream)
388 {
389 token tok(is);
390
392
394 {
395 // Expecting "( content )" - eg, (x y z), (xx xy ...)
396 do
397 {
398 toks.add_tokens(tok);
399
400 is >> tok;
402 }
403 while (!tok.isPunctuation(token::END_LIST));
404
406 {
407 toks.add_tokens(tok);
408 }
409 }
410 else if (tok.good())
411 {
412 toks.add_tokens(tok);
413 }
414
415 // Truncate to number tokens read
416 toks.resize(toks.tokenIndex());
417 toks.seek(0);
418
419 stream = &toks;
420 }
421
422 return readTokens(*stream);
424
425
427{
428 clear(); // type: none, value: zero
429
430 const valueTypeCode whichCode(exprValue::peekType(is));
431
432 switch (whichCode)
433 {
435 {
436 typeCode_ = whichCode;
437 is.skip(2); // Skip tokens: '( )'
438 return true;
439 }
440
441 // This one should be rare or even impossible
443 {
444 typeCode_ = whichCode;
445 if (!is.bad() && is.peek().isWord("bad"))
446 {
447 is.skip(1); // Skip token: "bad"
448 return true;
449 }
450 return false; // Some type of failure..
451 }
452
453 #undef doLocalCode
454 #define doLocalCode(Type, UnusedParam) \
455 \
456 case expressions::valueTypeCode::type_##Type : \
457 { \
458 data_.set<Type>(pTraits<Type>(is)); \
459 typeCode_ = whichCode; \
460 return true; \
461 }
462
464 #undef doLocalCode
465
466 // exprValue may only be a subset of valueTypeCode types
467 default: break;
468 }
469
470 return false;
472
473
475(
476 const exprValue& rhs
477) const
478{
479 if (typeCode_ != rhs.typeCode_)
480 {
481 // First compare by type
482 return (int(typeCode_) - int(rhs.typeCode_));
483 }
484 else if ((this == &rhs) || !good())
485 {
486 // Identical: same object or not good
487 // (ie, no further comparison possible)
488 return 0;
489 }
490
491 // Types are identical (and good)
492 // - compare by value.
493 // This is even messier than usual, since can only rely on
494 // operator< being defined
495
496 switch (typeCode_)
497 {
498 #undef doLocalCode
499 #define doLocalCode(Type, UnusedParam) \
500 \
501 case expressions::valueTypeCode::type_##Type : \
502 { \
503 const Type* a = data_.get<Type>(); \
504 const Type* b = rhs.data_.get<Type>(); \
505 return \
506 ( \
507 (a && b) \
508 ? ((*a < *b) ? -1 : (*b < *a) ? 1 : 0) \
509 : 0 \
510 ); \
511 break; \
512 }
513
515 #undef doLocalCode
516
517 // exprValue may only be a subset of valueTypeCode types
518 default: break;
519 }
520
521 // Should not happen
522 return 0;
523}
524
526// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
527
529{
530 if (typeCode_ != rhs.typeCode_)
531 {
532 // Types must match
533 return false;
534 }
535 else if (this == &rhs)
536 {
537 return true;
538 }
539
540 switch (typeCode_)
541 {
542 #undef doLocalCode
543 #define doLocalCode(Type, UnusedParam) \
544 \
545 case expressions::valueTypeCode::type_##Type : \
546 { \
547 const Type* a = data_.get<Type>(); \
548 const Type* b = rhs.data_.get<Type>(); \
549 return (a && b && (*a == *b)); \
550 break; \
551 }
552
554 #undef doLocalCode
555
556 // exprValue may only be a subset of valueTypeCode types
557 default: break;
558 }
559
560 return false;
565{
566 return (this->compare(rhs) < 0);
567}
568
570// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
571
572Foam::Istream& Foam::operator>>
573(
574 Istream& is,
576)
577{
578 val.read(is);
579 return is;
581
582
583Foam::Ostream& Foam::operator<<
584(
585 Ostream& os,
586 const expressions::exprValue& val
587)
588{
589 val.write(os, false); // no pruning
590 return os;
591}
593
594template<>
595Foam::Ostream& Foam::operator<<
596(
597 Ostream& os,
599)
600{
601 const auto& val = *iproxy;
602
603 if (val.typeCode() == expressions::valueTypeCode::NONE)
604 {
605 os << "none";
606 }
607 else if (val.typeCode() == expressions::valueTypeCode::INVALID)
608 {
609 os << "bad";
610 }
611 else
612 {
613 os << val.valueTypeName() << ": ";
614 val.write(os); // pruning is immaterial - !good() already handled
615 }
616
617 return os;
618}
619
620
621// ************************************************************************* //
bool fatalCheck(const char *operation) const
Check IOstream status for given operation.
Definition IOstream.C:51
bool bad() const noexcept
True if stream is corrupted.
Definition IOstream.H:305
An input stream of tokens.
Definition ITstream.H:56
void add_tokens(const token &tok)
Copy append a token at the current tokenIndex, incrementing the index.
Definition ITstream.C:709
label tokenIndex() const noexcept
The current token index when reading, or the insertion point.
Definition ITstream.H:412
void seek(label pos) noexcept
Move tokenIndex to the specified position and adjust the stream status (open/good/eof ....
Definition ITstream.C:353
label nRemainingTokens() const noexcept
Number of tokens remaining.
Definition ITstream.H:432
bool skip(label n=1) noexcept
Move tokenIndex relative to the current position.
Definition ITstream.C:385
const token & peek() const noexcept
Failsafe peek at what the next read would return, including handling of any putback.
Definition ITstream.C:327
bool hasPutback() const noexcept
True if putback token is in use.
Definition ITstream.H:357
A helper class for outputting values to Ostream.
Definition InfoProxy.H:49
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition Istream.H:60
T & emplace_back(Args &&... args)
Construct an element at the end of the list, return reference to the new list element.
Definition ListI.H:206
void resize(const label len)
Adjust allocated size of list.
Definition ListI.H:153
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition Ostream.H:59
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition Switch.H:81
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition UListI.H:410
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
A polymorphic typed union of simple primitive and VectorSpace types. It uses a 'fatter' representatio...
Definition exprValue.H:158
exprValue()
Default construct (zero-initialized) as 'none'.
Definition exprValueI.H:92
static expressions::valueTypeCode peekType(const ITstream &is)
Detect the type from the available tokens.
Definition exprValue.C:135
int compare(const exprValue &rhs) const
Compare (type,value).
Definition exprValue.C:472
bool good() const noexcept
True if the value type is not none/invalid.
Definition exprValueI.H:123
static bool read(const std::string &str, exprValue &val)
Read entire string as a exprValue, skipping leading/trailing whitespace.
Definition exprValue.C:233
void write(Ostream &os, bool prune=false) const
Write the (type-specific) content.
Definition exprValue.C:323
bool readTokens(ITstream &is)
Guess type and read tokens (if possible).
Definition exprValue.C:423
bool operator==(const exprValue &rhs) const
Compare (type,value) for equality.
Definition exprValue.C:525
void clear()
Reset to 'none'.
Definition exprValue.C:247
static bool good(const expressions::valueTypeCode) noexcept
True if valueTypeCode is not none/invalid.
Definition exprValueI.H:26
bool operator<(const exprValue &rhs) const
Compare (type,value).
Definition exprValue.C:561
A token holds an item read from Istream.
Definition token.H:70
bool isNumber() const noexcept
Token is (signed/unsigned) integer type, FLOAT or DOUBLE.
Definition tokenI.H:992
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
bool good() const noexcept
True if token is not UNDEFINED or ERROR.
Definition tokenI.H:584
bool isScalar() const noexcept
Token is FLOAT or DOUBLE.
Definition tokenI.H:971
bool isWord() const noexcept
Token is word-variant (WORD, DIRECTIVE).
Definition tokenI.H:1004
static token boolean(bool on) noexcept
Create a bool token.
Definition tokenI.H:26
A class for handling words, derived from Foam::string.
Definition word.H:66
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
#define FOR_ALL_EXPR_VALUE_TYPES(Macro,...)
Definition exprValue.H:49
OBJstream os(runTime.globalPath()/outputName)
#define doLocalCode(FieldType, Variable)
surface1 clear()
#define FUNCTION_NAME
valueTypeCode
An enumeration of known and expected expression value types.
Definition exprTraits.H:82
@ NONE
No type, or default initialized type.
Definition exprTraits.H:83
@ INVALID
Invalid/unknown/error type.
Definition exprTraits.H:84
Namespace for OpenFOAM.
static void putType(Ostream &os, const Type &val)
Definition exprValue.C:98
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
void putType< scalar >(Ostream &os, const scalar &val)
Specialized for scalar. Write with '.' to avoid scalar/label ambiguity.
Definition exprValue.C:122
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
constexpr bool is_vectorspace_v
The is_vectorspace value of Type.
Definition pTraits.H:244
errorManip< error > abort(error &err)
Definition errorManip.H:139
uint8_t direction
Definition direction.H:49
void rhs(fvMatrix< typename Expr::value_type > &m, const Expr &expression)
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
List< token > tokenList
List of token, used for dictionary primitive entry (for example).
Definition tokenList.H:32
void putType< bool >(Ostream &os, const bool &val)
Specialized for bool. Write as (true/false) via Switch to avoid bool/label ambiguity.
Definition exprValue.C:109
static constexpr::Foam::expressions::valueTypeCode value
Definition exprTraits.H:151
The vector-space number of components: default is 1.
Definition pTraits.H:140
static void notSpecialized(const std::string &msg) noexcept
Runtime 'assert' for unimplemented generic methods.
Definition exprValue.C:30