Changes in preparation of making SemistaticGraph non-copyable.
diff --git a/include/fruit/impl/data_structures/semistatic_graph.defn.h b/include/fruit/impl/data_structures/semistatic_graph.defn.h
index 3f83c23..6dade64 100644
--- a/include/fruit/impl/data_structures/semistatic_graph.defn.h
+++ b/include/fruit/impl/data_structures/semistatic_graph.defn.h
@@ -53,6 +53,36 @@
}
template <typename NodeId, typename Node>
+inline SemistaticGraph<NodeId, Node>::const_node_iterator::const_node_iterator(
+ typename std::vector<NodeData>::const_iterator itr)
+ : itr(itr) {
+}
+
+template <typename NodeId, typename Node>
+inline const Node& SemistaticGraph<NodeId, Node>::const_node_iterator::getNode() {
+ assert(itr->edgesBeginOffset != invalidEdgesBeginOffset);
+ return itr->node;
+}
+
+template <typename NodeId, typename Node>
+inline bool SemistaticGraph<NodeId, Node>::const_node_iterator::isTerminal() {
+ assert(itr->edgesBeginOffset != invalidEdgesBeginOffset);
+ return itr->edgesBeginOffset == 0;
+}
+
+template <typename NodeId, typename Node>
+inline void SemistaticGraph<NodeId, Node>::const_node_iterator::setTerminal() {
+ assert(itr->edgesBeginOffset != invalidEdgesBeginOffset);
+ itr->edgesBeginOffset = 0;
+}
+
+template <typename NodeId, typename Node>
+inline bool SemistaticGraph<NodeId, Node>::const_node_iterator::operator==(const const_node_iterator& other) const {
+ return itr == other.itr;
+}
+
+
+template <typename NodeId, typename Node>
inline typename SemistaticGraph<NodeId, Node>::edge_iterator SemistaticGraph<NodeId, Node>::node_iterator::neighborsBegin(
SemistaticGraph<NodeId, Node>& graph) {
return edge_iterator{graph.edgesStorage.begin() + itr->edgesBeginOffset};
@@ -87,11 +117,30 @@
}
template <typename NodeId, typename Node>
+inline typename SemistaticGraph<NodeId, Node>::const_node_iterator SemistaticGraph<NodeId, Node>::end() const {
+ return const_node_iterator{nodes.end()};
+}
+
+template <typename NodeId, typename Node>
inline typename SemistaticGraph<NodeId, Node>::node_iterator SemistaticGraph<NodeId, Node>::at(NodeId nodeId) {
return node_iterator{nodes.begin() + nodeIndexMap.at(nodeId)};
}
template <typename NodeId, typename Node>
+inline typename SemistaticGraph<NodeId, Node>::const_node_iterator SemistaticGraph<NodeId, Node>::find(NodeId nodeId) const {
+ const std::size_t* nodeIndexPtr = nodeIndexMap.find(nodeId);
+ if (nodeIndexPtr == nullptr) {
+ return const_node_iterator{nodes.end()};
+ } else {
+ auto itr = nodes.begin() + *nodeIndexPtr;
+ if (itr->edgesBeginOffset == invalidEdgesBeginOffset) {
+ return const_node_iterator{nodes.end()};
+ }
+ return const_node_iterator{itr};
+ }
+}
+
+template <typename NodeId, typename Node>
inline typename SemistaticGraph<NodeId, Node>::node_iterator SemistaticGraph<NodeId, Node>::find(NodeId nodeId) {
std::size_t* nodeIndexPtr = nodeIndexMap.find(nodeId);
if (nodeIndexPtr == nullptr) {
diff --git a/include/fruit/impl/data_structures/semistatic_graph.h b/include/fruit/impl/data_structures/semistatic_graph.h
index d8fa367..b27316e 100644
--- a/include/fruit/impl/data_structures/semistatic_graph.h
+++ b/include/fruit/impl/data_structures/semistatic_graph.h
@@ -93,6 +93,29 @@
bool operator==(const node_iterator&) const;
};
+ class const_node_iterator {
+ private:
+ typename std::vector<NodeData>::const_iterator itr;
+
+ friend class SemistaticGraph<NodeId, Node>;
+
+ const_node_iterator(typename std::vector<NodeData>::const_iterator itr);
+
+ public:
+ const Node& getNode();
+
+ bool isTerminal();
+
+ // Turns the node into a terminal node, also removing all the deps.
+ void setTerminal();
+
+ // Assumes !isTerminal().
+ // neighborsEnd() is NOT provided/stored for efficiency, the client code is expected to know the number of neighbors.
+ edge_iterator neighborsBegin(SemistaticGraph<NodeId, Node>& graph);
+
+ bool operator==(const const_node_iterator&) const;
+ };
+
class edge_iterator {
private:
// Iterator on edgesStorage.
@@ -126,13 +149,14 @@
template <typename NodeIter>
SemistaticGraph(NodeIter first, NodeIter last);
- SemistaticGraph(const SemistaticGraph&) = default;
SemistaticGraph(SemistaticGraph&&) = default;
+ SemistaticGraph(const SemistaticGraph&) = default;
SemistaticGraph& operator=(const SemistaticGraph&) = default;
SemistaticGraph& operator=(SemistaticGraph&&) = default;
node_iterator end();
+ const_node_iterator end() const;
// Precondition: `nodeId' must exist in the graph.
// Unlike std::map::at(), this yields undefined behavior if the precondition isn't satisfied (instead of throwing).
@@ -141,6 +165,7 @@
// Prefer using at() when possible, this is slightly slower.
// Returns end() if the node ID was not found.
node_iterator find(NodeId nodeId);
+ const_node_iterator find(NodeId nodeId) const;
// Sets nodeId as a non-terminal node with outgoing edges [edgesBegin, edgesEnd).
// If the node already exists, combine(oldNode, newNode) is called and the result (also of type Node) is used as the node value.
diff --git a/include/fruit/impl/data_structures/semistatic_map.h b/include/fruit/impl/data_structures/semistatic_map.h
index a04cf7d..05c1e12 100644
--- a/include/fruit/impl/data_structures/semistatic_map.h
+++ b/include/fruit/impl/data_structures/semistatic_map.h
@@ -92,6 +92,7 @@
// Prefer using at() when possible, this is slightly slower.
// Returns nullptr if the key was not found.
+ const Value* find(Key key) const;
Value* find(Key key);
// Inserts (key, value). If `key' already exists, inserts (key, combine(oldValue, (*this)[key])) instead.
diff --git a/include/fruit/impl/data_structures/semistatic_map.templates.h b/include/fruit/impl/data_structures/semistatic_map.templates.h
index 9b1f33c..22ef897 100644
--- a/include/fruit/impl/data_structures/semistatic_map.templates.h
+++ b/include/fruit/impl/data_structures/semistatic_map.templates.h
@@ -136,6 +136,12 @@
template <typename Key, typename Value>
Value* SemistaticMap<Key, Value>::find(Key key) {
+ const SemistaticMap<Key, Value>* cthis = this;
+ return const_cast<Value*>(cthis->find(key));
+}
+
+template <typename Key, typename Value>
+const Value* SemistaticMap<Key, Value>::find(Key key) const {
Unsigned h = hash(key);
Unsigned first_candidate_index = lookup_table[h];
Unsigned last_candidate_index = values.size();
diff --git a/src/injector_storage.cpp b/src/injector_storage.cpp
index df2801f..c967c9e 100644
--- a/src/injector_storage.cpp
+++ b/src/injector_storage.cpp
@@ -117,8 +117,7 @@
InjectorStorage::InjectorStorage(const NormalizedComponentStorage& normalizedComponent,
ComponentStorage&& component)
- : typeRegistry(normalizedComponent.typeRegistry),
- typeRegistryForMultibindings(normalizedComponent.typeRegistryForMultibindings) {
+ : typeRegistryForMultibindings(normalizedComponent.typeRegistryForMultibindings) {
std::size_t total_size = normalizedComponent.total_size;
@@ -130,9 +129,9 @@
// Step 2: Filter out already-present bindings, and check for inconsistent bindings between `normalizedComponent' and
// `component'.
auto itr = std::remove_if(component.typeRegistry.begin(), component.typeRegistry.end(),
- [this](const std::pair<TypeId, BindingData>& p) {
- auto node_itr = typeRegistry.find(p.first);
- if (node_itr == typeRegistry.end()) {
+ [&normalizedComponent](const std::pair<TypeId, BindingData>& p) {
+ auto node_itr = normalizedComponent.typeRegistry.find(p.first);
+ if (node_itr == normalizedComponent.typeRegistry.end()) {
// Not bound yet, keep the new binding.
return false;
}
@@ -145,6 +144,8 @@
});
component.typeRegistry.erase(itr, component.typeRegistry.end());
+ typeRegistry = Graph(normalizedComponent.typeRegistry);
+
// Step 3: Add the new bindings.
for (auto& p : component.typeRegistry) {
TypeId typeId = p.first;
@@ -162,10 +163,14 @@
typeRegistry.setNode(typeId, NormalizedBindingData{b.getCreate()},
bindingDeps->deps, bindingDeps->deps + bindingDeps->num_deps, combine);
}
- total_size += maximumRequiredSpace(typeId);
+ }
+
+ // Step 4: Update total_size taking into account the new bindings.
+ for (auto& p : component.typeRegistry) {
+ total_size += maximumRequiredSpace(p.first);
}
- // Step 4: Add multibindings.
+ // Step 5: Add multibindings.
addMultibindings(typeRegistryForMultibindings, total_size, std::move(component.typeRegistryForMultibindings));
// The +1 is because we waste the first byte (singletonStorageLastUsed points to the beginning of storage).