diff --git a/applications/test/cstring/Test-cstring.cxx b/applications/test/cstring/Test-cstring.cxx index 002300e00949a58b06f409a1bbf53a4b9f892d58..0adbb54d30d886ea25e38b185487fb84300ca6f6 100644 --- a/applications/test/cstring/Test-cstring.cxx +++ b/applications/test/cstring/Test-cstring.cxx @@ -123,7 +123,7 @@ int main(int argc, char *argv[]) ); Info<< testInput << nl; - SubStrings<string> args = stringOps::splitSpace(testInput); + auto args = stringOps::splitSpace(testInput); Info<< "split into " << args.size() << " args" << nl; CStringList inC(args); diff --git a/applications/test/fileHandler-ranks1/Test-fileHandler-ranks1.C b/applications/test/fileHandler-ranks1/Test-fileHandler-ranks1.C index 253553e7d6a400817e43ac59bded0e0c3f87e62e..2d038b580b3d222b8b974a7f511205fb2e29e8fa 100644 --- a/applications/test/fileHandler-ranks1/Test-fileHandler-ranks1.C +++ b/applications/test/fileHandler-ranks1/Test-fileHandler-ranks1.C @@ -47,7 +47,7 @@ using namespace Foam; template<class PrimitiveType> static List<PrimitiveType> splitStringToList(const std::string& str) { - const SubStrings<std::string> items = stringOps::splitAny(str, " ,;"); + const auto items = stringOps::splitAny(str, " ,;"); DynamicList<PrimitiveType> values(items.size()); diff --git a/applications/test/string/Test-string.C b/applications/test/string/Test-string.C index 587eb2e3149174a9b46a7dd4fed827d1d3ce7805..72cd2ab17801bb6cb570d39a45182632f326ca57 100644 --- a/applications/test/string/Test-string.C +++ b/applications/test/string/Test-string.C @@ -148,7 +148,7 @@ int main(int argc, char *argv[]) Info<< "input: " << input << nl << "expand: " << output << nl - << "split: " << stringOps::split(output, "/") << nl << nl; + << "split: " << stringOps::split(output, '/') << nl << nl; } } diff --git a/applications/test/stringSplit/Test-stringSplit.C b/applications/test/stringSplit/Test-stringSplit.C index 2dc4e6ab98e65e9d11de540e1102887b7196cbb4..bc12f4b1660d9704f60a0533e9ce92f930ea5216 100644 --- a/applications/test/stringSplit/Test-stringSplit.C +++ b/applications/test/stringSplit/Test-stringSplit.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2017-2021 OpenCFD Ltd. + Copyright (C) 2017-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -34,6 +34,7 @@ Description #include "argList.H" #include "fileName.H" #include "stringOps.H" +#include "Switch.H" using namespace Foam; @@ -65,6 +66,9 @@ int main(int argc, char *argv[]) { argList::noBanner(); argList::noParallel(); + argList::noMandatoryArgs(); + argList::addArgument("string .. stringN"); + argList::addOption ( "any", @@ -89,6 +93,12 @@ int main(int argc, char *argv[]) "int", "test split on fixed width" ); + argList::addOption + ( + "begin", + "int", + "begin offset for splits" + ); argList::addBoolOption ( "slash", @@ -104,18 +114,25 @@ int main(int argc, char *argv[]) "empty", "preserve empty strings in split" ); - argList args(argc, argv, false, true); + + argList args(argc, argv); if (args.size() <= 1 && args.options().empty()) { args.printUsage(); } + const label beginOffset = args.getOrDefault<label>("begin", 0); + const bool keepEmpty = args.found("empty"); + Info<< "begin offset: " << beginOffset << nl; + Info<< "keep empty : " << Switch::name(keepEmpty) << nl; + const label nopts = args.count({"any", "slash", "space", "sub", "fixed", "char"}); + if (args.found("any")) { const std::string& str = args["any"]; @@ -125,7 +142,7 @@ int main(int argc, char *argv[]) for (label argi=1; argi < args.size(); ++argi) { - const auto split = stringOps::splitAny(args[argi], str); + auto split = stringOps::splitAny(args[argi], str, beginOffset); printSubStrings(args[argi], split); } @@ -144,7 +161,7 @@ int main(int argc, char *argv[]) for (label argi=1; argi < args.size(); ++argi) { - const auto split = stringOps::split(args[argi], str); + auto split = stringOps::split(args[argi], str, beginOffset); printSubStrings(args[argi], split); } @@ -161,7 +178,11 @@ int main(int argc, char *argv[]) for (label argi=1; argi < args.size(); ++argi) { - const auto split = stringOps::splitSpace(args[argi]); + auto split = stringOps::splitSpace(args[argi], beginOffset); + printSubStrings(args[argi], split); + + Info<< "pop_front(2)" << nl; + split.pop_front(2); printSubStrings(args[argi], split); } @@ -180,7 +201,8 @@ int main(int argc, char *argv[]) for (label argi=1; argi < args.size(); ++argi) { - const auto split = stringOps::split(args[argi], delim, keepEmpty); + auto split = + stringOps::split(args[argi], delim, beginOffset, keepEmpty); printSubStrings(args[argi], split); } @@ -199,7 +221,7 @@ int main(int argc, char *argv[]) for (label argi=1; argi < args.size(); ++argi) { - const auto split = stringOps::splitFixed(args[argi], width); + auto split = stringOps::splitFixed(args[argi], width, beginOffset); printSubStrings(args[argi], split); } @@ -219,7 +241,8 @@ int main(int argc, char *argv[]) for (label argi=1; argi < args.size(); ++argi) { - const auto split = stringOps::split(args[argi], delim, keepEmpty); + auto split = + stringOps::split(args[argi], delim, beginOffset, keepEmpty); printSubStrings(args[argi], split); } } diff --git a/src/OpenFOAM/global/fileOperations/fileOperation/fileOperationRanks.C b/src/OpenFOAM/global/fileOperations/fileOperation/fileOperationRanks.C index c500571412a10ba84b406656d3bd67b6cd4fc191..cfedf5313061c62a320b313252227fcdf0799f9b 100644 --- a/src/OpenFOAM/global/fileOperations/fileOperation/fileOperationRanks.C +++ b/src/OpenFOAM/global/fileOperations/fileOperation/fileOperationRanks.C @@ -42,7 +42,7 @@ namespace Foam template<class PrimitiveType> static List<PrimitiveType> splitStringToList(const std::string& str) { - const SubStrings<std::string> items = stringOps::splitAny(str, " ,;"); + const auto items = stringOps::splitAny(str, " ,;"); DynamicList<PrimitiveType> values(items.size()); diff --git a/src/OpenFOAM/primitives/ranges/scalarRange/scalarRanges.C b/src/OpenFOAM/primitives/ranges/scalarRange/scalarRanges.C index f94f724742a9f67244f89d2779e8989462e96aac..74c3ce205ed051cc39039c17c94e297979613f2b 100644 --- a/src/OpenFOAM/primitives/ranges/scalarRange/scalarRanges.C +++ b/src/OpenFOAM/primitives/ranges/scalarRange/scalarRanges.C @@ -36,7 +36,7 @@ Foam::scalarRanges Foam::scalarRanges::parse bool report ) { - const SubStrings<std::string> items = stringOps::splitAny(str, " ,;"); + const auto items = stringOps::splitAny(str, " ,;"); scalarRanges ranges(items.size()); diff --git a/src/OpenFOAM/primitives/strings/lists/SubStrings.H b/src/OpenFOAM/primitives/strings/lists/SubStrings.H index 4892d7976ca5b721ac42983ff45c90e6d06fa0ac..373bebb6d4e8fbe507064f4ce9f2ac2dda167246 100644 --- a/src/OpenFOAM/primitives/strings/lists/SubStrings.H +++ b/src/OpenFOAM/primitives/strings/lists/SubStrings.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2017-2021 OpenCFD Ltd. + Copyright (C) 2017-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -66,12 +66,6 @@ public: typename StringType::const_iterator; - // Constructors - - //- Default construct - SubStrings() = default; - - // Member Functions //- The total string length of all sub-elements. @@ -109,6 +103,40 @@ public: this->push_back(range); } + + //- Reduce size by 1 or more elements. Can be called on an empty list. + void pop_back(size_t n = 1) + { + if (n >= this->size()) + { + this->clear(); + } + else if (n > 0) + { + this->resize(this->size() - n); + } + } + + //- Reduce size by 1 or more elements (from the front). + //- Can be called on an empty list. + void pop_front(size_t n = 1) + { + if (n >= this->size()) + { + this->clear(); + } + else if (n > 0) + { + // Overlapping range, avoid std::copy, std::move + for (size_t src = n, dst = 0; src < this->size(); ++src, ++dst) + { + (*this)[dst] = (*this)[src]; + } + this->resize(this->size() - n); + } + } + + // FUTURE? // #if __cplusplus >= 201703L // std::string_view view(size_t pos) const diff --git a/src/OpenFOAM/primitives/strings/stringOps/stringOps.H b/src/OpenFOAM/primitives/strings/stringOps/stringOps.H index 8f8a7a110cf14651d9e0e05b9d08f3e3021bb9dd..1bc9de475807f8f7ad3ca0cd3e9550b5338a7918 100644 --- a/src/OpenFOAM/primitives/strings/stringOps/stringOps.H +++ b/src/OpenFOAM/primitives/strings/stringOps/stringOps.H @@ -372,8 +372,13 @@ namespace stringOps template<class StringType> Foam::SubStrings<StringType> split ( + //! The string to split const StringType& str, + //! The delimiter for splitting. Ill-defined if NUL character const char delim, + //! Offset within string to start splitting + std::string::size_type pos = 0, + //! Retain empty fields const bool keepEmpty = false ); @@ -382,8 +387,13 @@ namespace stringOps template<class StringType> Foam::SubStrings<StringType> split ( + //! The string to split const StringType& str, + //! The delimiters for splitting. Ill-defined if empty const std::string& delim, + //! Offset within string to start splitting + std::string::size_type pos = 0, + //! Retain empty fields const bool keepEmpty = false ); @@ -393,22 +403,25 @@ namespace stringOps template<class StringType> Foam::SubStrings<StringType> splitAny ( + //! The string to split const StringType& str, - const std::string& delim + //! The delimiters for splitting. Ill-defined if empty! + const std::string& delim, + //! Offset within string to start splitting + std::string::size_type pos = 0 ); //- Split string into sub-strings using a fixed field width. // Behaviour is ill-defined if width is zero. - // \param str the string to be split - // \param width the fixed field width for each sub-string - // \param start the optional offset of where to start the splitting. - // Any text prior to start is ignored in the operation. template<class StringType> Foam::SubStrings<StringType> splitFixed ( + //! The string to split const StringType& str, + //! Fixed field width for each sub-string const std::string::size_type width, - const std::string::size_type start = 0 + //! Offset within string to start splitting + std::string::size_type pos = 0 ); //- Split string into sub-strings at whitespace (TAB, NL, VT, FF, CR, SPC) @@ -416,23 +429,25 @@ namespace stringOps template<class StringType> Foam::SubStrings<StringType> splitSpace ( - const StringType& str + //! The string to split + const StringType& str, + //! Offset within string to start splitting + std::string::size_type pos = 0 ); //- Output string with text wrapping. // Always includes a trailing newline, unless the string itself is empty. - // - // \param os the output stream - // \param str the text to be output - // \param width the max-width before wrapping - // \param indent indentation for continued lines - // \param escape escape any backslashes on output void writeWrapped ( + //! The output stream OSstream& os, + //! The text to be output const std::string& str, + //! The max-width before wrapping const std::string::size_type width, + //! Indentation for continued lines const std::string::size_type indent = 0, + //! Escape any backslashes on output const bool escape = false ); diff --git a/src/OpenFOAM/primitives/strings/stringOps/stringOpsTemplates.C b/src/OpenFOAM/primitives/strings/stringOps/stringOpsTemplates.C index 19d06d013667db3fad36c1b4e73d6841de9c4ae3..29b230497fe7b25b27754a47d20a336d62f973ab 100644 --- a/src/OpenFOAM/primitives/strings/stringOps/stringOpsTemplates.C +++ b/src/OpenFOAM/primitives/strings/stringOps/stringOpsTemplates.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016-2023 OpenCFD Ltd. + Copyright (C) 2016-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -98,34 +98,40 @@ Foam::SubStrings<StringType> Foam::stringOps::split ( const StringType& str, const char delim, + std::string::size_type pos, const bool keepEmpty ) { - Foam::SubStrings<StringType> lst; - if (str.empty() || !delim) + Foam::SubStrings<StringType> list; + + if + ( + !delim + || (pos == std::string::npos || pos >= str.size()) + ) { - return lst; + return list; } - lst.reserve(20); + list.reserve(20); - std::string::size_type beg = 0, end = 0; - while ((end = str.find(delim, beg)) != std::string::npos) + std::string::size_type end; + while ((end = str.find(delim, pos)) != std::string::npos) { - if (keepEmpty || (beg < end)) + if (keepEmpty || (pos < end)) { - lst.append(str.cbegin() + beg, str.cbegin() + end); + list.append(str.cbegin() + pos, str.cbegin() + end); } - beg = end + 1; + pos = end + 1; } // Trailing element - if (keepEmpty ? (beg <= str.size()) : (beg < str.size())) + if (keepEmpty ? (pos <= str.size()) : (pos < str.size())) { - lst.append(str.cbegin() + beg, str.cend()); + list.append(str.cbegin() + pos, str.cend()); } - return lst; + return list; } @@ -134,34 +140,40 @@ Foam::SubStrings<StringType> Foam::stringOps::split ( const StringType& str, const std::string& delim, + std::string::size_type pos, const bool keepEmpty ) { - Foam::SubStrings<StringType> lst; - if (str.empty() || delim.empty()) + Foam::SubStrings<StringType> list; + + if + ( + delim.empty() + || (pos == std::string::npos || pos >= str.size()) + ) { - return lst; + return list; } - lst.reserve(20); + list.reserve(20); - std::string::size_type beg = 0, end = 0; - while ((end = str.find(delim, beg)) != std::string::npos) + std::string::size_type end; + while ((end = str.find(delim, pos)) != std::string::npos) { - if (keepEmpty || (beg < end)) + if (keepEmpty || (pos < end)) { - lst.append(str.cbegin() + beg, str.cbegin() + end); + list.append(str.cbegin() + pos, str.cbegin() + end); } - beg = end + delim.size(); + pos = end + delim.size(); } // Trailing element - if (keepEmpty ? (beg <= str.size()) : (beg < str.size())) + if (keepEmpty ? (pos <= str.size()) : (pos < str.size())) { - lst.append(str.cbegin() + beg, str.cend()); + list.append(str.cbegin() + pos, str.cend()); } - return lst; + return list; } @@ -169,40 +181,41 @@ template<class StringType> Foam::SubStrings<StringType> Foam::stringOps::splitAny ( const StringType& str, - const std::string& delim + const std::string& delim, + std::string::size_type pos ) { - Foam::SubStrings<StringType> lst; - if (str.empty() || delim.empty()) + Foam::SubStrings<StringType> list; + + if + ( + delim.empty() + || (pos == std::string::npos || pos >= str.size()) + ) { - return lst; + return list; } - lst.reserve(20); + list.reserve(20); - for - ( - std::string::size_type pos = 0; - (pos = str.find_first_not_of(delim, pos)) != std::string::npos; - /*nil*/ - ) + while ((pos = str.find_first_not_of(delim, pos)) != std::string::npos) { const auto end = str.find_first_of(delim, pos); if (end == std::string::npos) { // Trailing element - lst.append(str.cbegin() + pos, str.cend()); + list.append(str.cbegin() + pos, str.cend()); break; } // Intermediate element - lst.append(str.cbegin() + pos, str.cbegin() + end); + list.append(str.cbegin() + pos, str.cbegin() + end); pos = end + 1; } - return lst; + return list; } @@ -211,43 +224,53 @@ Foam::SubStrings<StringType> Foam::stringOps::splitFixed ( const StringType& str, const std::string::size_type width, - const std::string::size_type start + std::string::size_type pos ) { - Foam::SubStrings<StringType> lst; - if (str.empty() || !width) + Foam::SubStrings<StringType> list; + + if + ( + !width + || (pos == std::string::npos || pos >= str.size()) + ) { - return lst; + return list; } + list.reserve(1 + ((str.size() - pos) / width)); + const auto len = str.size(); - lst.reserve(1 + (len / width)); - for (std::string::size_type pos = start; pos < len; pos += width) + while (pos < len) { const auto end = (pos + width); if (end >= len) { // Trailing element - lst.append(str.cbegin() + pos, str.cend()); + list.append(str.cbegin() + pos, str.cend()); break; } - lst.append(str.cbegin() + pos, str.cbegin() + end); + // Intermediate element + list.append(str.cbegin() + pos, str.cbegin() + end); + + pos += width; } - return lst; + return list; } template<class StringType> Foam::SubStrings<StringType> Foam::stringOps::splitSpace ( - const StringType& str + const StringType& str, + std::string::size_type pos ) { - return splitAny(str, "\t\n\v\f\r "); + return splitAny(str, "\t\n\v\f\r ", pos); } diff --git a/src/meshTools/edgeMesh/edgeFormats/obj/OBJedgeFormat.C b/src/meshTools/edgeMesh/edgeFormats/obj/OBJedgeFormat.C index c349c566cba121d3bb61cb70a7074b8641bbc0eb..0c771c74e5e08ad5d5d73ce6bbfd2662d5f958fb 100644 --- a/src/meshTools/edgeMesh/edgeFormats/obj/OBJedgeFormat.C +++ b/src/meshTools/edgeMesh/edgeFormats/obj/OBJedgeFormat.C @@ -120,7 +120,7 @@ bool Foam::fileFormats::OBJedgeFormat::read(const fileName& filename) line += this->getLineNoComment(is); } - const SubStrings<string> tokens = stringOps::splitSpace(line); + const auto tokens = stringOps::splitSpace(line); // Require command and some arguments if (tokens.size() < 2) diff --git a/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C b/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C index 816433deccb45ba69e30b9fc58a3c7f75404cec1..a836708018c58e5d643cc40f502f06363df0dc15 100644 --- a/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C +++ b/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C @@ -193,7 +193,8 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read if (line.starts_with("$ANSA_NAME")) { // Keep empty elements when splitting - const auto args = stringOps::split<std::string>(line, ';', true); + const auto args = + stringOps::split<std::string>(line, ';', 0, true); if (args.size() > 4 && line.starts_with("$ANSA_NAME_COMMENT")) { diff --git a/src/surfMesh/surfaceFormats/obj/OBJsurfaceFormat.C b/src/surfMesh/surfaceFormats/obj/OBJsurfaceFormat.C index d471bd66aed9a4799e34f1bdfda6af2f3c1e6f6e..4fd5c08a5f133681f0d5f98ad91aaa00e81d5704 100644 --- a/src/surfMesh/surfaceFormats/obj/OBJsurfaceFormat.C +++ b/src/surfMesh/surfaceFormats/obj/OBJsurfaceFormat.C @@ -91,7 +91,7 @@ bool Foam::fileFormats::OBJsurfaceFormat<Face>::read line += this->getLineNoComment(is); } - const SubStrings<string> tokens = stringOps::splitSpace(line); + const auto tokens = stringOps::splitSpace(line); // Require command and some arguments if (tokens.size() < 2)