aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2022-02-02 12:38:37 +0100
committerEelco Dolstra <edolstra@gmail.com>2022-02-02 12:38:37 +0100
commitcd35bbbeef72375873e396b9ffed14a4638693a8 (patch)
tree3db28adee43b34ce0875d27f21bab247a34e4586 /src/libexpr
parent73d5f38a47e7c3dea62994cfb8f962976194f767 (diff)
parentd439dceb3bc47f10a6f1f5b8cf4a5b17adc80071 (diff)
Merge branch 'more-stringviews' of https://github.com/pennae/nix
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/attr-path.cc2
-rw-r--r--src/libexpr/eval.cc60
-rw-r--r--src/libexpr/eval.hh17
-rw-r--r--src/libexpr/flake/flake.cc10
-rw-r--r--src/libexpr/get-drvs.cc2
-rw-r--r--src/libexpr/json-to-value.cc2
-rw-r--r--src/libexpr/json-to-value.hh2
-rw-r--r--src/libexpr/parser.y12
-rw-r--r--src/libexpr/primops.cc119
-rw-r--r--src/libexpr/primops/context.cc9
-rw-r--r--src/libexpr/primops/fetchMercurial.cc12
-rw-r--r--src/libexpr/primops/fetchTree.cc4
-rw-r--r--src/libexpr/primops/fromTOML.cc2
13 files changed, 135 insertions, 118 deletions
diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc
index c50c6d92b..edef4d9f8 100644
--- a/src/libexpr/attr-path.cc
+++ b/src/libexpr/attr-path.cc
@@ -121,7 +121,7 @@ Pos findPackageFilename(EvalState & state, Value & v, std::string what)
std::string filename(pos, 0, colon);
unsigned int lineno;
try {
- lineno = std::stoi(std::string(pos, colon + 1));
+ lineno = std::stoi(std::string(pos, colon + 1, string::npos));
} catch (std::invalid_argument & e) {
throw ParseError("cannot parse line number '%s'", pos);
}
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index b884b4001..3332dd703 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -1,5 +1,6 @@
#include "eval.hh"
#include "hash.hh"
+#include "types.hh"
#include "util.hh"
#include "store-api.hh"
#include "derivations.hh"
@@ -1694,7 +1695,7 @@ void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const Po
void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
{
PathSet context;
- std::vector<std::string> s;
+ std::vector<BackedStringView> s;
size_t sSize = 0;
NixInt n = 0;
NixFloat nf = 0;
@@ -1705,7 +1706,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
const auto str = [&] {
std::string result;
result.reserve(sSize);
- for (const auto & part : s) result += part;
+ for (const auto & part : s) result += *part;
return result;
};
/* c_str() is not str().c_str() because we want to create a string
@@ -1715,15 +1716,18 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
char * result = allocString(sSize + 1);
char * tmp = result;
for (const auto & part : s) {
- memcpy(tmp, part.c_str(), part.size());
- tmp += part.size();
+ memcpy(tmp, part->data(), part->size());
+ tmp += part->size();
}
*tmp = 0;
return result;
};
+ Value values[es->size()];
+ Value * vTmpP = values;
+
for (auto & [i_pos, i] : *es) {
- Value vTmp;
+ Value & vTmp = *vTmpP++;
i->eval(state, env, vTmp);
/* If the first element is a path, then the result will also
@@ -1756,9 +1760,9 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
/* skip canonization of first path, which would only be not
canonized in the first place if it's coming from a ./${foo} type
path */
- s.emplace_back(
- state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first));
- sSize += s.back().size();
+ auto part = state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first);
+ sSize += part->size();
+ s.emplace_back(std::move(part));
}
first = false;
@@ -1857,7 +1861,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos)
}
-string EvalState::forceString(Value & v, const Pos & pos)
+std::string_view EvalState::forceString(Value & v, const Pos & pos)
{
forceValue(v, pos);
if (v.type() != nString) {
@@ -1866,7 +1870,7 @@ string EvalState::forceString(Value & v, const Pos & pos)
else
throwTypeError("value is %1% while a string was expected", v);
}
- return string(v.string.s);
+ return v.string.s;
}
@@ -1901,17 +1905,17 @@ std::vector<std::pair<Path, std::string>> Value::getContext()
}
-string EvalState::forceString(Value & v, PathSet & context, const Pos & pos)
+std::string_view EvalState::forceString(Value & v, PathSet & context, const Pos & pos)
{
- string s = forceString(v, pos);
+ auto s = forceString(v, pos);
copyContext(v, context);
return s;
}
-string EvalState::forceStringNoCtx(Value & v, const Pos & pos)
+std::string_view EvalState::forceStringNoCtx(Value & v, const Pos & pos)
{
- string s = forceString(v, pos);
+ auto s = forceString(v, pos);
if (v.string.context) {
if (pos)
throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')",
@@ -1942,34 +1946,35 @@ std::optional<string> EvalState::tryAttrsToString(const Pos & pos, Value & v,
if (i != v.attrs->end()) {
Value v1;
callFunction(*i->value, v, v1, pos);
- return coerceToString(pos, v1, context, coerceMore, copyToStore);
+ return coerceToString(pos, v1, context, coerceMore, copyToStore).toOwned();
}
return {};
}
-string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
+BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
bool coerceMore, bool copyToStore, bool canonicalizePath)
{
forceValue(v, pos);
- string s;
-
if (v.type() == nString) {
copyContext(v, context);
- return v.string.s;
+ return std::string_view(v.string.s);
}
if (v.type() == nPath) {
- Path path(canonicalizePath ? canonPath(v.path) : v.path);
- return copyToStore ? copyPathToStore(context, path) : path;
+ BackedStringView path(PathView(v.path));
+ if (canonicalizePath)
+ path = canonPath(*path);
+ if (copyToStore)
+ path = copyPathToStore(context, std::move(path).toOwned());
+ return path;
}
if (v.type() == nAttrs) {
auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore);
- if (maybeString) {
- return *maybeString;
- }
+ if (maybeString)
+ return std::move(*maybeString);
auto i = v.attrs->find(sOutPath);
if (i == v.attrs->end()) throwTypeError(pos, "cannot coerce a set to a string");
return coerceToString(pos, *i->value, context, coerceMore, copyToStore);
@@ -1991,14 +1996,13 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
if (v.isList()) {
string result;
for (auto [n, v2] : enumerate(v.listItems())) {
- result += coerceToString(pos, *v2,
- context, coerceMore, copyToStore);
+ result += *coerceToString(pos, *v2, context, coerceMore, copyToStore);
if (n < v.listSize() - 1
/* !!! not quite correct */
&& (!v2->isList() || v2->listSize() != 0))
result += " ";
}
- return result;
+ return std::move(result);
}
}
@@ -2032,7 +2036,7 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path)
Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
{
- string path = coerceToString(pos, v, context, false, false);
+ string path = coerceToString(pos, v, context, false, false).toOwned();
if (path == "" || path[0] != '/')
throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path);
return path;
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index c59203aa5..04acc5728 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -1,6 +1,7 @@
#pragma once
#include "attr-set.hh"
+#include "types.hh"
#include "value.hh"
#include "nixexpr.hh"
#include "symbol-table.hh"
@@ -201,8 +202,8 @@ public:
void resetFileCache();
/* Look up a file in the search path. */
- Path findFile(const string & path);
- Path findFile(SearchPath & searchPath, const string & path, const Pos & pos = noPos);
+ Path findFile(const std::string_view path);
+ Path findFile(SearchPath & searchPath, const std::string_view path, const Pos & pos = noPos);
/* If the specified search path element is a URI, download it. */
std::pair<bool, std::string> resolveSearchPathElem(const SearchPathElem & elem);
@@ -236,9 +237,9 @@ public:
inline void forceList(Value & v);
inline void forceList(Value & v, const Pos & pos);
void forceFunction(Value & v, const Pos & pos); // either lambda or primop
- string forceString(Value & v, const Pos & pos = noPos);
- string forceString(Value & v, PathSet & context, const Pos & pos = noPos);
- string forceStringNoCtx(Value & v, const Pos & pos = noPos);
+ std::string_view forceString(Value & v, const Pos & pos = noPos);
+ std::string_view forceString(Value & v, PathSet & context, const Pos & pos = noPos);
+ std::string_view forceStringNoCtx(Value & v, const Pos & pos = noPos);
/* Return true iff the value `v' denotes a derivation (i.e. a
set with attribute `type = "derivation"'). */
@@ -251,7 +252,7 @@ public:
string. If `coerceMore' is set, also converts nulls, integers,
booleans and lists to a string. If `copyToStore' is set,
referenced paths are copied to the Nix store as a side effect. */
- string coerceToString(const Pos & pos, Value & v, PathSet & context,
+ BackedStringView coerceToString(const Pos & pos, Value & v, PathSet & context,
bool coerceMore = false, bool copyToStore = true,
bool canonicalizePath = true);
@@ -309,8 +310,8 @@ private:
friend struct ExprAttrs;
friend struct ExprLet;
- Expr * parse(char * text, size_t length, FileOrigin origin, const Path & path,
- const Path & basePath, StaticEnv & staticEnv);
+ Expr * parse(char * text, size_t length, FileOrigin origin, const PathView path,
+ const PathView basePath, StaticEnv & staticEnv);
public:
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index 0fbe9b960..27ba3288b 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -250,10 +250,12 @@ static Flake getFlake(
for (auto & setting : *nixConfig->value->attrs) {
forceTrivialValue(state, *setting.value, *setting.pos);
if (setting.value->type() == nString)
- flake.config.settings.insert({setting.name, state.forceStringNoCtx(*setting.value, *setting.pos)});
+ flake.config.settings.insert({setting.name, string(state.forceStringNoCtx(*setting.value, *setting.pos))});
else if (setting.value->type() == nPath) {
PathSet emptyContext = {};
- flake.config.settings.insert({setting.name, state.coerceToString(*setting.pos, *setting.value, emptyContext, false, true, true)});
+ flake.config.settings.emplace(
+ setting.name,
+ state.coerceToString(*setting.pos, *setting.value, emptyContext, false, true, true) .toOwned());
}
else if (setting.value->type() == nInt)
flake.config.settings.insert({setting.name, state.forceInt(*setting.value, *setting.pos)});
@@ -265,7 +267,7 @@ static Flake getFlake(
if (elem->type() != nString)
throw TypeError("list element in flake configuration setting '%s' is %s while a string is expected",
setting.name, showType(*setting.value));
- ss.push_back(state.forceStringNoCtx(*elem, *setting.pos));
+ ss.emplace_back(state.forceStringNoCtx(*elem, *setting.pos));
}
flake.config.settings.insert({setting.name, ss});
}
@@ -726,7 +728,7 @@ static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Va
{
state.requireExperimentalFeatureOnEvaluation(Xp::Flakes, "builtins.getFlake", pos);
- auto flakeRefS = state.forceStringNoCtx(*args[0], pos);
+ string flakeRefS(state.forceStringNoCtx(*args[0], pos));
auto flakeRef = parseFlakeRef(flakeRefS, {}, true);
if (evalSettings.pureEval && !flakeRef.input.isImmutable())
throw Error("cannot call 'getFlake' on mutable flake reference '%s', at %s (use --impure to override)", flakeRefS, pos);
diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc
index 25fd9b949..2651266b2 100644
--- a/src/libexpr/get-drvs.cc
+++ b/src/libexpr/get-drvs.cc
@@ -104,7 +104,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
/* For each output... */
for (auto elem : i->value->listItems()) {
/* Evaluate the corresponding set. */
- string name = state->forceStringNoCtx(*elem, *i->pos);
+ string name(state->forceStringNoCtx(*elem, *i->pos));
Bindings::iterator out = attrs->find(state->symbols.create(name));
if (out == attrs->end()) continue; // FIXME: throw error?
state->forceAttrs(*out->value);
diff --git a/src/libexpr/json-to-value.cc b/src/libexpr/json-to-value.cc
index 88716250c..99a475ff9 100644
--- a/src/libexpr/json-to-value.cc
+++ b/src/libexpr/json-to-value.cc
@@ -163,7 +163,7 @@ public:
}
};
-void parseJSON(EvalState & state, const string & s_, Value & v)
+void parseJSON(EvalState & state, const std::string_view & s_, Value & v)
{
JSONSax parser(state, v);
bool res = json::sax_parse(s_, &parser);
diff --git a/src/libexpr/json-to-value.hh b/src/libexpr/json-to-value.hh
index 3b0fdae11..84bec4eba 100644
--- a/src/libexpr/json-to-value.hh
+++ b/src/libexpr/json-to-value.hh
@@ -8,6 +8,6 @@ namespace nix {
MakeError(JSONParseError, EvalError);
-void parseJSON(EvalState & state, const string & s, Value & v);
+void parseJSON(EvalState & state, const std::string_view & s, Value & v);
}
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 7a8e93c12..b7910da8c 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -598,7 +598,7 @@ namespace nix {
Expr * EvalState::parse(char * text, size_t length, FileOrigin origin,
- const Path & path, const Path & basePath, StaticEnv & staticEnv)
+ const PathView path, const PathView basePath, StaticEnv & staticEnv)
{
yyscan_t scanner;
ParseData data(*this);
@@ -709,24 +709,24 @@ void EvalState::addToSearchPath(const string & s)
}
-Path EvalState::findFile(const string & path)
+Path EvalState::findFile(const std::string_view path)
{
return findFile(searchPath, path);
}
-Path EvalState::findFile(SearchPath & searchPath, const string & path, const Pos & pos)
+Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, const Pos & pos)
{
for (auto & i : searchPath) {
std::string suffix;
if (i.first.empty())
- suffix = "/" + path;
+ suffix = concatStrings("/", path);
else {
auto s = i.first.size();
if (path.compare(0, s, i.first) != 0 ||
(path.size() > s && path[s] != '/'))
continue;
- suffix = path.size() == s ? "" : "/" + string(path, s);
+ suffix = path.size() == s ? "" : concatStrings("/", path.substr(s));
}
auto r = resolveSearchPathElem(i);
if (!r.first) continue;
@@ -735,7 +735,7 @@ Path EvalState::findFile(SearchPath & searchPath, const string & path, const Pos
}
if (hasPrefix(path, "nix/"))
- return corepkgsPrefix + path.substr(4);
+ return concatStrings(corepkgsPrefix, path.substr(4));
throw ThrownError({
.msg = hintfmt(evalSettings.pureEval
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index ee0ffcd05..10d162cbb 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -314,7 +314,7 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value
{
auto path = realisePath(state, pos, *args[0]);
- string sym = state.forceStringNoCtx(*args[1], pos);
+ string sym(state.forceStringNoCtx(*args[1], pos));
void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
if (!handle)
@@ -350,10 +350,11 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
});
}
PathSet context;
- auto program = state.coerceToString(pos, *elems[0], context, false, false);
+ auto program = state.coerceToString(pos, *elems[0], context, false, false).toOwned();
Strings commandArgs;
- for (unsigned int i = 1; i < args[0]->listSize(); ++i)
- commandArgs.emplace_back(state.coerceToString(pos, *elems[i], context, false, false));
+ for (unsigned int i = 1; i < args[0]->listSize(); ++i) {
+ commandArgs.push_back(state.coerceToString(pos, *elems[i], context, false, false).toOwned());
+ }
try {
auto _ = state.realiseContext(context); // FIXME: Handle CA derivations
} catch (InvalidPathError & e) {
@@ -706,7 +707,7 @@ static RegisterPrimOp primop_abort({
.fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
- string s = state.coerceToString(pos, *args[0], context);
+ string s = state.coerceToString(pos, *args[0], context).toOwned();
throw Abort("evaluation aborted with the following error message: '%1%'", s);
}
});
@@ -724,7 +725,7 @@ static RegisterPrimOp primop_throw({
.fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
- string s = state.coerceToString(pos, *args[0], context);
+ string s = state.coerceToString(pos, *args[0], context).toOwned();
throw ThrownError(s);
}
});
@@ -736,7 +737,7 @@ static void prim_addErrorContext(EvalState & state, const Pos & pos, Value * * a
v = *args[1];
} catch (Error & e) {
PathSet context;
- e.addTrace(std::nullopt, state.coerceToString(pos, *args[0], context));
+ e.addTrace(std::nullopt, state.coerceToString(pos, *args[0], context).toOwned());
throw;
}
}
@@ -825,7 +826,7 @@ static RegisterPrimOp primop_tryEval({
/* Return an environment variable. Use with care. */
static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
- string name = state.forceStringNoCtx(*args[0], pos);
+ string name(state.forceStringNoCtx(*args[0], pos));
v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or(""));
}
@@ -975,7 +976,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
const string & key = i->name;
vomit("processing attribute '%1%'", key);
- auto handleHashMode = [&](const std::string & s) {
+ auto handleHashMode = [&](const std::string_view s) {
if (s == "recursive") ingestionMethod = FileIngestionMethod::Recursive;
else if (s == "flat") ingestionMethod = FileIngestionMethod::Flat;
else
@@ -1030,7 +1031,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
else if (i->name == state.sArgs) {
state.forceList(*i->value, pos);
for (auto elem : i->value->listItems()) {
- string s = state.coerceToString(posDrvName, *elem, context, true);
+ string s = state.coerceToString(posDrvName, *elem, context, true).toOwned();
drv.args.push_back(s);
}
}
@@ -1066,7 +1067,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
}
} else {
- auto s = state.coerceToString(*i->pos, *i->value, context, true);
+ auto s = state.coerceToString(*i->pos, *i->value, context, true).toOwned();
drv.env.emplace(key, s);
if (i->name == state.sBuilder) drv.builder = std::move(s);
else if (i->name == state.sSystem) drv.platform = std::move(s);
@@ -1399,7 +1400,7 @@ static RegisterPrimOp primop_pathExists({
static void prim_baseNameOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
- v.mkString(baseNameOf(state.coerceToString(pos, *args[0], context, false, false)), context);
+ v.mkString(baseNameOf(*state.coerceToString(pos, *args[0], context, false, false)), context);
}
static RegisterPrimOp primop_baseNameOf({
@@ -1419,7 +1420,8 @@ static RegisterPrimOp primop_baseNameOf({
static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
- Path dir = dirOf(state.coerceToString(pos, *args[0], context, false, false));
+ auto path = state.coerceToString(pos, *args[0], context, false, false);
+ auto dir = dirOf(*path);
if (args[0]->type() == nPath) v.mkPath(dir); else v.mkString(dir, context);
}
@@ -1486,7 +1488,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
);
PathSet context;
- string path = state.coerceToString(pos, *i->value, context, false, false);
+ string path = state.coerceToString(pos, *i->value, context, false, false).toOwned();
try {
auto rewrites = state.realiseContext(context);
@@ -1502,7 +1504,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
searchPath.emplace_back(prefix, path);
}
- string path = state.forceStringNoCtx(*args[1], pos);
+ auto path = state.forceStringNoCtx(*args[1], pos);
v.mkPath(state.checkSourcePath(state.findFile(searchPath, path, pos)));
}
@@ -1516,7 +1518,7 @@ static RegisterPrimOp primop_findFile(RegisterPrimOp::Info {
/* Return the cryptographic hash of a file in base-16. */
static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
- string type = state.forceStringNoCtx(*args[0], pos);
+ auto type = state.forceStringNoCtx(*args[0], pos);
std::optional<HashType> ht = parseHashType(type);
if (!ht)
throw Error({
@@ -1723,7 +1725,7 @@ static RegisterPrimOp primop_toJSON({
/* Parse a JSON string to a value. */
static void prim_fromJSON(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
- string s = state.forceStringNoCtx(*args[0], pos);
+ auto s = state.forceStringNoCtx(*args[0], pos);
try {
parseJSON(state, s, v);
} catch (JSONParseError &e) {
@@ -1752,8 +1754,8 @@ static RegisterPrimOp primop_fromJSON({
static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
- string name = state.forceStringNoCtx(*args[0], pos);
- string contents = state.forceString(*args[1], context, pos);
+ string name(state.forceStringNoCtx(*args[0], pos));
+ string contents(state.forceString(*args[1], context, pos));
StorePathSet refs;
@@ -2153,7 +2155,7 @@ static RegisterPrimOp primop_attrValues({
/* Dynamic version of the `.' operator. */
void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
- string attr = state.forceStringNoCtx(*args[0], pos);
+ auto attr = state.forceStringNoCtx(*args[0], pos);
state.forceAttrs(*args[1], pos);
Bindings::iterator i = getAttr(
state,
@@ -2183,7 +2185,7 @@ static RegisterPrimOp primop_getAttr({
/* Return position information of the specified attribute. */
static void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
- string attr = state.forceStringNoCtx(*args[0], pos);
+ auto attr = state.forceStringNoCtx(*args[0], pos);
state.forceAttrs(*args[1], pos);
Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr));
if (i == args[1]->attrs->end())
@@ -2201,7 +2203,7 @@ static RegisterPrimOp primop_unsafeGetAttrPos(RegisterPrimOp::Info {
/* Dynamic version of the `?' operator. */
static void prim_hasAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
- string attr = state.forceStringNoCtx(*args[0], pos);
+ auto attr = state.forceStringNoCtx(*args[0], pos);
state.forceAttrs(*args[1], pos);
v.mkBool(args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end());
}
@@ -2300,7 +2302,7 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
pos
);
- string name = state.forceStringNoCtx(*j->value, *j->pos);
+ auto name = state.forceStringNoCtx(*j->value, *j->pos);
Symbol sym = state.symbols.create(name);
if (seen.insert(sym).second) {
@@ -3032,7 +3034,7 @@ static void prim_groupBy(EvalState & state, const Pos & pos, Value * * args, Val
for (auto vElem : args[1]->listItems()) {
Value res;
state.callFunction(*args[0], *vElem, res, pos);
- string name = state.forceStringNoCtx(res, pos);
+ auto name = state.forceStringNoCtx(res, pos);
Symbol sym = state.symbols.create(name);
auto vector = attrs.try_emplace(sym, ValueVector()).first;
vector->second.push_back(vElem);
@@ -3288,8 +3290,8 @@ static RegisterPrimOp primop_lessThan({
static void prim_toString(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
- string s = state.coerceToString(pos, *args[0], context, true, false);
- v.mkString(s, context);
+ auto s = state.coerceToString(pos, *args[0], context, true, false);
+ v.mkString(*s, context);
}
static RegisterPrimOp primop_toString({
@@ -3325,7 +3327,7 @@ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, V
int start = state.forceInt(*args[0], pos);
int len = state.forceInt(*args[1], pos);
PathSet context;
- string s = state.coerceToString(pos, *args[2], context);
+ auto s = state.coerceToString(pos, *args[2], context);
if (start < 0)
throw EvalError({
@@ -3333,7 +3335,7 @@ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, V
.errPos = pos
});
- v.mkString((unsigned int) start >= s.size() ? "" : string(s, start, len), context);
+ v.mkString((unsigned int) start >= s->size() ? "" : s->substr(start, len), context);
}
static RegisterPrimOp primop_substring({
@@ -3359,8 +3361,8 @@ static RegisterPrimOp primop_substring({
static void prim_stringLength(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
- string s = state.coerceToString(pos, *args[0], context);
- v.mkInt(s.size());
+ auto s = state.coerceToString(pos, *args[0], context);
+ v.mkInt(s->size());
}
static RegisterPrimOp primop_stringLength({
@@ -3376,7 +3378,7 @@ static RegisterPrimOp primop_stringLength({
/* Return the cryptographic hash of a string in base-16. */
static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
- string type = state.forceStringNoCtx(*args[0], pos);
+ auto type = state.forceStringNoCtx(*args[0], pos);
std::optional<HashType> ht = parseHashType(type);
if (!ht)
throw Error({
@@ -3385,7 +3387,7 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args,
});
PathSet context; // discarded
- string s = state.forceString(*args[1], context, pos);
+ auto s = state.forceString(*args[1], context, pos);
v.mkString(hashString(*ht, s).to_string(Base16, false));
}
@@ -3403,7 +3405,18 @@ static RegisterPrimOp primop_hashString({
struct RegexCache
{
- std::unordered_map<std::string, std::regex> cache;
+ // TODO use C++20 transparent comparison when available
+ std::unordered_map<std::string_view, std::regex> cache;
+ std::list<std::string> keys;
+
+ std::regex get(std::string_view re)
+ {
+ auto it = cache.find(re);
+ if (it != cache.end())
+ return it->second;
+ keys.emplace_back(re);
+ return cache.emplace(keys.back(), std::regex(keys.back(), std::regex::extended)).first->second;
+ }
};
std::shared_ptr<RegexCache> makeRegexCache()
@@ -3417,15 +3430,13 @@ void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v)
try {
- auto regex = state.regexCache->cache.find(re);
- if (regex == state.regexCache->cache.end())
- regex = state.regexCache->cache.emplace(re, std::regex(re, std::regex::extended)).first;
+ auto regex = state.regexCache->get(re);
PathSet context;
- const std::string str = state.forceString(*args[1], context, pos);
+ const auto str = state.forceString(*args[1], context, pos);
- std::smatch match;
- if (!std::regex_match(str, match, regex->second)) {
+ std::cmatch match;
+ if (!std::regex_match(str.begin(), str.end(), match, regex)) {
v.mkNull();
return;
}
@@ -3500,15 +3511,13 @@ void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v)
try {
- auto regex = state.regexCache->cache.find(re);
- if (regex == state.regexCache->cache.end())
- regex = state.regexCache->cache.emplace(re, std::regex(re, std::regex::extended)).first;
+ auto regex = state.regexCache->get(re);
PathSet context;
- const std::string str = state.forceString(*args[1], context, pos);
+ const auto str = state.forceString(*args[1], context, pos);
- auto begin = std::sregex_iterator(str.begin(), str.end(), regex->second);
- auto end = std::sregex_iterator();
+ auto begin = std::cregex_iterator(str.begin(), str.end(), regex);
+ auto end = std::cregex_iterator();
// Any matches results are surrounded by non-matching results.
const size_t len = std::distance(begin, end);
@@ -3520,9 +3529,9 @@ void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v)
return;
}
- for (std::sregex_iterator i = begin; i != end; ++i) {
+ for (auto i = begin; i != end; ++i) {
assert(idx <= 2 * len + 1 - 3);
- std::smatch match = *i;
+ auto match = *i;
// Add a string for non-matched characters.
(v.listElems()[idx++] = state.allocValue())->mkString(match.prefix().str());
@@ -3613,7 +3622,7 @@ static void prim_concatStringsSep(EvalState & state, const Pos & pos, Value * *
for (auto elem : args[1]->listItems()) {
if (first) first = false; else res += sep;
- res += state.coerceToString(pos, *elem, context);
+ res += *state.coerceToString(pos, *elem, context);
}
v.mkString(res, context);
@@ -3643,14 +3652,14 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
vector<string> from;
from.reserve(args[0]->listSize());
for (auto elem : args[0]->listItems())
- from.push_back(state.forceString(*elem, pos));
+ from.emplace_back(state.forceString(*elem, pos));
vector<std::pair<string, PathSet>> to;
to.reserve(args[1]->listSize());
for (auto elem : args[1]->listItems()) {
PathSet ctx;
auto s = state.forceString(*elem, ctx, pos);
- to.push_back(std::make_pair(std::move(s), std::move(ctx)));
+ to.emplace_back(s, std::move(ctx));
}
PathSet context;
@@ -3712,7 +3721,7 @@ static RegisterPrimOp primop_replaceStrings({
static void prim_parseDrvName(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
- string name = state.forceStringNoCtx(*args[0], pos);
+ auto name = state.forceStringNoCtx(*args[0], pos);
DrvName parsed(name);
auto attrs = state.buildBindings(2);
attrs.alloc(state.sName).mkString(parsed.name);
@@ -3736,8 +3745,8 @@ static RegisterPrimOp primop_parseDrvName({
static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
- string version1 = state.forceStringNoCtx(*args[0], pos);
- string version2 = state.forceStringNoCtx(*args[1], pos);
+ auto version1 = state.forceStringNoCtx(*args[0], pos);
+ auto version2 = state.forceStringNoCtx(*args[1], pos);
v.mkInt(compareVersions(version1, version2));
}
@@ -3756,14 +3765,14 @@ static RegisterPrimOp primop_compareVersions({
static void prim_splitVersion(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
- string version = state.forceStringNoCtx(*args[0], pos);
+ auto version = state.forceStringNoCtx(*args[0], pos);
auto iter = version.cbegin();
Strings components;
while (iter != version.cend()) {
auto component = nextComponent(iter, version.cend());
if (component.empty())
break;
- components.emplace_back(std::move(component));
+ components.emplace_back(component);
}
state.mkList(v, components.size());
for (const auto & [n, component] : enumerate(components))
diff --git a/src/libexpr/primops/context.cc b/src/libexpr/primops/context.cc
index a239c06da..654251c23 100644
--- a/src/libexpr/primops/context.cc
+++ b/src/libexpr/primops/context.cc
@@ -7,7 +7,8 @@ namespace nix {
static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
- v.mkString(state.coerceToString(pos, *args[0], context));
+ auto s = state.coerceToString(pos, *args[0], context);
+ v.mkString(*s);
}
static RegisterPrimOp primop_unsafeDiscardStringContext("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
@@ -32,13 +33,13 @@ static RegisterPrimOp primop_hasContext("__hasContext", 1, prim_hasContext);
static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
- string s = state.coerceToString(pos, *args[0], context);
+ auto s = state.coerceToString(pos, *args[0], context);
PathSet context2;
for (auto & p : context)
context2.insert(p.at(0) == '=' ? string(p, 1) : p);
- v.mkString(s, context2);
+ v.mkString(*s, context2);
}
static RegisterPrimOp primop_unsafeDiscardOutputDependency("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
@@ -180,7 +181,7 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
}
for (auto elem : iter->value->listItems()) {
auto name = state.forceStringNoCtx(*elem, *iter->pos);
- context.insert("!" + name + "!" + string(i.name));
+ context.insert(concatStrings("!", name, "!", i.name));
}
}
}
diff --git a/src/libexpr/primops/fetchMercurial.cc b/src/libexpr/primops/fetchMercurial.cc
index 42214c207..c4e1a7bf0 100644
--- a/src/libexpr/primops/fetchMercurial.cc
+++ b/src/libexpr/primops/fetchMercurial.cc
@@ -12,7 +12,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
std::string url;
std::optional<Hash> rev;
std::optional<std::string> ref;
- std::string name = "source";
+ std::string_view name = "source";
PathSet context;
state.forceValue(*args[0], pos);
@@ -22,14 +22,14 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
state.forceAttrs(*args[0], pos);
for (auto & attr : *args[0]->attrs) {
- string n(attr.name);
+ std::string_view n(attr.name);
if (n == "url")
- url = state.coerceToString(*attr.pos, *attr.value, context, false, false);
+ url = state.coerceToString(*attr.pos, *attr.value, context, false, false).toOwned();
else if (n == "rev") {
// Ugly: unlike fetchGit, here the "rev" attribute can
// be both a revision or a branch/tag name.
auto value = state.forceStringNoCtx(*attr.value, *attr.pos);
- if (std::regex_match(value, revRegex))
+ if (std::regex_match(value.begin(), value.end(), revRegex))
rev = Hash::parseAny(value, htSHA1);
else
ref = value;
@@ -50,7 +50,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
});
} else
- url = state.coerceToString(pos, *args[0], context, false, false);
+ url = state.coerceToString(pos, *args[0], context, false, false).toOwned();
// FIXME: git externals probably can be used to bypass the URI
// whitelist. Ah well.
@@ -62,7 +62,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
fetchers::Attrs attrs;
attrs.insert_or_assign("type", "hg");
attrs.insert_or_assign("url", url.find("://") != std::string::npos ? url : "file://" + url);
- attrs.insert_or_assign("name", name);
+ attrs.insert_or_assign("name", string(name));
if (ref) attrs.insert_or_assign("ref", *ref);
if (rev) attrs.insert_or_assign("rev", rev->gitRev());
auto input = fetchers::Input::fromAttrs(std::move(attrs));
diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc
index 6647bd35c..d09e2d9e1 100644
--- a/src/libexpr/primops/fetchTree.cc
+++ b/src/libexpr/primops/fetchTree.cc
@@ -125,7 +125,7 @@ static void fetchTree(
if (attr.name == state.sType) continue;
state.forceValue(*attr.value, *attr.pos);
if (attr.value->type() == nPath || attr.value->type() == nString) {
- auto s = state.coerceToString(*attr.pos, *attr.value, context, false, false);
+ auto s = state.coerceToString(*attr.pos, *attr.value, context, false, false).toOwned();
attrs.emplace(attr.name,
attr.name == "url"
? type == "git"
@@ -151,7 +151,7 @@ static void fetchTree(
input = fetchers::Input::fromAttrs(std::move(attrs));
} else {
- auto url = state.coerceToString(pos, *args[0], context, false, false);
+ auto url = state.coerceToString(pos, *args[0], context, false, false).toOwned();
if (type == "git") {
fetchers::Attrs attrs;
diff --git a/src/libexpr/primops/fromTOML.cc b/src/libexpr/primops/fromTOML.cc
index 80c7e0b82..c0e858b61 100644
--- a/src/libexpr/primops/fromTOML.cc
+++ b/src/libexpr/primops/fromTOML.cc
@@ -9,7 +9,7 @@ static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Va
{
auto toml = state.forceStringNoCtx(*args[0], pos);
- std::istringstream tomlStream(toml);
+ std::istringstream tomlStream(string{toml});
std::function<void(Value &, toml::value)> visit;