refactor(3p/nix/libexpr): Use absl::btree_map for AttrSets

This is the first step towards replacing the implementation of
attribute sets with an absl::btree_map.

Currently many access are done using array offsets and pointer
arithmetic, so this change is currently causing Nix to fail in various
ways.
This commit is contained in:
Vincent Ambo 2020-05-21 19:20:24 +01:00
parent 1bb9cd7749
commit 28e347effe
6 changed files with 95 additions and 78 deletions

View file

@ -1,12 +1,13 @@
// This file implements the underlying structure of Nix attribute sets.
#pragma once
#include <algorithm>
#include <absl/container/btree_map.h>
#include "nixexpr.hh"
#include "symbol-table.hh"
#include "types.hh" // TODO(tazjin): audit this include
namespace nix {
namespace nix { // TODO(tazjin): ::expr
class EvalState;
struct Value;
@ -22,65 +23,49 @@ struct Attr {
bool operator<(const Attr& a) const { return name < a.name; }
};
/* Bindings contains all the attributes of an attribute set. It is defined
by its size and its capacity, the capacity being the number of Attr
elements allocated after this structure, while the size corresponds to
the number of elements already inserted in this structure. */
// TODO: remove this, it only exists briefly while I get rid of the
// current Attr struct
inline bool operator==(const Attr& lhs, const Attr& rhs) {
return lhs.name == rhs.name;
}
class Bindings {
public:
typedef uint32_t size_t;
typedef Attr* iterator; // TODO: type, and also 'using'?
// Return the number of contained elements.
size_t size();
// Is this attribute set empty?
bool empty();
// TODO(tazjin): rename
// TODO(tazjin): does this need to copy?
void push_back(const Attr& attr);
// Look up a specific element of the attribute set.
iterator find(const Symbol& name);
// TODO
iterator begin();
iterator end();
// ???
[[deprecated]] void sort();
// ???
[[deprecated]] size_t capacity();
// oh no
// Attr& operator[](size_t pos); // { return attrs[pos]; }
// TODO: can callers just iterate?
[[deprecated]] std::vector<const Attr*> lexicographicOrder();
// oh no
friend class EvalState;
private:
size_t size_, capacity_;
Attr attrs[0];
Bindings(size_t capacity) : size_(0), capacity_(capacity) {}
Bindings(const Bindings& bindings) = delete;
public:
size_t size() const { return size_; }
bool empty() const { return !size_; }
typedef Attr* iterator;
void push_back(const Attr& attr) {
assert(size_ < capacity_);
attrs[size_++] = attr;
}
iterator find(const Symbol& name) {
Attr key(name, 0);
iterator i = std::lower_bound(begin(), end(), key);
if (i != end() && i->name == name) {
return i;
}
return end();
}
iterator begin() { return &attrs[0]; }
iterator end() { return &attrs[size_]; }
Attr& operator[](size_t pos) { return attrs[pos]; }
void sort();
size_t capacity() { return capacity_; }
/* Returns the attributes in lexicographically sorted order. */
std::vector<const Attr*> lexicographicOrder() const {
std::vector<const Attr*> res;
res.reserve(size_);
for (size_t n = 0; n < size_; n++) {
res.emplace_back(&attrs[n]);
}
std::sort(res.begin(), res.end(), [](const Attr* a, const Attr* b) {
return (const std::string&)a->name < (const std::string&)b->name;
});
return res;
}
friend class EvalState;
absl::btree_map<Symbol, Attr> attributes_;
};
} // namespace nix