Skip to content

Commit bd42092

Browse files
Ericson2314glittersharkxokdvium
committed
Use less c_str() in the evaluator, and other cleanups
It is better to avoid null termination for performance and memory safety, wherever possible. These are good cleanups extracted from the Pascal String work that we can land by themselves first, shrinking the diff in that PR. Co-Authored-By: Aspen Smith <[email protected]> Co-Authored-By: Sergei Zimmerman <[email protected]>
1 parent 2d83bc6 commit bd42092

File tree

16 files changed

+64
-38
lines changed

16 files changed

+64
-38
lines changed

src/libexpr-c/nix_api_value.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ nix_get_string(nix_c_context * context, const nix_value * value, nix_get_string_
235235
try {
236236
auto & v = check_value_in(value);
237237
assert(v.type() == nix::nString);
238-
call_nix_get_string_callback(v.c_str(), callback, user_data);
238+
call_nix_get_string_callback(v.string_view(), callback, user_data);
239239
}
240240
NIXC_CATCH_ERRS
241241
}

src/libexpr-test-support/include/nix/expr/tests/libexpr.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ MATCHER_P(IsStringEq, s, fmt("The string is equal to \"%1%\"", s))
106106
if (arg.type() != nString) {
107107
return false;
108108
}
109-
return std::string_view(arg.c_str()) == s;
109+
return arg.string_view() == s;
110110
}
111111

112112
MATCHER_P(IsIntEq, v, fmt("The string is equal to \"%1%\"", v))

src/libexpr-tests/value/value.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "nix/expr/value.hh"
22

33
#include "nix/store/tests/libstore.hh"
4+
#include <gtest/gtest.h>
45

56
namespace nix {
67

@@ -22,4 +23,21 @@ TEST_F(ValueTest, vInt)
2223
ASSERT_EQ(true, vInt.isValid());
2324
}
2425

26+
TEST_F(ValueTest, staticString)
27+
{
28+
Value vStr1;
29+
Value vStr2;
30+
vStr1.mkStringNoCopy("foo");
31+
vStr2.mkStringNoCopy("foo");
32+
33+
auto sd1 = vStr1.string_view();
34+
auto sd2 = vStr2.string_view();
35+
36+
// The strings should be the same
37+
ASSERT_EQ(sd1, sd2);
38+
39+
// The strings should also be backed by the same (static) allocation
40+
ASSERT_EQ(sd1.data(), sd2.data());
41+
}
42+
2543
} // namespace nix

src/libexpr/eval-cache.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ Value & AttrCursor::forceValue()
406406

407407
if (root->db && (!cachedValue || std::get_if<placeholder_t>(&cachedValue->second))) {
408408
if (v.type() == nString)
409-
cachedValue = {root->db->setString(getKey(), v.c_str(), v.context()), string_t{v.c_str(), {}}};
409+
cachedValue = {root->db->setString(getKey(), v.string_view(), v.context()), string_t{v.string_view(), {}}};
410410
else if (v.type() == nPath) {
411411
auto path = v.path().path;
412412
cachedValue = {root->db->setString(getKey(), path.abs()), string_t{path.abs(), {}}};
@@ -541,7 +541,7 @@ std::string AttrCursor::getString()
541541
if (v.type() != nString && v.type() != nPath)
542542
root->state.error<TypeError>("'%s' is not a string but %s", getAttrPathStr(), showType(v)).debugThrow();
543543

544-
return v.type() == nString ? v.c_str() : v.path().to_string();
544+
return v.type() == nString ? std::string(v.string_view()) : v.path().to_string();
545545
}
546546

547547
string_t AttrCursor::getStringWithContext()
@@ -580,7 +580,7 @@ string_t AttrCursor::getStringWithContext()
580580
if (v.type() == nString) {
581581
NixStringContext context;
582582
copyContext(v, context);
583-
return {v.c_str(), std::move(context)};
583+
return {std::string{v.string_view()}, std::move(context)};
584584
} else if (v.type() == nPath)
585585
return {v.path().to_string(), {}};
586586
else

src/libexpr/eval.cc

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,12 +2366,15 @@ BackedStringView EvalState::coerceToString(
23662366
}
23672367

23682368
if (v.type() == nPath) {
2369-
return !canonicalizePath && !copyToStore
2370-
? // FIXME: hack to preserve path literals that end in a
2371-
// slash, as in /foo/${x}.
2372-
v.pathStr()
2373-
: copyToStore ? store->printStorePath(copyPathToStore(context, v.path()))
2374-
: std::string(v.path().path.abs());
2369+
if (!canonicalizePath && !copyToStore) {
2370+
// FIXME: hack to preserve path literals that end in a
2371+
// slash, as in /foo/${x}.
2372+
return v.pathStrView();
2373+
} else if (copyToStore) {
2374+
return store->printStorePath(copyPathToStore(context, v.path()));
2375+
} else {
2376+
return std::string{v.path().path.abs()};
2377+
}
23752378
}
23762379

23772380
if (v.type() == nAttrs) {
@@ -2624,7 +2627,7 @@ void EvalState::assertEqValues(Value & v1, Value & v2, const PosIdx pos, std::st
26242627
return;
26252628

26262629
case nString:
2627-
if (strcmp(v1.c_str(), v2.c_str()) != 0) {
2630+
if (v1.string_view() != v2.string_view()) {
26282631
error<AssertionError>(
26292632
"string '%s' is not equal to string '%s'",
26302633
ValuePrinter(*this, v1, errorPrintOptions),
@@ -2641,7 +2644,7 @@ void EvalState::assertEqValues(Value & v1, Value & v2, const PosIdx pos, std::st
26412644
ValuePrinter(*this, v2, errorPrintOptions))
26422645
.debugThrow();
26432646
}
2644-
if (strcmp(v1.pathStr(), v2.pathStr()) != 0) {
2647+
if (v1.pathStrView() != v2.pathStrView()) {
26452648
error<AssertionError>(
26462649
"path '%s' is not equal to path '%s'",
26472650
ValuePrinter(*this, v1, errorPrintOptions),
@@ -2807,12 +2810,12 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
28072810
return v1.boolean() == v2.boolean();
28082811

28092812
case nString:
2810-
return strcmp(v1.c_str(), v2.c_str()) == 0;
2813+
return v1.string_view() == v2.string_view();
28112814

28122815
case nPath:
28132816
return
28142817
// FIXME: compare accessors by their fingerprint.
2815-
v1.pathAccessor() == v2.pathAccessor() && strcmp(v1.pathStr(), v2.pathStr()) == 0;
2818+
v1.pathAccessor() == v2.pathAccessor() && v1.pathStrView() == v2.pathStrView();
28162819

28172820
case nNull:
28182821
return true;

src/libexpr/get-drvs.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
168168
for (auto elem : outTI->listView()) {
169169
if (elem->type() != nString)
170170
throw errMsg;
171-
auto out = outputs.find(elem->c_str());
171+
auto out = outputs.find(elem->string_view());
172172
if (out == outputs.end())
173173
throw errMsg;
174174
result.insert(*out);
@@ -245,7 +245,7 @@ std::string PackageInfo::queryMetaString(const std::string & name)
245245
Value * v = queryMeta(name);
246246
if (!v || v->type() != nString)
247247
return "";
248-
return v->c_str();
248+
return std::string{v->string_view()};
249249
}
250250

251251
NixInt PackageInfo::queryMetaInt(const std::string & name, NixInt def)
@@ -258,7 +258,7 @@ NixInt PackageInfo::queryMetaInt(const std::string & name, NixInt def)
258258
if (v->type() == nString) {
259259
/* Backwards compatibility with before we had support for
260260
integer meta fields. */
261-
if (auto n = string2Int<NixInt::Inner>(v->c_str()))
261+
if (auto n = string2Int<NixInt::Inner>(v->string_view()))
262262
return NixInt{*n};
263263
}
264264
return def;
@@ -274,7 +274,7 @@ NixFloat PackageInfo::queryMetaFloat(const std::string & name, NixFloat def)
274274
if (v->type() == nString) {
275275
/* Backwards compatibility with before we had support for
276276
float meta fields. */
277-
if (auto n = string2Float<NixFloat>(v->c_str()))
277+
if (auto n = string2Float<NixFloat>(v->string_view()))
278278
return *n;
279279
}
280280
return def;

src/libexpr/include/nix/expr/get-drvs.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace nix {
1515
struct PackageInfo
1616
{
1717
public:
18-
typedef std::map<std::string, std::optional<StorePath>> Outputs;
18+
typedef std::map<std::string, std::optional<StorePath>, std::less<>> Outputs;
1919

2020
private:
2121
EvalState * state;

src/libexpr/include/nix/expr/value.hh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,7 @@ public:
11091109

11101110
std::string_view string_view() const noexcept
11111111
{
1112-
return std::string_view(getStorage<StringWithContext>().c_str);
1112+
return std::string_view{getStorage<StringWithContext>().c_str};
11131113
}
11141114

11151115
const char * c_str() const noexcept
@@ -1177,6 +1177,11 @@ public:
11771177
return getStorage<Path>().path;
11781178
}
11791179

1180+
std::string_view pathStrView() const noexcept
1181+
{
1182+
return std::string_view{getStorage<Path>().path};
1183+
}
1184+
11801185
SourceAccessor * pathAccessor() const noexcept
11811186
{
11821187
return getStorage<Path>().accessor;

src/libexpr/nixexpr.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ void ExprString::show(const SymbolTable & symbols, std::ostream & str) const
4545

4646
void ExprPath::show(const SymbolTable & symbols, std::ostream & str) const
4747
{
48-
str << v.pathStr();
48+
str << v.pathStrView();
4949
}
5050

5151
void ExprVar::show(const SymbolTable & symbols, std::ostream & str) const

src/libexpr/primops.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -691,12 +691,12 @@ struct CompareValues
691691
case nFloat:
692692
return v1->fpoint() < v2->fpoint();
693693
case nString:
694-
return strcmp(v1->c_str(), v2->c_str()) < 0;
694+
return v1->string_view() < v2->string_view();
695695
case nPath:
696696
// Note: we don't take the accessor into account
697697
// since it's not obvious how to compare them in a
698698
// reproducible way.
699-
return strcmp(v1->pathStr(), v2->pathStr()) < 0;
699+
return v1->pathStrView() < v2->pathStrView();
700700
case nList:
701701
// Lexicographic comparison
702702
for (size_t i = 0;; i++) {
@@ -2930,7 +2930,7 @@ static void prim_attrNames(EvalState & state, const PosIdx pos, Value ** args, V
29302930
for (const auto & [n, i] : enumerate(*args[0]->attrs()))
29312931
list[n] = Value::toPtr(state.symbols[i.name]);
29322932

2933-
std::sort(list.begin(), list.end(), [](Value * v1, Value * v2) { return strcmp(v1->c_str(), v2->c_str()) < 0; });
2933+
std::sort(list.begin(), list.end(), [](Value * v1, Value * v2) { return v1->string_view() < v2->string_view(); });
29342934

29352935
v.mkList(list);
29362936
}

0 commit comments

Comments
 (0)