diff --git a/applications/test/exprValue/Make/files b/applications/test/exprValue/Make/files
deleted file mode 100644
index e205df0b3c..0000000000
--- a/applications/test/exprValue/Make/files
+++ /dev/null
@@ -1,3 +0,0 @@
-Test-exprValue.cxx
-
-EXE = $(FOAM_USER_APPBIN)/Test-exprValue
diff --git a/applications/test/exprValue1/Make/files b/applications/test/exprValue1/Make/files
new file mode 100644
index 0000000000..70f3fad0c7
--- /dev/null
+++ b/applications/test/exprValue1/Make/files
@@ -0,0 +1,3 @@
+Test-exprValue1.cxx
+
+EXE = $(FOAM_USER_APPBIN)/Test-exprValue1
diff --git a/applications/test/exprValue/Make/options b/applications/test/exprValue1/Make/options
similarity index 100%
rename from applications/test/exprValue/Make/options
rename to applications/test/exprValue1/Make/options
diff --git a/applications/test/exprValue/Test-exprValue.cxx b/applications/test/exprValue1/Test-exprValue1.cxx
similarity index 87%
rename from applications/test/exprValue/Test-exprValue.cxx
rename to applications/test/exprValue1/Test-exprValue1.cxx
index a4753b365f..df77fd9956 100644
--- a/applications/test/exprValue/Test-exprValue.cxx
+++ b/applications/test/exprValue1/Test-exprValue1.cxx
@@ -11,7 +11,7 @@ License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
Application
- Test-exprValue
+ Test-exprValue1
Description
Test low-level polymorphic value container (exprValue)
@@ -59,11 +59,11 @@ expressions::exprValue tryParse(const std::string& str)
Info<< "Direct from string: ";
if (expressions::exprValue::read(str, val2))
{
- Info<< "good" << nl;
+ Info<< "OK" << nl;
}
else
{
- Info<< "bad" << nl;
+ Info<< "NOK" << nl;
}
}
return val;
@@ -128,21 +128,22 @@ int main(int argc, char *argv[])
expressions::exprValue oldValue(value);
- // Since the IO serialization is not symmetric (in ASCII) there
- // is no 'operator>>' defined and thus the regular Pstream::broadcast
- // will not compile.
- // Even although the data are contiguous and that code branch is never
- // used.
- // Fails to compile: Pstream::broadcast(value);
-
- // Broadcast manually
- UPstream::broadcast
- (
- value.data_bytes(),
- value.size_bytes(),
- UPstream::worldComm
- );
+ if (true)
+ {
+ // Broadcast with serialization
+ Pstream::broadcast(value);
+ }
+ else
+ {
+ // Broadcast manually
+ UPstream::broadcast
+ (
+ value.data_bytes(),
+ value.size_bytes(),
+ UPstream::worldComm
+ );
+ }
Pout<< "same values: " << (oldValue == value) << nl;
diff --git a/applications/test/exprValue2/Make/files b/applications/test/exprValue2/Make/files
new file mode 100644
index 0000000000..c49a9ce705
--- /dev/null
+++ b/applications/test/exprValue2/Make/files
@@ -0,0 +1,5 @@
+exprValueFieldTag.cxx
+
+Test-exprValue2.cxx
+
+EXE = $(FOAM_USER_APPBIN)/Test-exprValue2
diff --git a/applications/test/exprValue2/Make/options b/applications/test/exprValue2/Make/options
new file mode 100644
index 0000000000..1f502ad153
--- /dev/null
+++ b/applications/test/exprValue2/Make/options
@@ -0,0 +1 @@
+/* EXE_INC = */
diff --git a/applications/test/exprValue2/Test-exprValue2.cxx b/applications/test/exprValue2/Test-exprValue2.cxx
new file mode 100644
index 0000000000..93897ae321
--- /dev/null
+++ b/applications/test/exprValue2/Test-exprValue2.cxx
@@ -0,0 +1,143 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / 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 .
+
+Description
+ Test exprValue uniformity checks
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "IOobject.H"
+#include "IOstreams.H"
+#include "labelList.H"
+#include "scalarField.H"
+#include "vectorField.H"
+#include "DynamicList.H"
+#include "Random.H"
+#include "exprValue.H"
+#include "exprValueFieldTag.H"
+
+using namespace Foam;
+
+Ostream& printInfo(const expressions::exprValueFieldTag& tag)
+{
+ tag.print(Pout);
+ return Pout;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// Main program:
+
+int main(int argc, char *argv[])
+{
+ using fieldTag = expressions::exprValueFieldTag;
+
+ Random rnd(123456);
+
+ argList::noCheckProcessorDirectories();
+
+ #include "setRootCase.H"
+
+ {
+ scalarField fld1(20);
+ scalarField fld2a(20, Zero);
+ scalarField fld2b(10, 3.10);
+ scalarField fld3;
+
+ forAll(fld1, i)
+ {
+ fld1[i] = rnd.position(0, 20);
+ }
+
+ fieldTag tag1(fld1.begin(), fld1.end());
+ fieldTag tag2a(fld2a.begin(), fld2a.end());
+ fieldTag tag2b(fld2b.begin(), fld2b.end());
+ fieldTag tag3(fld3.begin(), fld3.end());
+
+ printInfo(tag1) << nl;
+ printInfo(tag2a) << nl;
+ printInfo(tag2b) << nl;
+ printInfo(tag3) << nl;
+
+ fieldTag result;
+
+ result = fieldTag::combineOp{}(tag1, tag2a);
+ printInfo(result) << nl;
+
+ Info<< "combine: ";
+ printInfo(tag2a) << " and ";
+ printInfo(tag2b) << nl;
+
+ result = fieldTag::combineOp{}(tag2a, tag2b);
+ printInfo(result) << nl;
+ }
+
+ {
+ vectorField fld2a(20, Foam::zero{});
+ vectorField fld2b(10, vector::uniform(3.10));
+
+ fieldTag tag2a(fld2a.begin(), fld2a.end());
+ fieldTag tag2b(fld2b.begin(), fld2b.end());
+
+ printInfo(tag2a) << nl;
+ printInfo(tag2b) << nl;
+
+ fieldTag result;
+
+ Info<< "combine: ";
+ printInfo(tag2a) << " and ";
+ printInfo(tag2b) << nl;
+
+ result = fieldTag::combineOp{}(tag2a, tag2b);
+ printInfo(result) << nl;
+ }
+
+ if (UPstream::parRun())
+ {
+ scalarField fld;
+
+ if (!UPstream::master())
+ {
+ fld.resize(UPstream::myProcNo(), UPstream::myProcNo());
+ }
+
+ fieldTag oldTag(fld.begin(), fld.end());
+
+ printInfo(oldTag) << " input: " << fld << " <- before reduce" << nl;
+
+ fieldTag newTag = returnReduce(oldTag, fieldTag::combineOp());
+
+ printInfo(newTag) << " <- after reduce" << nl;
+ }
+
+
+ Info<< "\nEnd\n" << nl;
+
+ return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/exprValue2/exprValueFieldTag.H b/applications/test/exprValue2/exprValueFieldTag.H
new file mode 100644
index 0000000000..cd92e3597c
--- /dev/null
+++ b/applications/test/exprValue2/exprValueFieldTag.H
@@ -0,0 +1,170 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / 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 .
+
+Class
+ Foam::expressions::exprValueFieldTag
+
+Description
+ A polymorphic single-value container for tracking Field content
+ as uniform etc.
+
+SourceFiles
+ exprValueFieldTag.cxx
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef Foam_expressions_exprValueFieldTag_H
+#define Foam_expressions_exprValueFieldTag_H
+
+#include "exprValue.H"
+#include "List.H" // For ListPolicy
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+
+/*---------------------------------------------------------------------------*\
+ Class exprValueFieldTag Declaration
+\*---------------------------------------------------------------------------*/
+
+class exprValueFieldTag
+{
+ // Private data
+
+ //- Uniformity of field
+ int uniformity_{};
+
+ //- Representative (uniform) value for the field
+ expressions::exprValue value_{};
+
+public:
+
+ // Constructors
+
+ //- Default construct
+ exprValueFieldTag() = default;
+
+ //- Construct from a range of values
+ template
+ explicit exprValueFieldTag(const Type* first, const Type* last)
+ {
+ set(first, last);
+ }
+
+
+ // Member Functions
+
+ //- True if the uniformity is "empty"
+ bool empty() const noexcept;
+
+ //- True if the uniformity is "uniform"
+ bool is_uniform() const noexcept;
+
+ //- True if the uniformity is "non-uniform"
+ bool is_nonuniform() const noexcept;
+
+ //- Test for equality of the values
+ bool equal(const exprValueFieldTag& rhs) const;
+
+ //- Set value and uniformity from range of data
+ template
+ void set(const Type* first, const Type* last)
+ {
+ uniformity_ =
+ Foam::Detail::ListPolicy::check_uniformity(first, last);
+
+ if (first != last) // or uniformity_ != EMPTY
+ {
+ value_.set(*first);
+ }
+ else
+ {
+ value_.set(Foam::zero{});
+ }
+ }
+
+ //- Set uniform type and value
+ template
+ void set_uniform(const Type& val)
+ {
+ uniformity_ = Foam::Detail::ListPolicy::uniformity::UNIFORM;
+ value_.set(val);
+ }
+
+ //- Set as non-uniform
+ void set_nouniform() noexcept;
+
+
+ // Reduction operations
+
+ //- Combine - eg, for global uniformity
+ void combine(const exprValueFieldTag& b);
+
+ //- Binary operator to be used by reduce function for detecting
+ //- global uniformity
+ struct combineOp
+ {
+ exprValueFieldTag operator()
+ (
+ const exprValueFieldTag& a,
+ const exprValueFieldTag& b
+ ) const
+ {
+ exprValueFieldTag result(a);
+ result.combine(b);
+ return result;
+ }
+ };
+
+
+ // IO Operations
+
+ void read(Istream& is);
+ void write(Ostream& os) const;
+
+ //- Print description to Ostream
+ void print(Ostream& os) const;
+};
+
+} // End namespace expressions
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// IO
+Istream& operator>>(Istream&, expressions::exprValueFieldTag&);
+Ostream& operator<<(Ostream&, const expressions::exprValueFieldTag&);
+
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/test/exprValue2/exprValueFieldTag.cxx b/applications/test/exprValue2/exprValueFieldTag.cxx
new file mode 100644
index 0000000000..e30226107b
--- /dev/null
+++ b/applications/test/exprValue2/exprValueFieldTag.cxx
@@ -0,0 +1,160 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / 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 .
+
+\*---------------------------------------------------------------------------*/
+
+#include "exprValueFieldTag.H"
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+bool Foam::expressions::exprValueFieldTag::empty() const noexcept
+{
+ return
+ (
+ uniformity_ == Foam::Detail::ListPolicy::uniformity::EMPTY
+ );
+}
+
+
+bool Foam::expressions::exprValueFieldTag::is_uniform() const noexcept
+{
+ return
+ (
+ uniformity_ == Foam::Detail::ListPolicy::uniformity::UNIFORM
+ );
+}
+
+
+bool Foam::expressions::exprValueFieldTag::is_nonuniform() const noexcept
+{
+ return
+ (
+ uniformity_ == Foam::Detail::ListPolicy::uniformity::NONUNIFORM
+ );
+}
+
+
+bool Foam::expressions::exprValueFieldTag::equal
+(
+ const exprValueFieldTag& rhs
+) const
+{
+ return (value_ == rhs.value_);
+}
+
+
+void Foam::expressions::exprValueFieldTag::set_nouniform() noexcept
+{
+ uniformity_ = Foam::Detail::ListPolicy::uniformity::NONUNIFORM;
+ value_ = Foam::zero{};
+}
+
+
+void Foam::expressions::exprValueFieldTag::combine
+(
+ const exprValueFieldTag& b
+)
+{
+ if (b.empty())
+ {
+ // no-op
+ return;
+ }
+
+ exprValueFieldTag& a = *this;
+
+ if (a.empty())
+ {
+ a = b;
+ }
+ else if (a.is_nonuniform())
+ {
+ // Already non-uniform/mixed
+ // a.uniformity_ |= b.uniformity_;
+
+ a.value_ = Foam::zero{};
+ }
+ else if (a.is_uniform() && b.is_uniform())
+ {
+ // Both are uniform, but are they the same value?
+ if (!a.equal(b))
+ {
+ a.set_nouniform();
+ }
+ }
+}
+
+
+// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
+
+void Foam::expressions::exprValueFieldTag::read(Istream& is)
+{
+ label uniformTag;
+
+ is >> uniformTag;
+ uniformity_ = int(uniformTag);
+ value_.read(is);
+}
+
+
+void Foam::expressions::exprValueFieldTag::write(Ostream& os) const
+{
+ os << label(uniformity_);
+ value_.write(os, false); // No pruning
+}
+
+
+void Foam::expressions::exprValueFieldTag::print(Ostream& os) const
+{
+ os << "{ uniform:"
+ << label(uniformity_)
+ << " type:" << label(value_.typeCode())
+ << " value: " << value_ << " }";
+}
+
+
+Foam::Istream& Foam::operator>>
+(
+ Istream& is,
+ expressions::exprValueFieldTag& tag
+)
+{
+ tag.read(is);
+ return is;
+}
+
+
+Foam::Ostream& Foam::operator<<
+(
+ Ostream& os,
+ const expressions::exprValueFieldTag& tag
+)
+{
+ tag.write(os);
+ return os;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/traits/exprTraits.C b/src/OpenFOAM/expressions/traits/exprTraits.C
index 3e6a389536..55a8c68705 100644
--- a/src/OpenFOAM/expressions/traits/exprTraits.C
+++ b/src/OpenFOAM/expressions/traits/exprTraits.C
@@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
- Copyright (C) 2021 OpenCFD Ltd.
+ Copyright (C) 2021-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@@ -61,7 +61,37 @@ Foam::expressions::Detail::nComponents
\
case expressions::valueTypeCode::type_##Type : \
{ \
- return pTraits::nComponents; \
+ return exprTypeTraits::nComponents; \
+ }
+
+ FOR_ALL_EXPR_TYPE_CODES(doLocalCode);
+ #undef doLocalCode
+ }
+
+ return 0;
+}
+
+
+Foam::direction
+Foam::expressions::Detail::rank
+(
+ const expressions::valueTypeCode typeCode
+) noexcept
+{
+ switch (typeCode)
+ {
+ case expressions::valueTypeCode::NONE :
+ case expressions::valueTypeCode::INVALID :
+ {
+ break;
+ }
+
+ #undef doLocalCode
+ #define doLocalCode(Type, UnusedParam) \
+ \
+ case expressions::valueTypeCode::type_##Type : \
+ { \
+ return exprTypeTraits::rank; \
}
FOR_ALL_EXPR_TYPE_CODES(doLocalCode);
@@ -112,7 +142,7 @@ Foam::word Foam::name(const expressions::valueTypeCode typeCode)
case expressions::valueTypeCode::INVALID :
{
- // returns ""
+ // returns "", could also return "bad"
break;
}
diff --git a/src/OpenFOAM/expressions/traits/exprTraits.H b/src/OpenFOAM/expressions/traits/exprTraits.H
index c3452da052..a74f0844ce 100644
--- a/src/OpenFOAM/expressions/traits/exprTraits.H
+++ b/src/OpenFOAM/expressions/traits/exprTraits.H
@@ -117,6 +117,9 @@ namespace Detail
//- The number of components associated with given valueTypeCode
::Foam::direction nComponents(const expressions::valueTypeCode) noexcept;
+//- The vector-space rank associated with given valueTypeCode
+::Foam::direction rank(const expressions::valueTypeCode) noexcept;
+
} // End namespace Detail
diff --git a/src/OpenFOAM/expressions/value/exprValue.C b/src/OpenFOAM/expressions/value/exprValue.C
index 3e7a44b6d3..bfddba1137 100644
--- a/src/OpenFOAM/expressions/value/exprValue.C
+++ b/src/OpenFOAM/expressions/value/exprValue.C
@@ -129,6 +129,10 @@ Foam::expressions::exprValue::peekType(const ITstream& is)
switch (endCmpti - firstCmpti)
{
+ case 0: // Explicitly provided '()' - ie, none
+ whichCode = expressions::valueTypeCode::NONE;
+ break;
+
case 1: // pTraits::nComponents
whichCode = exprTypeTraits::value;
break;
@@ -177,6 +181,13 @@ Foam::expressions::exprValue::peekType(const ITstream& is)
{
whichCode = exprTypeTraits::value;
}
+
+ // Treat anything else as 'invalid', which also implicitly
+ // includes the token "bad"
+ // else if (tok0.isWord("bad"))
+ // {
+ // whichCode = expressions::valueTypeCode::INVALID;
+ // }
}
return whichCode;
@@ -192,7 +203,7 @@ bool Foam::expressions::exprValue::read
ITstream is(str);
// No trailing non-whitespace!
- return (val.read(is) && !is.nRemainingTokens());
+ return (val.readTokens(is) && !is.nRemainingTokens());
}
@@ -215,10 +226,33 @@ void Foam::expressions::exprValue::deepCopy(const exprValue& rhs)
}
-Foam::tokenList Foam::expressions::exprValue::tokens() const
+Foam::tokenList Foam::expressions::exprValue::tokens(bool prune) const
{
+ // Handling for NONE, INVALID:
+ // - NONE => pair of ( ) brackets
+ // - INVALID => "bad" as a word
+ //
+ // With prune:
+ // - no output for either
+
tokenList toks;
+ if (!prune)
+ {
+ if (typeCode_ == expressions::valueTypeCode::NONE)
+ {
+ toks.resize(2);
+ toks.front() = token::BEGIN_LIST;
+ toks.back() = token::END_LIST;
+ return toks;
+ }
+ else if (typeCode_ == expressions::valueTypeCode::INVALID)
+ {
+ toks.emplace_back(word("bad"));
+ return toks;
+ }
+ }
+
switch (typeCode_)
{
#undef doLocalCode
@@ -245,8 +279,29 @@ Foam::tokenList Foam::expressions::exprValue::tokens() const
}
-void Foam::expressions::exprValue::print(Ostream& os) const
+void Foam::expressions::exprValue::write(Ostream& os, bool prune) const
{
+ // Handling for NONE, INVALID:
+ // - NONE => pair of ( ) brackets
+ // - INVALID => "bad" as a word
+ //
+ // With prune:
+ // - no output for either
+
+ if (!prune)
+ {
+ if (typeCode_ == expressions::valueTypeCode::NONE)
+ {
+ os << token::BEGIN_LIST << token::END_LIST;
+ return;
+ }
+ else if (typeCode_ == expressions::valueTypeCode::INVALID)
+ {
+ os << word("bad");
+ return;
+ }
+ }
+
switch (typeCode_)
{
#undef doLocalCode
@@ -271,12 +326,87 @@ void Foam::expressions::exprValue::print(Ostream& os) const
}
-bool Foam::expressions::exprValue::read(ITstream& is)
+bool Foam::expressions::exprValue::read(Istream& is)
+{
+ ITstream* stream = dynamic_cast(&is);
+
+ // Reading via tokens - simple for now
+ // Expect either a single token (scalar, label, word etc)
+ // or ( ... ) content
+
+ ITstream toks;
+
+ if (!stream)
+ {
+ token tok(is);
+
+ is.fatalCheck(FUNCTION_NAME);
+
+ if (tok.isPunctuation(token::BEGIN_LIST))
+ {
+ // Expecting "( content )" - eg, (x y z), (xx xy ...)
+ do
+ {
+ toks.add_tokens(tok);
+
+ is >> tok;
+ is.fatalCheck(FUNCTION_NAME);
+ }
+ while (!tok.isPunctuation(token::END_LIST));
+
+ if (tok.isPunctuation(token::END_LIST))
+ {
+ toks.add_tokens(tok);
+ }
+ }
+ else if (tok.good())
+ {
+ toks.add_tokens(tok);
+ }
+
+ // Truncate to number tokens read
+ toks.resize(toks.tokenIndex());
+ toks.seek(0);
+
+ stream = &toks;
+ }
+
+ return readTokens(*stream);
+}
+
+
+bool Foam::expressions::exprValue::readTokens(ITstream& is)
{
clear(); // type: none, value: zero
const valueTypeCode whichCode(exprValue::peekType(is));
+ if (whichCode == expressions::valueTypeCode::NONE)
+ {
+ typeCode_ = whichCode;
+ is.skip(2); // Skip tokens: '( )'
+ return true;
+ }
+
+ // This one should be rare or even impossible
+ if (whichCode == expressions::valueTypeCode::INVALID)
+ {
+ typeCode_ = whichCode;
+
+ if (is.bad())
+ {
+ return false;
+ }
+
+ const token& tok0 = is.peek();
+
+ if (tok0.isWord("bad"))
+ {
+ is.skip(1); // Skip token: "bad"
+ return true;
+ }
+ }
+
switch (whichCode)
{
#undef doLocalCode
@@ -347,13 +477,24 @@ bool Foam::expressions::exprValue::operator<(const exprValue& rhs) const
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
+Foam::Istream& Foam::operator>>
+(
+ Istream& is,
+ expressions::exprValue& val
+)
+{
+ val.read(is);
+ return is;
+}
+
+
Foam::Ostream& Foam::operator<<
(
Ostream& os,
const expressions::exprValue& val
)
{
- val.print(os);
+ val.write(os, false); // no pruning
return os;
}
@@ -367,16 +508,18 @@ Foam::Ostream& Foam::operator<<
{
const auto& val = *iproxy;
- if (val.good())
+ if (val.typeCode() == expressions::valueTypeCode::NONE)
{
- os << val.valueTypeName() << ": ";
- val.print(os);
+ os << "none";
+ }
+ else if (val.typeCode() == expressions::valueTypeCode::INVALID)
+ {
+ os << "bad";
}
else
{
- // typeCode_ is *never* set to INVALID,
- // so NONE is the only remaining non-good type
- os << "none";
+ os << val.valueTypeName() << ": ";
+ val.write(os); // pruning is immaterial - !good() already handled
}
return os;
diff --git a/src/OpenFOAM/expressions/value/exprValue.H b/src/OpenFOAM/expressions/value/exprValue.H
index 014e36f205..16cf5753c2 100644
--- a/src/OpenFOAM/expressions/value/exprValue.H
+++ b/src/OpenFOAM/expressions/value/exprValue.H
@@ -169,7 +169,7 @@ class exprValue
// Private Member Functions
- //- Assign zero, preserving the data type
+ //- Fill the data with zero, preserving the data type
inline void fill_zero();
//- Copy assignment
@@ -215,6 +215,12 @@ public:
const expressions::valueTypeCode
) noexcept;
+ //- The vector-space rank associated with the valueTypeCode
+ inline static direction rank
+ (
+ const expressions::valueTypeCode
+ ) noexcept;
+
//- True if the specified type is supported
template
inline static bool supportedType();
@@ -250,6 +256,9 @@ public:
//- The number of components associated with the value type
inline direction nComponents() const noexcept;
+ //- The vector-space rank associated with the value type
+ inline direction rank() const noexcept;
+
//- The name for the value type. Similar to pTraits typeName
inline word valueTypeName() const;
@@ -260,9 +269,13 @@ public:
//- Reset to 'none'
void clear();
+ //- Read read tokens (if possible)
+ // \return True on success
+ bool read(Istream& is);
+
//- Guess type and read tokens (if possible)
// \return True on success
- bool read(ITstream& is);
+ bool readTokens(ITstream& is);
// Typed Access
@@ -346,11 +359,19 @@ public:
//- Return info proxy for printing information to a stream
InfoProxy info() const { return *this; }
- //- The value as tokens. An empty list is returned for NONE.
- tokenList tokens() const;
+ //- The exprValue as tokens.
+ // For none : emits pair of brackets.
+ // For invalid : emits "bad".
+ //
+ // \param prune suppress the output for none/invalid
+ tokenList tokens(bool prune = false) const;
- //- Print the (type-specific) content
- void print(Ostream& os) const;
+ //- Write the (type-specific) content.
+ // For none : emits pair of brackets.
+ // For invalid : emits "bad".
+ //
+ // \param prune suppress the output for none/invalid
+ void write(Ostream& os, bool prune = false) const;
};
@@ -364,7 +385,11 @@ template<> struct is_contiguous : std::true_type {};
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
-//- Write value to output stream in ASCII format. No output for !good().
+//- Read/parse value from input stream (uses ASCII format).
+Istream& operator>>(Istream& is, expressions::exprValue& val);
+
+//- Write value to output stream (uses ASCII format).
+//- Writes 'none' or 'bad' for unknown/unsupported types.
Ostream& operator<<(Ostream& os, const expressions::exprValue& val);
template<>
diff --git a/src/OpenFOAM/expressions/value/exprValueI.H b/src/OpenFOAM/expressions/value/exprValueI.H
index 9072c9225f..87a65b1584 100644
--- a/src/OpenFOAM/expressions/value/exprValueI.H
+++ b/src/OpenFOAM/expressions/value/exprValueI.H
@@ -64,6 +64,15 @@ inline Foam::direction Foam::expressions::exprValue::nComponents
}
+inline Foam::direction Foam::expressions::exprValue::rank
+(
+ const expressions::valueTypeCode valTypeCode
+) noexcept
+{
+ return expressions::Detail::rank(valTypeCode);
+}
+
+
template
inline bool Foam::expressions::exprValue::supportedType()
{
@@ -110,7 +119,7 @@ inline Foam::expressions::exprValue::exprValue(const Type& val)
{
FatalErrorInFunction
<< "Cannot construct for unsupported type: "
- << typeid(Type).name() << endl
+ << typeid(Type).name() << nl
<< abort(FatalError);
}
}
@@ -137,6 +146,13 @@ Foam::expressions::exprValue::nComponents() const noexcept
}
+inline Foam::direction
+Foam::expressions::exprValue::rank() const noexcept
+{
+ return expressions::Detail::rank(typeCode_);
+}
+
+
inline Foam::word
Foam::expressions::exprValue::valueTypeName() const
{