From 775d0b277ba52f3b18de57cb29e4b0eac7d2e2f7 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Wed, 27 Sep 2023 19:35:55 +0200 Subject: [PATCH] ENH: improve OpenFOAM I/O for std::vector container - input: added support (similar to DynamicList) - output: redirect through UList output, which enables binary etc - these changes enable support for broadcast and other parallel IO for std::vector ENH: support SubList of std::vector (entire length) - allows a 'glue' layer for re-casting std::vector to UList etc --- .../Test-parallel-broadcast.C | 26 ++- src/OpenFOAM/containers/Lists/List/SubList.H | 3 + src/OpenFOAM/containers/Lists/List/SubListI.H | 10 + src/OpenFOAM/containers/Lists/List/UList.H | 6 +- .../containers/Lists/List/stdVectorIO.C | 171 ++++++++++++++++-- 5 files changed, 202 insertions(+), 14 deletions(-) diff --git a/applications/test/parallel-broadcast/Test-parallel-broadcast.C b/applications/test/parallel-broadcast/Test-parallel-broadcast.C index 38a68382e35..02b68242d93 100644 --- a/applications/test/parallel-broadcast/Test-parallel-broadcast.C +++ b/applications/test/parallel-broadcast/Test-parallel-broadcast.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022 OpenCFD Ltd. + Copyright (C) 2022-2023 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -75,6 +75,16 @@ void testBroadcast(List<T>& values) } +template<class T> +void testBroadcast(std::vector<T>& values) +{ + Info<< nl << "is_contiguous:" << is_contiguous<T>::value << endl; + Pout<< "pre-broadcast: " << flatOutput(values) << endl; + Pstream::broadcast(values); + Pout<< "post-broadcast: " << flatOutput(values) << endl; +} + + void testBroadcast(bitSet& values) { Pout<< "pre-broadcast: " @@ -135,6 +145,20 @@ int main(int argc, char *argv[]) testBroadcast(values); } + { + std::vector<word> values; + if (Pstream::master()) + { + values.resize(UPstream::nProcs()); + + for (decltype(values.size()) i=0; i < values.size(); ++i) + { + values[i] = "vector_" + Foam::name(i); + } + } + testBroadcast(values); + } + { vector values(vector::uniform(-1)); if (Pstream::master()) diff --git a/src/OpenFOAM/containers/Lists/List/SubList.H b/src/OpenFOAM/containers/Lists/List/SubList.H index f1c6aa2b38d..886068bf073 100644 --- a/src/OpenFOAM/containers/Lists/List/SubList.H +++ b/src/OpenFOAM/containers/Lists/List/SubList.H @@ -91,6 +91,9 @@ public: //- Construct from UList, the entire size inline explicit SubList(const UList<T>& list) noexcept; + //- Construct from std::vector, the entire size + inline explicit SubList(const std::vector<T>& list) noexcept; + //- Construct from FixedList, the entire size template<unsigned N> inline explicit SubList(const FixedList<T, N>& list); diff --git a/src/OpenFOAM/containers/Lists/List/SubListI.H b/src/OpenFOAM/containers/Lists/List/SubListI.H index 389e9e85f8f..f9057480d29 100644 --- a/src/OpenFOAM/containers/Lists/List/SubListI.H +++ b/src/OpenFOAM/containers/Lists/List/SubListI.H @@ -49,6 +49,16 @@ inline Foam::SubList<T>::SubList {} +template<class T> +inline Foam::SubList<T>::SubList +( + const std::vector<T>& list +) noexcept +: + UList<T>(const_cast<T*>(list.data()), label(list.size())) +{} + + template<class T> template<unsigned N> inline Foam::SubList<T>::SubList diff --git a/src/OpenFOAM/containers/Lists/List/UList.H b/src/OpenFOAM/containers/Lists/List/UList.H index 1d70c027032..169e50f35be 100644 --- a/src/OpenFOAM/containers/Lists/List/UList.H +++ b/src/OpenFOAM/containers/Lists/List/UList.H @@ -676,7 +676,11 @@ Ostream& operator<<(Ostream& os, const UList<T>& list) return list.writeList(os, Detail::ListPolicy::short_length<T>::value); } -//- Write std::vector to Ostream. ASCII only, no line-breaks +//- Read std::vector contents from Istream +template<class T> +Istream& operator>>(Istream& is, std::vector<T>& list); + +//- Write std::vector to Ostream (via UList) template<class T> Ostream& operator<<(Ostream& os, const std::vector<T>& list); diff --git a/src/OpenFOAM/containers/Lists/List/stdVectorIO.C b/src/OpenFOAM/containers/Lists/List/stdVectorIO.C index d3359cd8642..e286a14edfa 100644 --- a/src/OpenFOAM/containers/Lists/List/stdVectorIO.C +++ b/src/OpenFOAM/containers/Lists/List/stdVectorIO.C @@ -26,36 +26,183 @@ License \*---------------------------------------------------------------------------*/ #include "UList.H" +#include "Istream.H" #include "Ostream.H" +#include "contiguous.H" #include "token.H" #include <vector> // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * // template<class T> -Foam::Ostream& Foam::operator<<(Ostream& os, const std::vector<T>& list) +Foam::Istream& Foam::operator>>(Istream& is, std::vector<T>& list) { - auto iter = list.cbegin(); - const auto last = list.cend(); + is.fatalCheck(FUNCTION_NAME); + + token tok(is); + + is.fatalCheck("Istream >> std::vector<T> : reading first token"); + + if (tok.isCompound()) + { + // No compound handling ... + + list.clear(); // Clear old contents + FatalIOErrorInFunction(is) + << "Support for compoundToken - not implemented" << nl + << exit(FatalIOError); + } + else if (tok.isLabel()) + { + // Label: could be int(..), int{...} or just a plain '0' + + const label len = tok.labelToken(); + + // Resize to length required + list.resize(len); + + if (is.format() == IOstreamOption::BINARY && is_contiguous<T>::value) + { + // Binary and contiguous + + if (len) + { + Detail::readContiguous<T> + ( + is, + reinterpret_cast<char*>(list.data()), // data_bytes() + std::streamsize(list.size())*sizeof(T) // size_bytes() + ); + + is.fatalCheck + ( + "Istream >> std::vector<T> : " + "reading binary block" + ); + } + } + else if (std::is_same<char, T>::value) + { + // Special treatment for char data (binary I/O only) + const auto oldFmt = is.format(IOstreamOption::BINARY); + + if (len) + { + // read(...) includes surrounding start/end delimiters + is.read + ( + reinterpret_cast<char*>(list.data()), // data_bytes() + std::streamsize(list.size())*sizeof(T) // size_bytes() + ); + + is.fatalCheck + ( + "Istream >> std::vector<char> : " + "reading binary block" + ); + } + + is.format(oldFmt); + } + else + { + // Begin of contents marker + const char delimiter = is.readBeginList("List"); - // Write ascii list contents, no line breaks + if (len) + { + if (delimiter == token::BEGIN_LIST) + { + auto iter = list.begin(); + const auto last = list.end(); - os << label(list.size()) << token::BEGIN_LIST; + // Contents + for (/*nil*/; (iter != last); (void)++iter) + { + is >> *iter; - // Contents - if (iter != last) + is.fatalCheck + ( + "Istream >> std::vector<char> : " + "reading entry" + ); + } + } + else + { + // Uniform content (delimiter == token::BEGIN_BLOCK) + + T elem; + is >> elem; + + is.fatalCheck + ( + "Istream >> std::vector<char> : " + "reading the single entry" + ); + + // Fill with the value + list.assign(list.size(), elem); + } + } + + // End of contents marker + is.readEndList("List"); + } + } + else if (tok.isPunctuation(token::BEGIN_LIST)) { - os << *iter; + // "(...)" : read as bracketed list - for (++iter; (iter != last); (void)++iter) + // Slightly sub-optimal since it has intermediate resizing, + // however don't expect this as input very often. + + list.clear(); // Clear addressing, leave storage intact (probably) + + is >> tok; + is.fatalCheck(FUNCTION_NAME); + + while (!tok.isPunctuation(token::END_LIST)) { - os << token::SPACE << *iter; + is.putBack(tok); + + // C++17 + // is >> list.emplace_back(); + + // C++11 + list.emplace_back(); + is >> list.back(); + + is.fatalCheck + ( + "Istream >> std::vector<char> : " + "reading entry" + ); + + is >> tok; + is.fatalCheck(FUNCTION_NAME); } } + else + { + list.clear(); // Clear old contents + + FatalIOErrorInFunction(is) + << "incorrect first token, expected <int> or '(', found " + << tok.info() << nl + << exit(FatalIOError); + } + + return is; +} - os << token::END_LIST; - os.check(FUNCTION_NAME); +template<class T> +Foam::Ostream& Foam::operator<<(Ostream& os, const std::vector<T>& list) +{ + // Use UList for output + UList<T> proxy(const_cast<T*>(list.data()), label(list.size())); + os << proxy; return os; } -- GitLab