2012-07-18 21:59:03 +03:00
|
|
|
#pragma once
|
2010-04-13 15:25:42 +03:00
|
|
|
|
2021-12-20 12:29:14 +02:00
|
|
|
#include <list>
|
2010-04-13 15:25:42 +03:00
|
|
|
#include <map>
|
2021-12-20 12:29:14 +02:00
|
|
|
#include <unordered_map>
|
2010-04-13 15:25:42 +03:00
|
|
|
|
|
|
|
#include "types.hh"
|
2022-04-22 11:01:02 +03:00
|
|
|
#include "chunked-vector.hh"
|
2010-04-13 15:25:42 +03:00
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
|
|
|
/* Symbol table used by the parser and evaluator to represent and look
|
2013-10-24 17:41:04 +03:00
|
|
|
up identifiers and attributes efficiently. SymbolTable::create()
|
|
|
|
converts a string into a symbol. Symbols have the property that
|
2022-04-22 22:45:39 +03:00
|
|
|
they can be compared efficiently (using an equality test),
|
2013-10-24 17:41:04 +03:00
|
|
|
because the symbol table stores only one copy of each string. */
|
2010-04-13 15:25:42 +03:00
|
|
|
|
2022-04-22 22:45:39 +03:00
|
|
|
/* 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
|
2010-04-13 15:25:42 +03:00
|
|
|
{
|
|
|
|
friend class SymbolTable;
|
2022-04-22 22:45:39 +03:00
|
|
|
|
2022-03-05 15:40:24 +02:00
|
|
|
private:
|
2022-04-22 22:45:39 +03:00
|
|
|
const std::string * s;
|
2010-04-13 15:25:42 +03:00
|
|
|
|
2022-04-22 22:45:39 +03:00
|
|
|
explicit SymbolStr(const std::string & symbol): s(&symbol) {}
|
2013-05-16 20:08:02 +03:00
|
|
|
|
2022-04-22 22:45:39 +03:00
|
|
|
public:
|
2020-04-17 02:02:29 +03:00
|
|
|
bool operator == (std::string_view s2) const
|
|
|
|
{
|
2022-04-22 22:45:39 +03:00
|
|
|
return *s == s2;
|
2010-04-13 15:25:42 +03:00
|
|
|
}
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
operator const std::string & () const
|
|
|
|
{
|
2022-04-22 22:45:39 +03:00
|
|
|
return *s;
|
2019-12-05 20:11:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
operator const std::string_view () const
|
2013-05-16 20:08:02 +03:00
|
|
|
{
|
2022-04-22 22:45:39 +03:00
|
|
|
return *s;
|
2013-05-16 20:08:02 +03:00
|
|
|
}
|
|
|
|
|
2022-04-22 22:45:39 +03:00
|
|
|
friend std::ostream & operator <<(std::ostream & os, const SymbolStr & symbol);
|
2010-04-13 15:25:42 +03:00
|
|
|
};
|
|
|
|
|
2022-04-22 22:45:39 +03:00
|
|
|
class Symbol
|
2022-03-05 15:40:24 +02:00
|
|
|
{
|
|
|
|
friend class SymbolTable;
|
|
|
|
|
|
|
|
private:
|
|
|
|
uint32_t id;
|
|
|
|
|
2022-04-22 22:45:39 +03:00
|
|
|
explicit Symbol(uint32_t id): id(id) {}
|
2022-03-05 15:40:24 +02:00
|
|
|
|
|
|
|
public:
|
2022-04-22 22:45:39 +03:00
|
|
|
Symbol() : id(0) {}
|
2022-03-05 15:40:24 +02:00
|
|
|
|
|
|
|
explicit operator bool() const { return id > 0; }
|
|
|
|
|
2022-04-22 22:45:39 +03:00
|
|
|
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; }
|
2022-03-05 15:40:24 +02:00
|
|
|
};
|
|
|
|
|
2010-04-13 15:25:42 +03:00
|
|
|
class SymbolTable
|
|
|
|
{
|
|
|
|
private:
|
2022-04-22 22:45:39 +03:00
|
|
|
std::unordered_map<std::string_view, std::pair<const std::string *, uint32_t>> symbols;
|
|
|
|
ChunkedVector<std::string, 8192> store{16};
|
2010-04-13 15:25:42 +03:00
|
|
|
|
|
|
|
public:
|
2022-04-26 15:16:20 +03:00
|
|
|
|
2022-04-22 22:45:39 +03:00
|
|
|
Symbol create(std::string_view s)
|
2010-04-13 15:25:42 +03:00
|
|
|
{
|
2021-12-20 12:29:14 +02:00
|
|
|
// 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
|
2022-04-26 15:16:20 +03:00
|
|
|
// FIXME: make this thread-safe.
|
2021-12-20 12:29:14 +02:00
|
|
|
auto it = symbols.find(s);
|
2022-04-22 22:45:39 +03:00
|
|
|
if (it != symbols.end()) return Symbol(it->second.second + 1);
|
2021-12-20 12:29:14 +02:00
|
|
|
|
2022-04-22 22:45:39 +03:00
|
|
|
const auto & [rawSym, idx] = store.add(std::string(s));
|
2022-03-05 15:40:24 +02:00
|
|
|
symbols.emplace(rawSym, std::make_pair(&rawSym, idx));
|
2022-04-22 22:45:39 +03:00
|
|
|
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;
|
2022-03-05 15:40:24 +02:00
|
|
|
}
|
|
|
|
|
2022-04-22 22:45:39 +03:00
|
|
|
SymbolStr operator[](Symbol s) const
|
2022-03-05 15:40:24 +02:00
|
|
|
{
|
|
|
|
if (s.id == 0 || s.id > store.size())
|
|
|
|
abort();
|
2022-04-22 22:45:39 +03:00
|
|
|
return SymbolStr(store[s.id - 1]);
|
2010-04-13 15:25:42 +03:00
|
|
|
}
|
2010-04-13 17:34:11 +03:00
|
|
|
|
2018-05-02 14:56:34 +03:00
|
|
|
size_t size() const
|
2010-04-13 17:34:11 +03:00
|
|
|
{
|
2022-03-05 15:40:24 +02:00
|
|
|
return store.size();
|
2010-04-13 17:34:11 +03:00
|
|
|
}
|
2013-10-08 16:34:57 +03:00
|
|
|
|
|
|
|
size_t totalSize() const;
|
2019-04-12 00:04:13 +03:00
|
|
|
|
|
|
|
template<typename T>
|
2022-03-05 15:40:24 +02:00
|
|
|
void dump(T callback) const
|
2019-04-12 00:04:13 +03:00
|
|
|
{
|
2022-03-05 15:40:24 +02:00
|
|
|
store.forEach(callback);
|
2019-04-12 00:04:13 +03:00
|
|
|
}
|
2010-04-13 15:25:42 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|