ENH: rationalize some string methods.

- silently deprecate 'startsWith', 'endsWith' methods
  (added in 2016: 2b14360662), in favour of
  'starts_with', 'ends_with' methods, corresponding to C++20 and
  allowing us to cull then in a few years.

- handle single character versions of starts_with, ends_with.

- add single character version of removeEnd and silently deprecate
  removeTrailing which did the same thing.

- drop the const versions of removeRepeated, removeTrailing.
  Unused and with potential confusion.

STYLE: use shrink_to_fit(), erase()
This commit is contained in:
Mark Olesen 2019-11-11 18:50:00 +01:00 committed by Andrew Heather
parent ea214727a5
commit 7c1190f0b1
28 changed files with 185 additions and 206 deletions

View File

@ -83,7 +83,7 @@ int main(int argc, char *argv[])
const word& item
: DirLister::files(".").where
(
[](const word& val){ return val.startsWith("T"); }
[](const word& val){ return val.starts_with('T'); }
)
)
{
@ -135,7 +135,7 @@ int main(int argc, char *argv[])
<< "~~~~~~~~~~" << nl
<< DirLister(".").list<fileName>
(
[](const word& val){ return val.startsWith("D"); },
[](const word& val){ return val.starts_with('D'); },
false
)
<< nl;

View File

@ -353,7 +353,7 @@ int main(int argc, char *argv[])
<< word::printf("formatted '%08d'", val) << "\n";
}
// test startsWith, endsWith methods
// test starts_with, ends_with methods
{
string empty; //;
string input1 = "shorter input";
@ -362,64 +362,64 @@ int main(int argc, char *argv[])
stringList checks{"match", "long", "", "short", "text", "s", "l", "t"};
Info<< nl;
Info<< "check startsWith:" << nl
Info<< "check starts_with:" << nl
<< "~~~~~~~~~~~~~~~~~" << nl;
Info<<"input: " << empty << nl;
for (const string& test : checks)
{
Info<< " startsWith(" << test << ") = "
<< Switch(empty.startsWith(test)) << nl;
Info<< " starts_with(" << test << ") = "
<< Switch(empty.starts_with(test)) << nl;
}
Info<<"input: " << input1 << nl;
for (const string& test : checks)
{
Info<< " startsWith(" << test << ") = "
<< Switch(input1.startsWith(test)) << nl;
Info<< " starts_with(" << test << ") = "
<< Switch(input1.starts_with(test)) << nl;
}
Info<<"input: " << input2 << nl;
for (const string& test : checks)
{
Info<< " startsWith(" << test << ") = "
<< Switch(input2.startsWith(test)) << nl;
Info<< " starts_with(" << test << ") = "
<< Switch(input2.starts_with(test)) << nl;
}
Info<< nl;
Info<< "check endsWith:" << nl
Info<< "check ends_with:" << nl
<< "~~~~~~~~~~~~~~~~~" << nl;
Info<<"input: " << empty << nl;
for (const string& test : checks)
{
Info<< " endsWith(" << test << ") = "
<< Switch(empty.endsWith(test)) << nl;
Info<< " ends_with(" << test << ") = "
<< Switch(empty.ends_with(test)) << nl;
}
Info<<"input: " << input1 << nl;
for (const string& test : checks)
{
Info<< " endsWith(" << test << ") = "
<< Switch(input1.endsWith(test)) << nl;
Info<< " ends_with(" << test << ") = "
<< Switch(input1.ends_with(test)) << nl;
}
Info<<"input: " << input2 << nl;
for (const string& test : checks)
{
Info<< " endsWith(" << test << ") = "
<< Switch(input2.endsWith(test)) << nl;
Info<< " ends_with(" << test << ") = "
<< Switch(input2.ends_with(test)) << nl;
}
Info<< nl;
Info<< "check endsWith as applied to field names:" << nl
Info<< "check ends_with as applied to field names:" << nl
<< "~~~~~~~~~~~~~~~~~" << nl;
string input3 = "field_0";
string input4 = "_0";
Info<<input3 << " endsWith(\"_0\") = "
<< Switch(input3.endsWith("_0")) << nl;
Info<<input3 << " ends_with(\"_0\") = "
<< Switch(input3.ends_with("_0")) << nl;
Info<<input4 << " endsWith(\"_0\") = "
<< Switch(input4.endsWith("_0")) << nl;
Info<<input4 << " ends_with(\"_0\") = "
<< Switch(input4.ends_with("_0")) << nl;
}

View File

@ -175,7 +175,7 @@ int main(int argc, char *argv[])
{
nodeStream.getLine(line);
}
while (line.size() && line[0] == '#');
while (line.starts_with('#'));
IStringStream nodeLine(line);
@ -252,7 +252,7 @@ int main(int argc, char *argv[])
{
eleStream.getLine(line);
}
while (line.size() && line[0] == '#');
while (line.starts_with('#'));
IStringStream eleLine(line);
@ -368,7 +368,7 @@ int main(int argc, char *argv[])
{
faceStream.getLine(line);
}
while (line.size() && line[0] == '#');
while (line.starts_with('#'));
IStringStream faceLine(line);

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -51,7 +52,7 @@ string getLine(std::ifstream& is)
{
std::getline(is, line);
}
while (line.size() && line[0] == '#');
while (line.starts_with('#'));
return line;
}

View File

@ -40,7 +40,7 @@ Foam::autoPtr<Foam::helpType> Foam::helpType::New
{
// special treatment for -help
// exit without stack trace
if (helpTypeName.startsWith("-help"))
if (helpTypeName.starts_with("-help"))
{
FatalErrorInFunction
<< "Valid helpType selections:" << nl

View File

@ -678,7 +678,7 @@ void Foam::vtkPVFoam::Update
// Suppress caching of Lagrangian since it normally always changes.
cachedVtp_.filterKeys
(
[](const word& k){ return k.startsWith("lagrangian/"); },
[](const word& k){ return k.starts_with("lagrangian/"); },
true // prune
);
}

View File

@ -179,7 +179,7 @@ void Foam::vtkPVFoam::convertMeshPatches()
}
}
if (longName.startsWith("group/"))
if (longName.starts_with("group/"))
{
// Patch group. Collect patch faces.

View File

@ -1221,7 +1221,7 @@ void* Foam::dlOpen(const fileName& libName, const bool check)
(
!handle
&& libName.find('/') == std::string::npos
&& !libso.startsWith("lib")
&& !libso.starts_with("lib")
)
{
// Try with 'lib' prefix

View File

@ -1674,7 +1674,7 @@ void* Foam::dlOpen(const fileName& libName, const bool check)
if
(
libName.find('/') == std::string::npos
&& !libName.startsWith("lib")
&& !libName.starts_with("lib")
)
{
// Try with 'lib' prefix

View File

@ -97,17 +97,6 @@ namespace Foam
}
// file-scope
//
// A file is 'outside' of the case if it has been specified using an
// absolute path (starts with '/')
//
static inline bool isOutsideOfCase(const std::string& file)
{
return !file.empty() && file[0] == '/';
}
// * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * * //
bool Foam::IOobject::fileNameComponents
@ -119,7 +108,7 @@ bool Foam::IOobject::fileNameComponents
)
{
// Convert explicit relative file-system path to absolute file-system path.
if (path.startsWith("./") || path.startsWith("../"))
if (path.starts_with("./") || path.starts_with("../"))
{
fileName absPath = cwd()/path;
absPath.clean();
@ -461,7 +450,10 @@ const Foam::fileName& Foam::IOobject::caseName() const
Foam::fileName Foam::IOobject::path() const
{
if (isOutsideOfCase(instance()))
// A file is 'outside' of the case if it has been specified using an
// absolute path (starts with '/')
if (instance().starts_with('/'))
{
return instance();
}

View File

@ -382,7 +382,7 @@ Foam::label Foam::IOobjectList::prune_0()
return
HashPtrTable<IOobject>::filterKeys
(
[](const word& k){ return k.endsWith("_0"); },
[](const word& k){ return k.ends_with("_0"); },
true // prune
);
}

View File

@ -924,7 +924,7 @@ void Foam::GeometricField<Type, PatchField, GeoMesh>::storeOldTimes() const
(
field0Ptr_
&& timeIndex_ != this->time().timeIndex()
&& !this->name().endsWith("_0")
&& !this->name().ends_with("_0")
)
{
storeOldTime();

View File

@ -1164,7 +1164,7 @@ void Foam::argList::parse
}
// Case-relative if not absolute and not "./" etc
if (!source.isAbsolute() && !source.startsWith("."))
if (!source.isAbsolute() && !source.starts_with('.'))
{
source = rootPath_/globalCase_/source;
adjustOpt = true;
@ -1632,8 +1632,8 @@ void Foam::argList::displayDoc(bool source) const
for (const fileName& dir : docDirs)
{
// http protocols are last in the list
if (dir.startsWith("http:") || dir.startsWith("https:"))
// The http protocols are last in the list
if (dir.starts_with("http:") || dir.starts_with("https:"))
{
url = dir/executable_ + docExt;
break;
@ -1643,7 +1643,7 @@ void Foam::argList::displayDoc(bool source) const
if
(
docFile.startsWith("file://")
docFile.starts_with("file://")
? isFile(docFile.substr(7)) // check part after "file://"
: isFile(docFile)
)

View File

@ -77,11 +77,11 @@ void Foam::solution::read(const dictionary& dict)
{
scalar value = relaxDict.get<scalar>(e);
if (e.startsWith("p"))
if (e.starts_with('p'))
{
fieldRelaxDict_.add(e, value);
}
else if (e.startsWith("rho"))
else if (e.starts_with("rho"))
{
fieldRelaxDict_.add(e, value);
}

View File

@ -191,36 +191,31 @@ bool Foam::fileName::equals(const std::string& s1, const std::string& s2)
}
bool Foam::fileName::isBackup(const std::string& str)
bool Foam::fileName::isBackup(const std::string& s)
{
if (str.empty())
if (s.empty())
{
return false;
}
else if (str.back() == '~')
else if (s.back() == '~')
{
return true;
}
// Now check the extension
const auto dot = find_ext(str);
auto dot = find_ext(s);
if (dot == npos)
{
return false;
}
const std::string ending = str.substr(dot+1);
if (ending.empty())
{
return false;
}
++dot;
return
(
ending == "bak" || ending == "BAK"
|| ending == "old" || ending == "save"
!s.compare(dot, npos, "bak") || !s.compare(dot, npos, "BAK")
|| !s.compare(dot, npos, "old") || !s.compare(dot, npos, "save")
);
}
@ -448,7 +443,7 @@ Foam::fileName Foam::fileName::relative
if
(
top && (f.size() > (top+1)) && f[top] == '/'
&& f.startsWith(parent)
&& f.starts_with(parent)
)
{
if (caseTag)

View File

@ -128,7 +128,7 @@ inline void Foam::fileName::stripInvalid()
}
removeRepeated('/');
removeTrailing('/');
removeEnd('/');
}
}
@ -137,7 +137,7 @@ inline bool Foam::fileName::isAbsolute(const std::string& str)
{
return
(
(!str.empty() && str[0] == '/')
(!str.empty() && str.front() == '/') // ie, str.starts_with('/')
#ifdef _WIN32
||
(

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2017 OpenCFD Ltd.
Copyright (C) 2016-2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -34,7 +34,9 @@ License
/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
const char* const Foam::string::typeName = "string";
int Foam::string::debug(Foam::debug::debugSwitch(string::typeName, 0));
int Foam::string::debug(Foam::debug::debugSwitch(Foam::string::typeName, 0));
const Foam::string Foam::string::null;
@ -117,16 +119,14 @@ Foam::string::size_type Foam::string::count(const char c) const
Foam::string& Foam::string::replace
(
const string& oldStr,
const string& newStr,
const size_type start
const std::string& s1,
const std::string& s2,
size_type pos
)
{
size_type pos = start;
if ((pos = find(oldStr, pos)) != npos)
if ((pos = find(s1, pos)) != npos)
{
std::string::replace(pos, oldStr.size(), newStr);
std::string::replace(pos, s1.size(), s2);
}
return *this;
@ -135,24 +135,20 @@ Foam::string& Foam::string::replace
Foam::string& Foam::string::replaceAll
(
const string& oldStr,
const string& newStr,
const size_type start
const std::string& s1,
const std::string& s2,
size_type pos
)
{
const size_type lenOld = oldStr.size();
const size_type lenNew = newStr.size();
const auto n1 = s1.length();
const auto n2 = s2.length();
if (lenOld)
if (n1)
{
for
(
size_type pos = start;
(pos = find(oldStr, pos)) != npos;
pos += lenNew
)
while ((pos = find(s1, pos)) != npos)
{
std::string::replace(pos, lenOld, newStr);
std::string::replace(pos, n1, s2);
pos += n2;
}
}
@ -201,47 +197,14 @@ bool Foam::string::removeRepeated(const char character)
}
Foam::string Foam::string::removeRepeated(const char character) const
{
string str(*this);
str.removeRepeated(character);
return str;
}
bool Foam::string::removeTrailing(const char character)
{
const string::size_type nChar = size();
if (character && nChar > 1 && operator[](nChar-1) == character)
{
resize(nChar-1);
return true;
}
return false;
}
Foam::string Foam::string::removeTrailing(const char character) const
{
string str(*this);
str.removeTrailing(character);
return str;
}
bool Foam::string::removeStart(const std::string& text)
{
const size_type txtLen = text.size();
if (!txtLen)
{
return true;
}
const auto txtLen = text.length();
const auto strLen = length();
const size_type strLen = this->size();
if (strLen >= txtLen && !compare(0, txtLen, text))
if (txtLen && strLen >= txtLen && !compare(0, txtLen, text))
{
this->erase(0, txtLen);
erase(0, txtLen);
return true;
}
@ -251,16 +214,12 @@ bool Foam::string::removeStart(const std::string& text)
bool Foam::string::removeEnd(const std::string& text)
{
const size_type txtLen = text.size();
if (!txtLen)
{
return true;
}
const auto txtLen = text.length();
const auto strLen = length();
const size_type strLen = this->size();
if (strLen >= txtLen && !compare(strLen - txtLen, npos, text))
if (txtLen && strLen >= txtLen && !compare(strLen - txtLen, npos, text))
{
this->resize(strLen - txtLen);
resize(strLen - txtLen);
return true;
}
@ -268,29 +227,28 @@ bool Foam::string::removeEnd(const std::string& text)
}
bool Foam::string::startsWith(const std::string& text) const
bool Foam::string::removeStart(const char c)
{
const size_type strLen = this->size();
const size_type txtLen = text.size();
if (length() > 1 && front() == c)
{
erase(0, 1);
return true;
}
return
(
!txtLen
|| (strLen >= txtLen && !compare(0, txtLen, text))
);
return false;
}
bool Foam::string::endsWith(const std::string& text) const
bool Foam::string::removeEnd(const char c)
{
const size_type strLen = this->size();
const size_type txtLen = text.size();
const auto n = length();
if (n > 1 && back() == c)
{
resize(n-1);
return true;
}
return
(
!txtLen
|| (strLen >= txtLen && !compare(strLen - txtLen, npos, text))
);
return false;
}

View File

@ -40,6 +40,7 @@ See also
configuration directory
SourceFiles
stringI.H
string.C
stringIO.C
stringTemplates.C
@ -51,7 +52,6 @@ SourceFiles
#include "char.H"
#include "Hasher.H"
#include <string>
#include <cstring>
#include <cstdlib>
@ -136,9 +136,12 @@ protected:
public:
// Static data members
// Static Data Members
//- The type name "string"
static const char* const typeName;
//- The debug flag
static int debug;
//- An empty string
@ -183,12 +186,7 @@ public:
explicit string(Istream& is);
// Member Functions
//- Count the number of occurrences of the specified character
//- in the string
// Partially deprecated (NOV-2017) in favour of stringOps::count
size_type count(const char c) const;
// Static Member Functions
//- Does the string contain valid characters only?
template<class String>
@ -215,6 +213,9 @@ public:
const char quote = '\\'
);
// Member Functions
//- Test for equality.
// \return True when strings match literally.
inline bool match(const std::string& text) const;
@ -222,22 +223,23 @@ public:
//- Avoid masking the normal std::string replace
using std::string::replace;
//- Replace first occurrence of sub-string oldStr with newStr,
//- beginning at start
//- Replace first occurrence of sub-string s1 with s2,
//- beginning at pos
string& replace
(
const string& oldStr,
const string& newStr,
const size_type start = 0
const std::string& s1,
const std::string& s2,
size_type pos = 0
);
//- Replace all occurrences of sub-string oldStr with newStr,
//- beginning at start. This is a no-op if oldStr is empty.
//- Replace all occurrences of sub-string s1 with s2,
//- beginning at pos in the string.
// This is a no-op if s1 is empty.
string& replaceAll
(
const string& oldStr,
const string& newStr,
const size_type start = 0
const std::string& s1,
const std::string& s2,
size_type pos = 0
);
//- Inplace expand initial tags, tildes, and all occurrences of
@ -252,34 +254,21 @@ public:
// \return True if string changed
bool removeRepeated(const char character);
//- Return string with repeated characters removed
string removeRepeated(const char character) const;
//- Remove trailing character, unless string is a single character
// \return True if string changed
bool removeTrailing(const char character);
//- Return string with trailing character removed,
// unless string is a single character
string removeTrailing(const char character) const;
//- Remove the given text from the start of the string.
// \return True if the removal occurred or the given text is empty.
// \return True if the removal occurred
bool removeStart(const std::string& text);
//- Remove leading character, unless string is a single character
// \return True if the removal occurred
bool removeStart(const char c);
//- Remove the given text from the end of the string.
// Always true if the removal occurred or the given text is empty.
// \return True if the removal occurred
bool removeEnd(const std::string& text);
//- True if the string starts with the given text.
// Always true if the given text is empty or if the string
// is identical to the given text.
bool startsWith(const std::string& text) const;
//- True if the string ends with the given text.
// Always true if the given text is empty or if the string
// is identical to the given text.
bool endsWith(const std::string& text) const;
//- Remove trailing character, unless string is a single character
// \return True if the removal occurred
bool removeEnd(const char c);
// Editing
@ -293,6 +282,50 @@ public:
//- Test for equality. Allows use as a predicate.
// \return True when strings match literally.
inline bool operator()(const std::string& text) const;
// Housekeeping
//- True if string starts with the given prefix (cf. C++20)
bool starts_with(const std::string& s) const
{
return (size() >= s.size() && !compare(0, s.size(), s));
}
//- True if string starts with the given character (cf. C++20)
bool starts_with(const char c) const
{
return (!empty() && front() == c);
}
//- True if string ends with the given suffix (cf. C++20)
bool ends_with(const std::string& s) const
{
return (size() >= s.size() && !compare(size()-s.size(), npos, s));
}
//- True if string ends with the given character (cf. C++20)
bool ends_with(const char c) const
{
return (!empty() && back() == c);
}
//- Count the number of occurrences of the specified character
//- in the string
// Partially deprecated (NOV-2017) in favour of stringOps::count
size_type count(const char c) const;
//- Deprecated(2019-11)
// \deprecated(2019-11) use starts_with instead
bool startsWith(const std::string& s) const { return starts_with(s); }
//- Deprecated(2019-11)
// \deprecated(2019-11) use ends_with instead
bool endsWith(const std::string& s) const { return ends_with(s); }
//- Deprecated(2019-11)
// \deprecated(2019-11) use removeEnd instead
bool removeTrailing(const char c) { return removeEnd(c); }
};

View File

@ -68,7 +68,7 @@ inline bool Foam::string::removePath()
return false;
}
this->erase(0, i+1);
erase(0, i+1);
return true;
}
@ -82,7 +82,7 @@ inline bool Foam::string::removeExt()
return false;
}
this->resize(i);
erase(i);
return true;
}
@ -163,7 +163,7 @@ inline bool Foam::string::stripInvalid(std::string& str)
}
}
str.resize(nChar);
str.erase(nChar);
return true;
}
@ -228,7 +228,7 @@ Foam::string::quotemeta(const std::string& str, const char quote)
sQuoted += c;
}
sQuoted.resize(sQuoted.size());
sQuoted.shrink_to_fit();
return sQuoted;
}
@ -251,7 +251,7 @@ inline String Foam::string::validate(const std::string& str)
}
}
out.resize(len);
out.erase(len);
return out;
}

View File

@ -71,7 +71,7 @@ inline void Foam::ensight::FileName::stripInvalid()
string::stripInvalid<FileName>(*this);
removeRepeated('/');
removeTrailing('/');
removeEnd('/');
if (empty())
{

View File

@ -618,7 +618,7 @@ Foam::label Foam::vtk::seriesWriter::scan
return
(
minLen < file.length()
&& file.hasExt(ext) && file.startsWith(stem)
&& file.hasExt(ext) && file.starts_with(stem)
);
};

View File

@ -256,7 +256,7 @@ bool Foam::functionObjects::vtkCloud::writeCloud
(
[](const word& k)
{
return k.startsWith("position") || k.startsWith("coordinate");
return k.starts_with("position") || k.starts_with("coordinate");
},
true // prune
);

View File

@ -226,7 +226,7 @@ bool Foam::functionObjects::ensightWrite::write()
// Prune restart fields
acceptField.filterKeys
(
[](const word& k){ return k.endsWith("_0"); },
[](const word& k){ return k.ends_with("_0"); },
true // prune
);

View File

@ -304,7 +304,7 @@ bool Foam::functionObjects::vtkWrite::write()
// Prune restart fields
acceptField.filterKeys
(
[](const word& k){ return k.endsWith("_0"); },
[](const word& k){ return k.ends_with("_0"); },
true // prune
);

View File

@ -115,7 +115,7 @@ bool Foam::fileFormats::OBJedgeFormat::read(const fileName& filename)
string line = this->getLineNoComment(is);
// Line continuations
while (line.removeEnd("\\"))
while (line.removeEnd('\\'))
{
line += this->getLineNoComment(is);
}

View File

@ -611,7 +611,7 @@ bool Foam::dynamicOversetFvMesh::update()
Foam::word Foam::dynamicOversetFvMesh::baseName(const word& name)
{
if (name.endsWith("_0"))
if (name.ends_with("_0"))
{
return baseName(name.substr(0, name.size()-2));
}

View File

@ -149,7 +149,7 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
// ANSA extension
// line 1: $ANSA_NAME;<int>;<word>;
// line 2: $partName
if (line.startsWith("$ANSA_NAME"))
if (line.starts_with("$ANSA_NAME"))
{
const auto sem0 = line.find(';', 0);
const auto sem1 = line.find(';', sem0+1);
@ -167,7 +167,7 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
string rawName;
is.getLine(rawName);
rawName.removeEnd("\r"); // Possible CR-NL
rawName.removeEnd('\r'); // Possible CR-NL
ansaName = word::validate(rawName.substr(1));
// Info<< "ANSA tag for NastranID:" << ansaId
@ -179,7 +179,7 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
// HYPERMESH extension
// $HMNAME COMP 1"partName"
if (line.startsWith("$HMNAME COMP") && line.find('"') != string::npos)
if (line.starts_with("$HMNAME COMP") && line.find('"') != string::npos)
{
label groupId = readLabel(line.substr(16, 16));

View File

@ -83,7 +83,7 @@ bool Foam::fileFormats::OBJsurfaceFormat<Face>::read
string line = this->getLineNoComment(is);
// Line continuations
while (line.removeEnd("\\"))
while (line.removeEnd('\\'))
{
line += this->getLineNoComment(is);
}