Skip to content

Commit fb677eb

Browse files
committed
Make StringWithContext::Context length-prefixed instead
Rather than having a null pointer at the end, have a `size_t` at the beginning. This is the exact same size (note that null pointer is longer than null byte) and thus takes no more space!
1 parent cb40c83 commit fb677eb

File tree

2 files changed

+19
-15
lines changed

2 files changed

+19
-15
lines changed

src/libexpr/eval.cc

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -824,12 +824,15 @@ void Value::mkString(std::string_view s)
824824
Value::StringWithContext::Context * Value::StringWithContext::Context::fromBuilder(const NixStringContext & context)
825825
{
826826
if (!context.empty()) {
827-
size_t n = 0;
828-
auto ctx = (Value::StringWithContext::Context *) allocBytes((context.size() + 1) * sizeof(char *));
829-
for (auto & i : context) {
830-
ctx->elems[n++] = makeImmutableString({i.to_string()});
827+
auto ctx = (Value::StringWithContext::Context *) allocBytes(sizeof(size_t) + context.size() * sizeof(char *));
828+
ctx->size = context.size();
829+
/* Mapping the original iterator to turn references into
830+
pointers is necessary to make sure that enumerate doesn't
831+
accidently copy the elements when it returns tuples by value.
832+
*/
833+
for (auto [n, i] : enumerate(context | std::views::transform([](const auto & r) { return &r; }))) {
834+
ctx->elems[n] = makeImmutableString({i->to_string()});
831835
}
832-
ctx->elems[n] = nullptr;
833836
return ctx;
834837
} else
835838
return nullptr;

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

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,10 @@ struct ValueBase
224224
/**
225225
* The type of the context itself.
226226
*
227-
* Currently, it is a null-terminated array of pointers to
228-
* null-terminated strings. (So far, this is the same as `argv`,
229-
* the `main` parameter, for example.) In addition, the strings
230-
* are specially formatted to represent a flattening of the
231-
* recursive sum type that is a context element.
227+
* Currently, it is length-prefixed array of pointers to
228+
* null-terminated strings. The strings are specially formatted
229+
* to represent a flattening of the recursive sum type that is a
230+
* context element.
232231
*
233232
* @See NixStringContext for an more easily understood type,
234233
* that of the "builder" for this data structure.
@@ -237,11 +236,16 @@ struct ValueBase
237236
{
238237
using Elem = const char *;
239238

239+
/**
240+
* Number of items in the array
241+
*/
242+
size_t size;
243+
240244
private:
241245
/**
242246
* must be in sorted order
243247
*/
244-
Elem elems[];
248+
Elem elems[/*size*/];
245249
public:
246250

247251
const Elem * begin() const
@@ -251,10 +255,7 @@ struct ValueBase
251255

252256
const Elem * end() const
253257
{
254-
const Elem * p = begin();
255-
while (*p)
256-
++p;
257-
return p;
258+
return &elems[size];
258259
}
259260

260261
/**

0 commit comments

Comments
 (0)