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-2023 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
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 "ITstream.H"
30 #include "Switch.H"
31 #include <cstring> // For memcpy, memset
32 
33 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
34 
35 namespace Foam
36 {
37 
38 template<class Type>
39 static void fillTokens(const Type& val, tokenList& toks)
40 {
42  const direction nParen = 2*(pTraits<Type>::rank || (nCmpt > 1) ? 1 : 0);
43 
44  toks.resize_nocopy(nCmpt + nParen);
45 
46  auto iter = toks.begin();
47 
48  if (nParen)
49  {
50  *iter = token::BEGIN_LIST;
51  ++iter;
52  }
53 
54  for (direction cmpt = 0; cmpt < nCmpt; ++cmpt)
55  {
56  *iter = component(val, cmpt);
57  ++iter;
58  }
59 
60  if (nParen)
61  {
62  *iter = token::END_LIST;
63  ++iter;
64  }
65 }
66 
67 
68 //- Specialized for bool
69 template<>
70 void fillTokens<bool>(const bool& val, tokenList& toks)
71 {
72  toks.resize_nocopy(1);
73  toks.front() = token::boolean(val);
74 }
75 
76 
77 //- Specialized for label
78 template<>
79 void fillTokens<label>(const label& val, tokenList& toks)
80 {
81  toks.resize_nocopy(1);
82  toks.front() = val;
83 }
84 
85 
86 //- Specialized for scalar
87 template<>
88 void fillTokens<scalar>(const scalar& val, tokenList& toks)
89 {
90  toks.resize_nocopy(1);
91  toks.front() = val;
92 }
93 
94 } // End namespace Foam
95 
96 
97 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
98 
101 {
103 
104  const token& tok0 = is.peek();
105 
107  {
108  // Expecting "( content )" - eg, (x y z), (xx xy ...)
109 
110  // First component starts after the opening '('.
111  // Can use the current index if the '(' actually came from
112  // the putBack.
113 
114  const label firstCmpti = (is.tokenIndex() + (is.hasPutback() ? 0 : 1));
115 
116  // Search for closing ')', require all components to be numbers
117  for (label endCmpti = firstCmpti; endCmpti < is.size(); ++endCmpti)
118  {
119  const token& tok = is[endCmpti];
120 
124 
126  {
127  // Select based on the number of components
128  // cf. pTraits<Type>::nComponents
129 
130  switch (endCmpti - firstCmpti)
131  {
132  case 0: // Explicitly provided '()' - ie, none
134  break;
135 
136  case 1: // pTraits<sphericalTensor>::nComponents
138  break;
139 
140  // FUTURE?
141  // case 2: // pTraits<complex>::nComponents
142  // whichCode = exprTypeTraits<complex>::value;
143  // break;
144 
145  case 3: // pTraits<vector>::nComponents
146  whichCode = exprTypeTraits<vector>::value;
147  break;
148 
149  case 6: // pTraits<symmTensor>::nComponents
151  break;
152 
153  case 9: // pTraits<tensor>::nComponents
154  whichCode = exprTypeTraits<tensor>::value;
155  break;
156  }
157 
158  // Closing ')' terminates peeking
159  break;
160  }
161  else if (!tok.isNumber())
162  {
163  // All components should be numeric
164  break;
165  }
166  }
167  }
168  else if (tok0.good())
169  {
171 
172  if (tok0.isScalar())
173  {
174  whichCode = exprTypeTraits<scalar>::value;
175  }
176  else if (tok0.isLabel())
177  {
178  whichCode = exprTypeTraits<label>::value;
179  }
180  else if (Switch(tok0).good())
181  {
182  whichCode = exprTypeTraits<bool>::value;
183  }
184 
185  // Treat anything else as 'invalid', which also implicitly
186  // includes the token "bad"
187  // else if (tok0.isWord("bad"))
188  // {
189  // whichCode = expressions::valueTypeCode::INVALID;
190  // }
191  }
192 
193  return whichCode;
194 }
195 
196 
198 (
199  const std::string& str,
200  exprValue& val
201 )
202 {
203  ITstream is(str);
204 
205  // No trailing non-whitespace!
206  return (val.readTokens(is) && !is.nRemainingTokens());
207 }
208 
209 
210 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
213 {
214  std::memset(static_cast<void*>(this), '\0', sizeof(*this));
215  // Redundant: typeCode_ = expressions::valueTypeCode::NONE;
216 }
217 
218 
219 void Foam::expressions::exprValue::deepCopy(const exprValue& rhs)
220 {
221  if (this != &rhs)
222  {
223  // Self-assignment is a no-op
224  std::memcpy(static_cast<void*>(this), &rhs, sizeof(*this));
225  }
226 }
227 
230 {
231  // Handling for NONE, INVALID:
232  // - NONE => pair of ( ) brackets
233  // - INVALID => "bad" as a word
234  //
235  // With prune:
236  // - no output for either
237 
238  tokenList toks;
239 
240  if (!prune)
241  {
242  if (typeCode_ == expressions::valueTypeCode::NONE)
243  {
244  toks.resize(2);
245  toks.front() = token::BEGIN_LIST;
246  toks.back() = token::END_LIST;
247  return toks;
248  }
249  else if (typeCode_ == expressions::valueTypeCode::INVALID)
250  {
251  toks.emplace_back(word("bad"));
252  return toks;
253  }
254  }
255 
256  switch (typeCode_)
257  {
258  #undef doLocalCode
259  #define doLocalCode(Type, UnusedParam) \
260  \
261  case expressions::valueTypeCode::type_##Type : \
262  { \
263  const Type* dataPtr = data_.get<Type>(); \
264  if (dataPtr) \
265  { \
266  fillTokens<Type>(*dataPtr, toks); \
267  } \
268  break; \
269  }
270 
272  #undef doLocalCode
273 
274  // exprValue may only be a subset of valueTypeCode types
275  default: break;
276  }
277 
278  return toks;
279 }
280 
282 void Foam::expressions::exprValue::write(Ostream& os, bool prune) const
283 {
284  // Handling for NONE, INVALID:
285  // - NONE => pair of ( ) brackets
286  // - INVALID => "bad" as a word
287  //
288  // With prune:
289  // - no output for either
290 
291  if (!prune)
292  {
293  if (typeCode_ == expressions::valueTypeCode::NONE)
294  {
296  return;
297  }
298  else if (typeCode_ == expressions::valueTypeCode::INVALID)
299  {
300  os << word("bad");
301  return;
302  }
303  }
304 
305  switch (typeCode_)
306  {
307  #undef doLocalCode
308  #define doLocalCode(Type, UnusedParam) \
309  \
310  case expressions::valueTypeCode::type_##Type : \
311  { \
312  const Type* dataPtr = data_.get<Type>(); \
313  if (dataPtr) \
314  { \
315  os << *dataPtr; \
316  } \
317  break; \
318  }
319 
321  #undef doLocalCode
322 
323  // exprValue may only be a subset of valueTypeCode types
324  default: break;
325  }
326 }
327 
330 {
331  ITstream* stream = dynamic_cast<ITstream*>(&is);
332 
333  // Reading via tokens - simple for now
334  // Expect either a single token (scalar, label, word etc)
335  // or ( ... ) content
336 
337  ITstream toks;
338 
339  if (!stream)
340  {
341  token tok(is);
342 
344 
346  {
347  // Expecting "( content )" - eg, (x y z), (xx xy ...)
348  do
349  {
350  toks.add_tokens(tok);
351 
352  is >> tok;
354  }
355  while (!tok.isPunctuation(token::END_LIST));
356 
358  {
359  toks.add_tokens(tok);
360  }
361  }
362  else if (tok.good())
363  {
364  toks.add_tokens(tok);
365  }
366 
367  // Truncate to number tokens read
368  toks.resize(toks.tokenIndex());
369  toks.seek(0);
370 
371  stream = &toks;
372  }
373 
374  return readTokens(*stream);
375 }
376 
379 {
380  clear(); // type: none, value: zero
381 
382  const valueTypeCode whichCode(exprValue::peekType(is));
383 
384  if (whichCode == expressions::valueTypeCode::NONE)
385  {
386  typeCode_ = whichCode;
387  is.skip(2); // Skip tokens: '( )'
388  return true;
389  }
390 
391  // This one should be rare or even impossible
392  if (whichCode == expressions::valueTypeCode::INVALID)
393  {
394  typeCode_ = whichCode;
395 
396  if (is.bad())
397  {
398  return false;
399  }
400 
401  const token& tok0 = is.peek();
402 
403  if (tok0.isWord("bad"))
404  {
405  is.skip(1); // Skip token: "bad"
406  return true;
407  }
408  }
409 
410  switch (whichCode)
411  {
412  #undef doLocalCode
413  #define doLocalCode(Type, UnusedParam) \
414  \
415  case expressions::valueTypeCode::type_##Type : \
416  { \
417  data_.set<Type>(pTraits<Type>(is)); \
418  typeCode_ = whichCode; \
419  return true; \
420  }
421 
423  #undef doLocalCode
424 
425  // exprValue may only be a subset of valueTypeCode types
426  default: break;
427  }
428 
429  return false;
430 }
431 
432 
433 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
436 {
437  if (typeCode_ != rhs.typeCode_)
438  {
439  // Types must match
440  return false;
441  }
442  else if (this == &rhs)
443  {
444  return true;
445  }
446 
447  switch (typeCode_)
448  {
449  #undef doLocalCode
450  #define doLocalCode(Type, UnusedParam) \
451  \
452  case expressions::valueTypeCode::type_##Type : \
453  { \
454  const Type* a = data_.get<Type>(); \
455  const Type* b = rhs.data_.get<Type>(); \
456  return (a && b && (*a == *b)); \
457  break; \
458  }
459 
461  #undef doLocalCode
462 
463  // exprValue may only be a subset of valueTypeCode types
464  default: break;
465  }
466 
467  return false;
468 }
469 
472 {
473  // Not yet sortable
474  return false;
475 }
476 
477 
478 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
479 
480 Foam::Istream& Foam::operator>>
481 (
482  Istream& is,
484 )
485 {
486  val.read(is);
487  return is;
488 }
489 
490 
491 Foam::Ostream& Foam::operator<<
492 (
493  Ostream& os,
494  const expressions::exprValue& val
495 )
496 {
497  val.write(os, false); // no pruning
498  return os;
499 }
500 
501 
502 template<>
503 Foam::Ostream& Foam::operator<<
504 (
505  Ostream& os,
506  const InfoProxy<expressions::exprValue>& iproxy
507 )
508 {
509  const auto& val = *iproxy;
510 
512  {
513  os << "none";
514  }
516  {
517  os << "bad";
518  }
519  else
520  {
521  os << val.valueTypeName() << ": ";
522  val.write(os); // pruning is immaterial - !good() already handled
523  }
524 
525  return os;
526 }
527 
528 
529 // ************************************************************************* //
void add_tokens(const token &tok)
Copy append a token at the current tokenIndex, incrementing the index.
Definition: ITstream.C:735
void fillTokens< scalar >(const scalar &val, tokenList &toks)
Specialized for scalar.
Definition: exprValue.C:87
bool good() const noexcept
True if token is not UNDEFINED or ERROR.
Definition: tokenI.H:507
bool isPunctuation() const noexcept
Token is PUNCTUATION.
Definition: tokenI.H:561
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
bool good() const noexcept
True if the Switch represents a valid enumeration.
Definition: Switch.C:307
bool isWord() const noexcept
Token is word-variant (WORD, DIRECTIVE)
Definition: tokenI.H:711
uint8_t direction
Definition: direction.H:46
void seek(label pos)
Move tokenIndex to the specified position.
Definition: ITstream.C:380
bool bad() const noexcept
True if stream is corrupted.
Definition: IOstream.H:305
static void fillTokens(const Type &val, tokenList &toks)
Definition: exprValue.C:32
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:56
A polymorphic typed union of simple primitive and VectorSpace types. It uses a &#39;fatter&#39; representatio...
Definition: exprValue.H:164
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
A token holds an item read from Istream.
Definition: token.H:65
T & front()
Access first element of the list, position [0].
Definition: UListI.H:237
A traits class, which is primarily used for primitives and vector-space.
Definition: pTraits.H:75
No type, or default initialized type.
A simple wrapper around bool so that it can be read as a word: true/false, on/off, yes/no, any/none. Also accepts 0/1 as a string and shortcuts t/f, y/n.
Definition: Switch.H:77
Begin list [isseparator].
Definition: token.H:161
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:175
label tokenIndex() const noexcept
The current token index when reading, or the insertion point.
Definition: ITstream.H:351
label nRemainingTokens() const noexcept
Number of tokens remaining.
Definition: ITstream.H:371
List< token > tokenList
List of token, used for dictionary primitive entry (for example)
Definition: tokenList.H:32
bool isScalar() const noexcept
Token is FLOAT or DOUBLE.
Definition: tokenI.H:663
const token & peek() const
Failsafe peek at what the next read would return, including handling of any putback.
Definition: ITstream.C:354
void fillTokens< bool >(const bool &val, tokenList &toks)
Specialized for bool.
Definition: exprValue.C:65
Invalid/unknown/error type.
A class for handling words, derived from Foam::string.
Definition: word.H:63
static expressions::valueTypeCode peekType(const ITstream &is)
Detect the type from the available tokens.
Definition: exprValue.C:99
bool hasPutback() const noexcept
True if putback token is in use.
Definition: ITstream.H:305
static bool read(const std::string &str, exprValue &val)
Read entire string as a exprValue, skipping leading/trailing whitespace.
Definition: exprValue.C:197
valueTypeCode
An enumeration of known and expected expression value types.
Definition: exprTraits.H:81
End list [isseparator].
Definition: token.H:162
patchWriters clear()
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition: UListI.H:391
bool operator<(const exprValue &rhs) const
Compare (type,value) - currently not implemented.
Definition: exprValue.C:470
void write(Ostream &os, bool prune=false) const
Write the (type-specific) content.
Definition: exprValue.C:281
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
word valueTypeName() const
The name for the value type. Similar to pTraits typeName.
Definition: exprValueI.H:150
bool readTokens(ITstream &is)
Guess type and read tokens (if possible)
Definition: exprValue.C:377
bool operator==(const exprValue &rhs) const
Compare (type,value) for equality.
Definition: exprValue.C:434
OBJstream os(runTime.globalPath()/outputName)
#define FUNCTION_NAME
T & emplace_back(Args &&... args)
Construct an element at the end of the list, return reference to the new list element.
Definition: ListI.H:212
Simple type identifiers for polymorphic expression values. The definitions are similar to std::integr...
Definition: exprTraits.H:143
#define doLocalCode(Type, UnusedParam)
bool fatalCheck(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:51
#define FOR_ALL_EXPR_VALUE_TYPES(Macro,...)
Definition: exprValue.H:51
static token boolean(bool on) noexcept
Create a bool token.
Definition: tokenI.H:26
expressions::valueTypeCode typeCode() const noexcept
The value type code.
Definition: exprValue.H:284
bool isLabel() const noexcept
Token is LABEL.
Definition: tokenI.H:599
T & back()
Access last element of the list, position [size()-1].
Definition: UListI.H:251
void fillTokens< label >(const label &val, tokenList &toks)
Specialized for label.
Definition: exprValue.C:76
void clear()
Reset to &#39;none&#39;.
Definition: exprValue.C:211
bool skip(label n=1)
Move tokenIndex relative to the current position.
Definition: ITstream.C:427
bool isNumber() const noexcept
Token is LABEL, FLOAT or DOUBLE.
Definition: tokenI.H:689
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
An input stream of tokens.
Definition: ITstream.H:52
Namespace for OpenFOAM.
tokenList tokens(bool prune=false) const
The exprValue as tokens.
Definition: exprValue.C:228