return string_views from forceString*

once a string has been forced we already have dynamic storage allocated for it,
so we can easily reuse that storage instead of copying.
This commit is contained in:
pennae 2022-01-21 14:44:00 +01:00
parent 0d7fae6a57
commit 41d70a2fc8
19 changed files with 94 additions and 87 deletions

View file

@ -121,7 +121,7 @@ Pos findPackageFilename(EvalState & state, Value & v, std::string what)
std::string filename(pos, 0, colon); std::string filename(pos, 0, colon);
unsigned int lineno; unsigned int lineno;
try { try {
lineno = std::stoi(std::string(pos, colon + 1)); lineno = std::stoi(std::string(pos, colon + 1, string::npos));
} catch (std::invalid_argument & e) { } catch (std::invalid_argument & e) {
throw ParseError("cannot parse line number '%s'", pos); throw ParseError("cannot parse line number '%s'", pos);
} }

View file

@ -1857,7 +1857,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); forceValue(v, pos);
if (v.type() != nString) { if (v.type() != nString) {
@ -1866,7 +1866,7 @@ string EvalState::forceString(Value & v, const Pos & pos)
else else
throwTypeError("value is %1% while a string was expected", v); throwTypeError("value is %1% while a string was expected", v);
} }
return string(v.string.s); return v.string.s;
} }
@ -1901,17 +1901,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); copyContext(v, context);
return s; 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 (v.string.context) {
if (pos) if (pos)
throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')",

View file

@ -201,8 +201,8 @@ public:
void resetFileCache(); void resetFileCache();
/* Look up a file in the search path. */ /* Look up a file in the search path. */
Path findFile(const string & path); Path findFile(const std::string_view path);
Path findFile(SearchPath & searchPath, const string & path, const Pos & pos = noPos); Path findFile(SearchPath & searchPath, const std::string_view path, const Pos & pos = noPos);
/* If the specified search path element is a URI, download it. */ /* If the specified search path element is a URI, download it. */
std::pair<bool, std::string> resolveSearchPathElem(const SearchPathElem & elem); std::pair<bool, std::string> resolveSearchPathElem(const SearchPathElem & elem);
@ -236,9 +236,9 @@ public:
inline void forceList(Value & v); inline void forceList(Value & v);
inline void forceList(Value & v, const Pos & pos); inline void forceList(Value & v, const Pos & pos);
void forceFunction(Value & v, const Pos & pos); // either lambda or primop void forceFunction(Value & v, const Pos & pos); // either lambda or primop
string forceString(Value & v, const Pos & pos = noPos); std::string_view forceString(Value & v, const Pos & pos = noPos);
string forceString(Value & v, PathSet & context, const Pos & pos = noPos); std::string_view forceString(Value & v, PathSet & context, const Pos & pos = noPos);
string forceStringNoCtx(Value & v, 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 /* Return true iff the value `v' denotes a derivation (i.e. a
set with attribute `type = "derivation"'). */ set with attribute `type = "derivation"'). */

View file

@ -250,7 +250,7 @@ static Flake getFlake(
for (auto & setting : *nixConfig->value->attrs) { for (auto & setting : *nixConfig->value->attrs) {
forceTrivialValue(state, *setting.value, *setting.pos); forceTrivialValue(state, *setting.value, *setting.pos);
if (setting.value->type() == nString) 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) { else if (setting.value->type() == nPath) {
PathSet emptyContext = {}; PathSet emptyContext = {};
flake.config.settings.insert({setting.name, state.coerceToString(*setting.pos, *setting.value, emptyContext, false, true, true)}); flake.config.settings.insert({setting.name, state.coerceToString(*setting.pos, *setting.value, emptyContext, false, true, true)});
@ -265,7 +265,7 @@ static Flake getFlake(
if (elem->type() != nString) if (elem->type() != nString)
throw TypeError("list element in flake configuration setting '%s' is %s while a string is expected", throw TypeError("list element in flake configuration setting '%s' is %s while a string is expected",
setting.name, showType(*setting.value)); 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}); flake.config.settings.insert({setting.name, ss});
} }
@ -726,7 +726,7 @@ static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Va
{ {
state.requireExperimentalFeatureOnEvaluation(Xp::Flakes, "builtins.getFlake", pos); 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); auto flakeRef = parseFlakeRef(flakeRefS, {}, true);
if (evalSettings.pureEval && !flakeRef.input.isImmutable()) if (evalSettings.pureEval && !flakeRef.input.isImmutable())
throw Error("cannot call 'getFlake' on mutable flake reference '%s', at %s (use --impure to override)", flakeRefS, pos); throw Error("cannot call 'getFlake' on mutable flake reference '%s', at %s (use --impure to override)", flakeRefS, pos);

View file

@ -104,7 +104,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
/* For each output... */ /* For each output... */
for (auto elem : i->value->listItems()) { for (auto elem : i->value->listItems()) {
/* Evaluate the corresponding set. */ /* 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)); Bindings::iterator out = attrs->find(state->symbols.create(name));
if (out == attrs->end()) continue; // FIXME: throw error? if (out == attrs->end()) continue; // FIXME: throw error?
state->forceAttrs(*out->value); state->forceAttrs(*out->value);

View file

@ -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); JSONSax parser(state, v);
bool res = json::sax_parse(s_, &parser); bool res = json::sax_parse(s_, &parser);

View file

@ -8,6 +8,6 @@ namespace nix {
MakeError(JSONParseError, EvalError); MakeError(JSONParseError, EvalError);
void parseJSON(EvalState & state, const string & s, Value & v); void parseJSON(EvalState & state, const std::string_view & s, Value & v);
} }

View file

@ -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); 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) { for (auto & i : searchPath) {
std::string suffix; std::string suffix;
if (i.first.empty()) if (i.first.empty())
suffix = "/" + path; suffix = concatStrings("/", path);
else { else {
auto s = i.first.size(); auto s = i.first.size();
if (path.compare(0, s, i.first) != 0 || if (path.compare(0, s, i.first) != 0 ||
(path.size() > s && path[s] != '/')) (path.size() > s && path[s] != '/'))
continue; continue;
suffix = path.size() == s ? "" : "/" + string(path, s); suffix = path.size() == s ? "" : concatStrings("/", path.substr(s));
} }
auto r = resolveSearchPathElem(i); auto r = resolveSearchPathElem(i);
if (!r.first) continue; if (!r.first) continue;
@ -735,7 +735,7 @@ Path EvalState::findFile(SearchPath & searchPath, const string & path, const Pos
} }
if (hasPrefix(path, "nix/")) if (hasPrefix(path, "nix/"))
return corepkgsPrefix + path.substr(4); return concatStrings(corepkgsPrefix, path.substr(4));
throw ThrownError({ throw ThrownError({
.msg = hintfmt(evalSettings.pureEval .msg = hintfmt(evalSettings.pureEval

View file

@ -314,7 +314,7 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value
{ {
auto path = realisePath(state, pos, *args[0]); 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); void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
if (!handle) if (!handle)
@ -825,7 +825,7 @@ static RegisterPrimOp primop_tryEval({
/* Return an environment variable. Use with care. */ /* Return an environment variable. Use with care. */
static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v) 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("")); v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or(""));
} }
@ -975,7 +975,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
const string & key = i->name; const string & key = i->name;
vomit("processing attribute '%1%'", key); vomit("processing attribute '%1%'", key);
auto handleHashMode = [&](const std::string & s) { auto handleHashMode = [&](const std::string_view s) {
if (s == "recursive") ingestionMethod = FileIngestionMethod::Recursive; if (s == "recursive") ingestionMethod = FileIngestionMethod::Recursive;
else if (s == "flat") ingestionMethod = FileIngestionMethod::Flat; else if (s == "flat") ingestionMethod = FileIngestionMethod::Flat;
else else
@ -1502,7 +1502,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
searchPath.emplace_back(prefix, path); 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))); v.mkPath(state.checkSourcePath(state.findFile(searchPath, path, pos)));
} }
@ -1516,7 +1516,7 @@ static RegisterPrimOp primop_findFile(RegisterPrimOp::Info {
/* Return the cryptographic hash of a file in base-16. */ /* Return the cryptographic hash of a file in base-16. */
static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Value & v) 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); std::optional<HashType> ht = parseHashType(type);
if (!ht) if (!ht)
throw Error({ throw Error({
@ -1723,7 +1723,7 @@ static RegisterPrimOp primop_toJSON({
/* Parse a JSON string to a value. */ /* Parse a JSON string to a value. */
static void prim_fromJSON(EvalState & state, const Pos & pos, Value * * args, Value & v) 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 { try {
parseJSON(state, s, v); parseJSON(state, s, v);
} catch (JSONParseError &e) { } catch (JSONParseError &e) {
@ -1752,8 +1752,8 @@ static RegisterPrimOp primop_fromJSON({
static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
string name = state.forceStringNoCtx(*args[0], pos); string name(state.forceStringNoCtx(*args[0], pos));
string contents = state.forceString(*args[1], context, pos); string contents(state.forceString(*args[1], context, pos));
StorePathSet refs; StorePathSet refs;
@ -2153,7 +2153,7 @@ static RegisterPrimOp primop_attrValues({
/* Dynamic version of the `.' operator. */ /* Dynamic version of the `.' operator. */
void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) 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); state.forceAttrs(*args[1], pos);
Bindings::iterator i = getAttr( Bindings::iterator i = getAttr(
state, state,
@ -2183,7 +2183,7 @@ static RegisterPrimOp primop_getAttr({
/* Return position information of the specified attribute. */ /* Return position information of the specified attribute. */
static void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, Value & v) 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); state.forceAttrs(*args[1], pos);
Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr));
if (i == args[1]->attrs->end()) if (i == args[1]->attrs->end())
@ -2201,7 +2201,7 @@ static RegisterPrimOp primop_unsafeGetAttrPos(RegisterPrimOp::Info {
/* Dynamic version of the `?' operator. */ /* Dynamic version of the `?' operator. */
static void prim_hasAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) 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); state.forceAttrs(*args[1], pos);
v.mkBool(args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end()); v.mkBool(args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end());
} }
@ -2300,7 +2300,7 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
pos pos
); );
string name = state.forceStringNoCtx(*j->value, *j->pos); auto name = state.forceStringNoCtx(*j->value, *j->pos);
Symbol sym = state.symbols.create(name); Symbol sym = state.symbols.create(name);
if (seen.insert(sym).second) { if (seen.insert(sym).second) {
@ -3032,7 +3032,7 @@ static void prim_groupBy(EvalState & state, const Pos & pos, Value * * args, Val
for (auto vElem : args[1]->listItems()) { for (auto vElem : args[1]->listItems()) {
Value res; Value res;
state.callFunction(*args[0], *vElem, res, pos); 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); Symbol sym = state.symbols.create(name);
auto vector = attrs.try_emplace(sym, ValueVector()).first; auto vector = attrs.try_emplace(sym, ValueVector()).first;
vector->second.push_back(vElem); vector->second.push_back(vElem);
@ -3376,7 +3376,7 @@ static RegisterPrimOp primop_stringLength({
/* Return the cryptographic hash of a string in base-16. */ /* Return the cryptographic hash of a string in base-16. */
static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v) 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); std::optional<HashType> ht = parseHashType(type);
if (!ht) if (!ht)
throw Error({ throw Error({
@ -3385,7 +3385,7 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args,
}); });
PathSet context; // discarded 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)); v.mkString(hashString(*ht, s).to_string(Base16, false));
} }
@ -3403,7 +3403,18 @@ static RegisterPrimOp primop_hashString({
struct RegexCache 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() std::shared_ptr<RegexCache> makeRegexCache()
@ -3417,15 +3428,13 @@ void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v)
try { try {
auto regex = state.regexCache->cache.find(re); auto regex = state.regexCache->get(re);
if (regex == state.regexCache->cache.end())
regex = state.regexCache->cache.emplace(re, std::regex(re, std::regex::extended)).first;
PathSet context; PathSet context;
const std::string str = state.forceString(*args[1], context, pos); const auto str = state.forceString(*args[1], context, pos);
std::smatch match; std::cmatch match;
if (!std::regex_match(str, match, regex->second)) { if (!std::regex_match(str.begin(), str.end(), match, regex)) {
v.mkNull(); v.mkNull();
return; return;
} }
@ -3500,15 +3509,13 @@ void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v)
try { try {
auto regex = state.regexCache->cache.find(re); auto regex = state.regexCache->get(re);
if (regex == state.regexCache->cache.end())
regex = state.regexCache->cache.emplace(re, std::regex(re, std::regex::extended)).first;
PathSet context; 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 begin = std::cregex_iterator(str.begin(), str.end(), regex);
auto end = std::sregex_iterator(); auto end = std::cregex_iterator();
// Any matches results are surrounded by non-matching results. // Any matches results are surrounded by non-matching results.
const size_t len = std::distance(begin, end); const size_t len = std::distance(begin, end);
@ -3520,9 +3527,9 @@ void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v)
return; return;
} }
for (std::sregex_iterator i = begin; i != end; ++i) { for (auto i = begin; i != end; ++i) {
assert(idx <= 2 * len + 1 - 3); assert(idx <= 2 * len + 1 - 3);
std::smatch match = *i; auto match = *i;
// Add a string for non-matched characters. // Add a string for non-matched characters.
(v.listElems()[idx++] = state.allocValue())->mkString(match.prefix().str()); (v.listElems()[idx++] = state.allocValue())->mkString(match.prefix().str());
@ -3643,14 +3650,14 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
vector<string> from; vector<string> from;
from.reserve(args[0]->listSize()); from.reserve(args[0]->listSize());
for (auto elem : args[0]->listItems()) 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; vector<std::pair<string, PathSet>> to;
to.reserve(args[1]->listSize()); to.reserve(args[1]->listSize());
for (auto elem : args[1]->listItems()) { for (auto elem : args[1]->listItems()) {
PathSet ctx; PathSet ctx;
auto s = state.forceString(*elem, ctx, pos); 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; PathSet context;
@ -3712,7 +3719,7 @@ static RegisterPrimOp primop_replaceStrings({
static void prim_parseDrvName(EvalState & state, const Pos & pos, Value * * args, Value & v) 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); DrvName parsed(name);
auto attrs = state.buildBindings(2); auto attrs = state.buildBindings(2);
attrs.alloc(state.sName).mkString(parsed.name); attrs.alloc(state.sName).mkString(parsed.name);
@ -3736,8 +3743,8 @@ static RegisterPrimOp primop_parseDrvName({
static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
string version1 = state.forceStringNoCtx(*args[0], pos); auto version1 = state.forceStringNoCtx(*args[0], pos);
string version2 = state.forceStringNoCtx(*args[1], pos); auto version2 = state.forceStringNoCtx(*args[1], pos);
v.mkInt(compareVersions(version1, version2)); v.mkInt(compareVersions(version1, version2));
} }
@ -3756,14 +3763,14 @@ static RegisterPrimOp primop_compareVersions({
static void prim_splitVersion(EvalState & state, const Pos & pos, Value * * args, Value & v) 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(); auto iter = version.cbegin();
Strings components; Strings components;
while (iter != version.cend()) { while (iter != version.cend()) {
auto component = nextComponent(iter, version.cend()); auto component = nextComponent(iter, version.cend());
if (component.empty()) if (component.empty())
break; break;
components.emplace_back(std::move(component)); components.emplace_back(component);
} }
state.mkList(v, components.size()); state.mkList(v, components.size());
for (const auto & [n, component] : enumerate(components)) for (const auto & [n, component] : enumerate(components))

View file

@ -180,7 +180,7 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
} }
for (auto elem : iter->value->listItems()) { for (auto elem : iter->value->listItems()) {
auto name = state.forceStringNoCtx(*elem, *iter->pos); auto name = state.forceStringNoCtx(*elem, *iter->pos);
context.insert("!" + name + "!" + string(i.name)); context.insert(concatStrings("!", name, "!", i.name));
} }
} }
} }

View file

@ -12,7 +12,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
std::string url; std::string url;
std::optional<Hash> rev; std::optional<Hash> rev;
std::optional<std::string> ref; std::optional<std::string> ref;
std::string name = "source"; std::string_view name = "source";
PathSet context; PathSet context;
state.forceValue(*args[0], pos); 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); state.forceAttrs(*args[0], pos);
for (auto & attr : *args[0]->attrs) { for (auto & attr : *args[0]->attrs) {
string n(attr.name); std::string_view n(attr.name);
if (n == "url") if (n == "url")
url = state.coerceToString(*attr.pos, *attr.value, context, false, false); url = state.coerceToString(*attr.pos, *attr.value, context, false, false);
else if (n == "rev") { else if (n == "rev") {
// Ugly: unlike fetchGit, here the "rev" attribute can // Ugly: unlike fetchGit, here the "rev" attribute can
// be both a revision or a branch/tag name. // be both a revision or a branch/tag name.
auto value = state.forceStringNoCtx(*attr.value, *attr.pos); 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); rev = Hash::parseAny(value, htSHA1);
else else
ref = value; ref = value;
@ -62,7 +62,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
fetchers::Attrs attrs; fetchers::Attrs attrs;
attrs.insert_or_assign("type", "hg"); attrs.insert_or_assign("type", "hg");
attrs.insert_or_assign("url", url.find("://") != std::string::npos ? url : "file://" + url); 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 (ref) attrs.insert_or_assign("ref", *ref);
if (rev) attrs.insert_or_assign("rev", rev->gitRev()); if (rev) attrs.insert_or_assign("rev", rev->gitRev());
auto input = fetchers::Input::fromAttrs(std::move(attrs)); auto input = fetchers::Input::fromAttrs(std::move(attrs));

View file

@ -9,7 +9,7 @@ static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Va
{ {
auto toml = state.forceStringNoCtx(*args[0], pos); auto toml = state.forceStringNoCtx(*args[0], pos);
std::istringstream tomlStream(toml); std::istringstream tomlStream(string{toml});
std::function<void(Value &, toml::value)> visit; std::function<void(Value &, toml::value)> visit;

View file

@ -699,10 +699,10 @@ void writeDerivation(Sink & out, const Store & store, const BasicDerivation & dr
} }
std::string hashPlaceholder(const std::string & outputName) std::string hashPlaceholder(const std::string_view outputName)
{ {
// FIXME: memoize? // FIXME: memoize?
return "/" + hashString(htSHA256, "nix-output:" + outputName).to_string(Base32, false); return "/" + hashString(htSHA256, concatStrings("nix-output:", outputName)).to_string(Base32, false);
} }
std::string downstreamPlaceholder(const Store & store, const StorePath & drvPath, std::string_view outputName) std::string downstreamPlaceholder(const Store & store, const StorePath & drvPath, std::string_view outputName)

View file

@ -236,7 +236,7 @@ void writeDerivation(Sink & out, const Store & store, const BasicDerivation & dr
It is used as a placeholder to allow derivations to refer to their It is used as a placeholder to allow derivations to refer to their
own outputs without needing to use the hash of a derivation in own outputs without needing to use the hash of a derivation in
itself, making the hash near-impossible to calculate. */ itself, making the hash near-impossible to calculate. */
std::string hashPlaceholder(const std::string & outputName); std::string hashPlaceholder(const std::string_view outputName);
/* This creates an opaque and almost certainly unique string /* This creates an opaque and almost certainly unique string
deterministically from a derivation path and output name. deterministically from a derivation path and output name.

View file

@ -56,8 +56,8 @@ bool DrvName::matches(const DrvName & n)
} }
string nextComponent(string::const_iterator & p, std::string_view nextComponent(std::string_view::const_iterator & p,
const string::const_iterator end) const std::string_view::const_iterator end)
{ {
/* Skip any dots and dashes (component separators). */ /* Skip any dots and dashes (component separators). */
while (p != end && (*p == '.' || *p == '-')) ++p; while (p != end && (*p == '.' || *p == '-')) ++p;
@ -67,18 +67,18 @@ string nextComponent(string::const_iterator & p,
/* If the first character is a digit, consume the longest sequence /* If the first character is a digit, consume the longest sequence
of digits. Otherwise, consume the longest sequence of of digits. Otherwise, consume the longest sequence of
non-digit, non-separator characters. */ non-digit, non-separator characters. */
string s; auto s = p;
if (isdigit(*p)) if (isdigit(*p))
while (p != end && isdigit(*p)) s += *p++; while (p != end && isdigit(*p)) p++;
else else
while (p != end && (!isdigit(*p) && *p != '.' && *p != '-')) while (p != end && (!isdigit(*p) && *p != '.' && *p != '-'))
s += *p++; p++;
return s; return {s, size_t(p - s)};
} }
static bool componentsLT(const string & c1, const string & c2) static bool componentsLT(const std::string_view c1, const std::string_view c2)
{ {
auto n1 = string2Int<int>(c1); auto n1 = string2Int<int>(c1);
auto n2 = string2Int<int>(c2); auto n2 = string2Int<int>(c2);
@ -94,14 +94,14 @@ static bool componentsLT(const string & c1, const string & c2)
} }
int compareVersions(const string & v1, const string & v2) int compareVersions(const std::string_view v1, const std::string_view v2)
{ {
string::const_iterator p1 = v1.begin(); auto p1 = v1.begin();
string::const_iterator p2 = v2.begin(); auto p2 = v2.begin();
while (p1 != v1.end() || p2 != v2.end()) { while (p1 != v1.end() || p2 != v2.end()) {
string c1 = nextComponent(p1, v1.end()); auto c1 = nextComponent(p1, v1.end());
string c2 = nextComponent(p2, v2.end()); auto c2 = nextComponent(p2, v2.end());
if (componentsLT(c1, c2)) return -1; if (componentsLT(c1, c2)) return -1;
else if (componentsLT(c2, c1)) return 1; else if (componentsLT(c2, c1)) return 1;
} }

View file

@ -27,9 +27,9 @@ private:
typedef list<DrvName> DrvNames; typedef list<DrvName> DrvNames;
string nextComponent(string::const_iterator & p, std::string_view nextComponent(std::string_view::const_iterator & p,
const string::const_iterator end); const std::string_view::const_iterator end);
int compareVersions(const string & v1, const string & v2); int compareVersions(const std::string_view v1, const std::string_view v2);
DrvNames drvNamesFromArgs(const Strings & opArgs); DrvNames drvNamesFromArgs(const Strings & opArgs);
} }

View file

@ -259,7 +259,7 @@ Hash::Hash(std::string_view rest, HashType type, bool isSRI)
throw BadHash("hash '%s' has wrong length for hash type '%s'", rest, printHashType(this->type)); throw BadHash("hash '%s' has wrong length for hash type '%s'", rest, printHashType(this->type));
} }
Hash newHashAllowEmpty(std::string hashStr, std::optional<HashType> ht) Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashType> ht)
{ {
if (hashStr.empty()) { if (hashStr.empty()) {
if (!ht) if (!ht)

View file

@ -107,7 +107,7 @@ public:
}; };
/* Helper that defaults empty hashes to the 0 hash. */ /* Helper that defaults empty hashes to the 0 hash. */
Hash newHashAllowEmpty(std::string hashStr, std::optional<HashType> ht); Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashType> ht);
/* Print a hash in base-16 if it's MD5, or base-32 otherwise. */ /* Print a hash in base-16 if it's MD5, or base-32 otherwise. */
string printHash16or32(const Hash & hash); string printHash16or32(const Hash & hash);

View file

@ -38,7 +38,7 @@ string resolveMirrorUrl(EvalState & state, string url)
if (mirrorList->value->listSize() < 1) if (mirrorList->value->listSize() < 1)
throw Error("mirror URL '%s' did not expand to anything", url); throw Error("mirror URL '%s' did not expand to anything", url);
auto mirror = state.forceString(*mirrorList->value->listElems()[0]); string mirror(state.forceString(*mirrorList->value->listElems()[0]));
return mirror + (hasSuffix(mirror, "/") ? "" : "/") + string(s, p + 1); return mirror + (hasSuffix(mirror, "/") ? "" : "/") + string(s, p + 1);
} }