#pragma once #include #include #include #include #include #include #include namespace example { template struct Span { using iterator = ElementType*; template Span(Container& c) : begin_(c.data()), end_(begin_ + c.size()) { } iterator begin() const { return begin_; } iterator end() const { return end_; } private: iterator begin_; iterator end_; }; template class IdMap { public: using iterator = typename std::vector::iterator; using const_iterator = typename std::vector::const_iterator; // Iterators const_iterator begin() const { return elements_.begin(); } const_iterator end() const { return elements_.end(); } // Element access Span elements() const { return elements_; } // Capacity bool empty() const { return sorted_ids_.empty(); } size_t size() const { return sorted_ids_.size(); } // Modifiers std::pair insert(int id, const ElementType& element); std::pair insert(int id, ElementType&& element); size_t erase(int id); void clear(); // Lookup iterator find(int id); const_iterator find(int id) const; bool contains(int id) const; private: std::vector elements_; std::vector sorted_ids_; }; template std::pair::iterator, bool> IdMap::insert( const int id, const ElementType& element) { auto lower_bound = std::lower_bound(sorted_ids_.begin(), sorted_ids_.end(), id); if (lower_bound != sorted_ids_.end() && id == *lower_bound) { return std::make_pair( std::next(elements_.begin(), std::distance(sorted_ids_.begin(), lower_bound)), false); } auto insert_element_at = std::next(elements_.begin(), std::distance(sorted_ids_.begin(), lower_bound)); sorted_ids_.insert(lower_bound, id); return std::make_pair(elements_.insert(insert_element_at, element), true); } template std::pair::iterator, bool> IdMap::insert( const int id, ElementType&& element) { auto lower_bound = std::lower_bound(sorted_ids_.begin(), sorted_ids_.end(), id); if (lower_bound != sorted_ids_.end() && id == *lower_bound) { return std::make_pair( std::next(elements_.begin(), std::distance(sorted_ids_.begin(), lower_bound)), false); } auto insert_element_at = std::next(elements_.begin(), std::distance(sorted_ids_.begin(), lower_bound)); sorted_ids_.insert(lower_bound, id); return std::make_pair(elements_.insert(insert_element_at, std::move(element)), true); } template size_t IdMap::erase(const int id) { auto lower_bound = std::lower_bound(sorted_ids_.begin(), sorted_ids_.end(), id); if (lower_bound == sorted_ids_.end() || id != *lower_bound) { return 0ull; } auto erase_element_at = std::next(elements_.begin(), std::distance(sorted_ids_.begin(), lower_bound)); sorted_ids_.erase(lower_bound); elements_.erase(erase_element_at); return 1ull; } template void IdMap::clear() { elements_.clear(); sorted_ids_.clear(); } template typename IdMap::iterator IdMap::find(const int id) { const auto lower_bound = std::lower_bound(sorted_ids_.cbegin(), sorted_ids_.cend(), id); return (lower_bound == sorted_ids_.cend() || *lower_bound != id) ? elements_.end() : std::next(elements_.begin(), std::distance(sorted_ids_.cbegin(), lower_bound)); } template typename IdMap::const_iterator IdMap::find(const int id) const { const auto lower_bound = std::lower_bound(sorted_ids_.cbegin(), sorted_ids_.cend(), id); return (lower_bound == sorted_ids_.cend() || *lower_bound != id) ? elements_.cend() : std::next(elements_.cbegin(), std::distance(sorted_ids_.cbegin(), lower_bound)); } template bool IdMap::contains(const int id) const { const auto lower_bound = std::lower_bound(sorted_ids_.cbegin(), sorted_ids_.cend(), id); if (lower_bound == sorted_ids_.cend()) { return false; } return *lower_bound == id; } // a very simple directional graph template class Graph { public: Graph() : current_id_(0), nodes_(), edges_from_node_(), node_neighbors_(), edges_() {} struct Edge { int id; int from, to; Edge() = default; Edge(const int id, const int f, const int t) : id(id), from(f), to(t) {} inline int opposite(const int n) const { return n == from ? to : from; } inline bool contains(const int n) const { return n == from || n == to; } }; // Element access NodeType& node(int node_id); const NodeType& node(int node_id) const; Span neighbors(int node_id) const; Span edges() const; // Capacity size_t num_edges_from_node(int node_id) const; // Modifiers int insert_node(const NodeType& node); void erase_node(int node_id); int insert_edge(int from, int to); void erase_edge(int edge_id); private: int current_id_; // These contains map to the node id IdMap nodes_; IdMap edges_from_node_; IdMap> node_neighbors_; // This container maps to the edge id IdMap edges_; }; template NodeType& Graph::node(const int id) { return const_cast(static_cast(this)->node(id)); } template const NodeType& Graph::node(const int id) const { const auto iter = nodes_.find(id); assert(iter != nodes_.end()); return *iter; } template Span Graph::neighbors(int node_id) const { const auto iter = node_neighbors_.find(node_id); assert(iter != node_neighbors_.end()); return *iter; } template Span::Edge> Graph::edges() const { return edges_.elements(); } template size_t Graph::num_edges_from_node(const int id) const { auto iter = edges_from_node_.find(id); assert(iter != edges_from_node_.end()); return *iter; } template int Graph::insert_node(const NodeType& node) { const int id = current_id_++; assert(!nodes_.contains(id)); nodes_.insert(id, node); edges_from_node_.insert(id, 0); node_neighbors_.insert(id, std::vector()); return id; } template void Graph::erase_node(const int id) { // first, remove any potential dangling edges { static std::vector edges_to_erase; for (const Edge& edge : edges_.elements()) { if (edge.contains(id)) { edges_to_erase.push_back(edge.id); } } for (const int edge_id : edges_to_erase) { erase_edge(edge_id); } edges_to_erase.clear(); } nodes_.erase(id); edges_from_node_.erase(id); node_neighbors_.erase(id); } template int Graph::insert_edge(const int from, const int to) { const int id = current_id_++; assert(!edges_.contains(id)); assert(nodes_.contains(from)); assert(nodes_.contains(to)); edges_.insert(id, Edge(id, from, to)); // update neighbor count assert(edges_from_node_.contains(from)); *edges_from_node_.find(from) += 1; // update neighbor list assert(node_neighbors_.contains(from)); node_neighbors_.find(from)->push_back(to); return id; } template void Graph::erase_edge(const int edge_id) { // This is a bit lazy, we find the pointer here, but we refind it when we erase the edge based // on id key. assert(edges_.contains(edge_id)); const Edge& edge = *edges_.find(edge_id); // update neighbor count assert(edges_from_node_.contains(edge.from)); int& edge_count = *edges_from_node_.find(edge.from); assert(edge_count > 0); edge_count -= 1; // update neighbor list { assert(node_neighbors_.contains(edge.from)); auto neighbors = node_neighbors_.find(edge.from); auto iter = std::find(neighbors->begin(), neighbors->end(), edge.to); assert(iter != neighbors->end()); neighbors->erase(iter); } edges_.erase(edge_id); } template void dfs_traverse(const Graph& graph, const int start_node, Visitor visitor) { std::stack stack; stack.push(start_node); while (!stack.empty()) { const int current_node = stack.top(); stack.pop(); visitor(current_node); for (const int neighbor : graph.neighbors(current_node)) { stack.push(neighbor); } } } } // namespace example