use more string_view in utils

there's a couple places that can be easily converted from using strings to using
string_views instead. gives a slight (~1%) boost to system eval.

 # before

  nix eval --raw --impure --expr 'with import <nixpkgs/nixos> {}; system'
    Time (mean ± σ):      2.946 s ±  0.026 s    [User: 2.655 s, System: 0.209 s]
    Range (min … max):    2.905 s …  2.995 s    20 runs

 # after

    Time (mean ± σ):      2.928 s ±  0.024 s    [User: 2.638 s, System: 0.211 s]
    Range (min … max):    2.893 s …  2.970 s    20 runs
This commit is contained in:
pennae 2022-01-12 16:02:29 +01:00
parent e61c4bc25a
commit 44c92a1667
3 changed files with 39 additions and 23 deletions

View file

@ -22,6 +22,7 @@ typedef std::map<string, string> StringMap;
/* Paths are just strings. */ /* Paths are just strings. */
typedef string Path; typedef string Path;
typedef std::string_view PathView;
typedef list<Path> Paths; typedef list<Path> Paths;
typedef set<Path> PathSet; typedef set<Path> PathSet;

View file

@ -106,16 +106,16 @@ Path absPath(Path path, std::optional<Path> dir, bool resolveSymlinks)
} }
Path canonPath(const Path & path, bool resolveSymlinks) Path canonPath(PathView path, bool resolveSymlinks)
{ {
assert(path != ""); assert(path != "");
string s; string s;
s.reserve(256);
if (path[0] != '/') if (path[0] != '/')
throw Error("not an absolute path: '%1%'", path); throw Error("not an absolute path: '%1%'", path);
string::const_iterator i = path.begin(), end = path.end();
string temp; string temp;
/* Count the number of times we follow a symlink and stop at some /* Count the number of times we follow a symlink and stop at some
@ -125,33 +125,37 @@ Path canonPath(const Path & path, bool resolveSymlinks)
while (1) { while (1) {
/* Skip slashes. */ /* Skip slashes. */
while (i != end && *i == '/') i++; while (!path.empty() && path[0] == '/') path.remove_prefix(1);
if (i == end) break; if (path.empty()) break;
/* Ignore `.'. */ /* Ignore `.'. */
if (*i == '.' && (i + 1 == end || i[1] == '/')) if (path == "." || path.substr(0, 2) == "./")
i++; path.remove_prefix(1);
/* If `..', delete the last component. */ /* If `..', delete the last component. */
else if (*i == '.' && i + 1 < end && i[1] == '.' && else if (path == ".." || path.substr(0, 3) == "../")
(i + 2 == end || i[2] == '/'))
{ {
if (!s.empty()) s.erase(s.rfind('/')); if (!s.empty()) s.erase(s.rfind('/'));
i += 2; path.remove_prefix(2);
} }
/* Normal component; copy it. */ /* Normal component; copy it. */
else { else {
s += '/'; s += '/';
while (i != end && *i != '/') s += *i++; if (const auto slash = path.find('/'); slash == string::npos) {
s += path;
path = {};
} else {
s += path.substr(0, slash);
path = path.substr(slash + 1);
}
/* If s points to a symlink, resolve it and continue from there */ /* If s points to a symlink, resolve it and continue from there */
if (resolveSymlinks && isLink(s)) { if (resolveSymlinks && isLink(s)) {
if (++followCount >= maxFollow) if (++followCount >= maxFollow)
throw Error("infinite symlink recursion in path '%1%'", path); throw Error("infinite symlink recursion in path '%1%'", path);
temp = readLink(s) + string(i, end); temp = concatStrings(readLink(s), path);
i = temp.begin(); path = temp;
end = temp.end();
if (!temp.empty() && temp[0] == '/') { if (!temp.empty() && temp[0] == '/') {
s.clear(); /* restart for symlinks pointing to absolute path */ s.clear(); /* restart for symlinks pointing to absolute path */
} else { } else {
@ -164,7 +168,7 @@ Path canonPath(const Path & path, bool resolveSymlinks)
} }
} }
return s.empty() ? "/" : s; return s.empty() ? "/" : std::move(s);
} }
@ -1229,23 +1233,22 @@ void _interrupted()
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
template<class C> C tokenizeString(std::string_view s, const string & separators) template<class C> C tokenizeString(std::string_view s, std::string_view separators)
{ {
C result; C result;
string::size_type pos = s.find_first_not_of(separators, 0); string::size_type pos = s.find_first_not_of(separators, 0);
while (pos != string::npos) { while (pos != string::npos) {
string::size_type end = s.find_first_of(separators, pos + 1); string::size_type end = s.find_first_of(separators, pos + 1);
if (end == string::npos) end = s.size(); if (end == string::npos) end = s.size();
string token(s, pos, end - pos); result.insert(result.end(), string(s, pos, end - pos));
result.insert(result.end(), token);
pos = s.find_first_not_of(separators, end); pos = s.find_first_not_of(separators, end);
} }
return result; return result;
} }
template Strings tokenizeString(std::string_view s, const string & separators); template Strings tokenizeString(std::string_view s, std::string_view separators);
template StringSet tokenizeString(std::string_view s, const string & separators); template StringSet tokenizeString(std::string_view s, std::string_view separators);
template vector<string> tokenizeString(std::string_view s, const string & separators); template vector<string> tokenizeString(std::string_view s, std::string_view separators);
string chomp(std::string_view s) string chomp(std::string_view s)

View file

@ -56,7 +56,7 @@ Path absPath(Path path,
double or trailing slashes. Optionally resolves all symlink double or trailing slashes. Optionally resolves all symlink
components such that each component of the resulting path is *not* components such that each component of the resulting path is *not*
a symbolic link. */ a symbolic link. */
Path canonPath(const Path & path, bool resolveSymlinks = false); Path canonPath(PathView path, bool resolveSymlinks = false);
/* Return the directory part of the given canonical path, i.e., /* Return the directory part of the given canonical path, i.e.,
everything before the final `/'. If the path is the root or an everything before the final `/'. If the path is the root or an
@ -368,15 +368,19 @@ MakeError(FormatError, Error);
/* String tokenizer. */ /* String tokenizer. */
template<class C> C tokenizeString(std::string_view s, const string & separators = " \t\n\r"); template<class C> C tokenizeString(std::string_view s, std::string_view separators = " \t\n\r");
/* Concatenate the given strings with a separator between the /* Concatenate the given strings with a separator between the
elements. */ elements. */
template<class C> template<class C>
string concatStringsSep(const string & sep, const C & ss) string concatStringsSep(const std::string_view sep, const C & ss)
{ {
size_t size = 0;
// need a cast to string_view since this is also called with Symbols
for (const auto & s : ss) size += sep.size() + std::string_view(s).size();
string s; string s;
s.reserve(size);
for (auto & i : ss) { for (auto & i : ss) {
if (s.size() != 0) s += sep; if (s.size() != 0) s += sep;
s += i; s += i;
@ -384,6 +388,14 @@ string concatStringsSep(const string & sep, const C & ss)
return s; return s;
} }
template<class ... Parts>
auto concatStrings(Parts && ... parts)
-> std::enable_if_t<(... && std::is_convertible_v<Parts, std::string_view>), string>
{
std::string_view views[sizeof...(parts)] = { parts... };
return concatStringsSep({}, views);
}
/* Add quotes around a collection of strings. */ /* Add quotes around a collection of strings. */
template<class C> Strings quoteStrings(const C & c) template<class C> Strings quoteStrings(const C & c)