diff --git a/lix/libexpr/nixexpr.cc b/lix/libexpr/nixexpr.cc index 9b37de980..4f894c7dd 100644 --- a/lix/libexpr/nixexpr.cc +++ b/lix/libexpr/nixexpr.cc @@ -19,6 +19,12 @@ std::ostream & operator <<(std::ostream & str, const SymbolStr & symbol) return printIdentifier(str, s); } +std::ostream & operator<<(std::ostream & str, const InternedSymbol & symbol) +{ + str << SymbolStr(symbol); + return str; +} + AttrName::AttrName(PosIdx pos, Symbol s) : pos(pos), symbol(s) { } diff --git a/lix/libexpr/primops.cc b/lix/libexpr/primops.cc index 6c7410b6a..3ed9c68c9 100644 --- a/lix/libexpr/primops.cc +++ b/lix/libexpr/primops.cc @@ -810,7 +810,7 @@ drvName, Bindings * attrs, Value & v) for (auto & i : attrs->lexicographicOrder(state.ctx.symbols)) { if (i->name == state.ctx.s.ignoreNulls) continue; - const std::string & key = state.ctx.symbols[i->name]; + auto & key = state.ctx.symbols[i->name]; vomit("processing attribute '%1%'", key); auto handleHashMode = [&](const std::string_view s, NeverAsync = {}) { @@ -1539,7 +1539,7 @@ static void prim_path(EvalState & state, Value * * args, Value & v) state.forceAttrs(*args[0], noPos, "while evaluating the argument passed to 'builtins.path'"); for (auto & attr : *args[0]->attrs) { - auto n = state.ctx.symbols[attr.name]; + auto & n = state.ctx.symbols[attr.name]; if (n == "path") path.emplace(state.coerceToPath(attr.pos, *attr.value, context, "while evaluating the 'path' attribute passed to 'builtins.path'")); else if (attr.name == state.ctx.s.name) diff --git a/lix/libexpr/symbol-table.hh b/lix/libexpr/symbol-table.hh index 156fd38ae..93c38662e 100644 --- a/lix/libexpr/symbol-table.hh +++ b/lix/libexpr/symbol-table.hh @@ -6,6 +6,8 @@ #include "lix/libutil/types.hh" #include "lix/libutil/chunked-vector.hh" +#include "lix/libexpr/value.hh" + namespace nix { /** @@ -16,6 +18,7 @@ namespace nix { class SymbolStr { friend class SymbolTable; + friend class InternedSymbol; private: const std::string * s; @@ -41,6 +44,59 @@ public: friend std::ostream & operator <<(std::ostream & os, const SymbolStr & symbol); }; +class InternedSymbol +{ +private: + /* + * The type that actually stores the string contained inside of the Value. + */ + std::string contents; + + /* + * A value containing a string that can be immediately passed to the evaluator. + */ + Value underlyingValue; + +public: + explicit InternedSymbol(std::string_view s) + : contents(s) + , underlyingValue(NewValueAs::string, contents.c_str(), nullptr) + { + } + + InternedSymbol(InternedSymbol &&) = default; + InternedSymbol & operator=(InternedSymbol &&) = default; + + KJ_DISALLOW_COPY(InternedSymbol); + + operator SymbolStr() const + { + return SymbolStr(contents); + } + + bool operator==(std::string_view s2) const + { + return contents == s2; + } + + operator const std::string &() const + { + return contents; + } + + operator std::string_view() const + { + return contents; + } + + const Value * toValuePtr() const + { + return &underlyingValue; + } + + friend std::ostream & operator<<(std::ostream & os, const InternedSymbol & symbol); +}; + /** * Symbols have the property that they can be compared efficiently * (using an equality test), because the symbol table stores only one @@ -77,7 +133,7 @@ private: * ChunkedVector references are never invalidated. */ std::unordered_map symbols; - ChunkedVector store{16}; + ChunkedVector store{16}; public: @@ -101,11 +157,11 @@ public: return Symbol(idx + 1); } - SymbolStr operator[](Symbol s) const + const InternedSymbol & operator[](Symbol s) const { if (s.id == 0 || s.id > store.size()) abort(); - return SymbolStr(store[s.id - 1]); + return store[s.id - 1]; } size_t size() const