aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/symbol-table.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr/symbol-table.hh')
-rw-r--r--src/libexpr/symbol-table.hh60
1 files changed, 36 insertions, 24 deletions
diff --git a/src/libexpr/symbol-table.hh b/src/libexpr/symbol-table.hh
index b6ad60f68..63fb25d73 100644
--- a/src/libexpr/symbol-table.hh
+++ b/src/libexpr/symbol-table.hh
@@ -12,82 +12,94 @@ namespace nix {
/* Symbol table used by the parser and evaluator to represent and look
up identifiers and attributes efficiently. SymbolTable::create()
converts a string into a symbol. Symbols have the property that
- they can be compared efficiently (using a pointer equality test),
+ they can be compared efficiently (using an equality test),
because the symbol table stores only one copy of each string. */
-class Symbol
+/* This class mainly exists to give us an operator<< for ostreams. We could also
+ return plain strings from SymbolTable, but then we'd have to wrap every
+ instance of a symbol that is fmt()ed, which is inconvenient and error-prone. */
+class SymbolStr
{
friend class SymbolTable;
+
private:
- std::string s;
+ const std::string * s;
-public:
- Symbol(std::string_view s) : s(s) { }
+ explicit SymbolStr(const std::string & symbol): s(&symbol) {}
- // FIXME: remove
+public:
bool operator == (std::string_view s2) const
{
- return s == s2;
+ return *s == s2;
}
operator const std::string & () const
{
- return s;
+ return *s;
}
operator const std::string_view () const
{
- return s;
+ return *s;
}
- friend std::ostream & operator << (std::ostream & str, const Symbol & sym);
+ friend std::ostream & operator <<(std::ostream & os, const SymbolStr & symbol);
};
-class SymbolIdx
+class Symbol
{
friend class SymbolTable;
private:
uint32_t id;
- explicit SymbolIdx(uint32_t id): id(id) {}
+ explicit Symbol(uint32_t id): id(id) {}
public:
- SymbolIdx() : id(0) {}
+ Symbol() : id(0) {}
explicit operator bool() const { return id > 0; }
- bool operator<(const SymbolIdx other) const { return id < other.id; }
- bool operator==(const SymbolIdx other) const { return id == other.id; }
- bool operator!=(const SymbolIdx other) const { return id != other.id; }
+ bool operator<(const Symbol other) const { return id < other.id; }
+ bool operator==(const Symbol other) const { return id == other.id; }
+ bool operator!=(const Symbol other) const { return id != other.id; }
};
class SymbolTable
{
private:
- std::unordered_map<std::string_view, std::pair<const Symbol *, uint32_t>> symbols;
- ChunkedVector<Symbol, 8192> store{16};
+ std::unordered_map<std::string_view, std::pair<const std::string *, uint32_t>> symbols;
+ ChunkedVector<std::string, 8192> store{16};
public:
- SymbolIdx create(std::string_view s)
+ Symbol create(std::string_view s)
{
// Most symbols are looked up more than once, so we trade off insertion performance
// for lookup performance.
// TODO: could probably be done more efficiently with transparent Hash and Equals
// on the original implementation using unordered_set
auto it = symbols.find(s);
- if (it != symbols.end()) return SymbolIdx(it->second.second + 1);
+ if (it != symbols.end()) return Symbol(it->second.second + 1);
- const auto & [rawSym, idx] = store.add(s);
+ const auto & [rawSym, idx] = store.add(std::string(s));
symbols.emplace(rawSym, std::make_pair(&rawSym, idx));
- return SymbolIdx(idx + 1);
+ return Symbol(idx + 1);
+ }
+
+ std::vector<SymbolStr> resolve(const std::vector<Symbol> & symbols) const
+ {
+ std::vector<SymbolStr> result;
+ result.reserve(symbols.size());
+ for (auto sym : symbols)
+ result.push_back((*this)[sym]);
+ return result;
}
- const Symbol & operator[](SymbolIdx s) const
+ SymbolStr operator[](Symbol s) const
{
if (s.id == 0 || s.id > store.size())
abort();
- return store[s.id - 1];
+ return SymbolStr(store[s.id - 1]);
}
size_t size() const