19#include <unordered_set>
22#include <unordered_map>
47 std::unordered_set<std::size_t> incoming_edges;
48 std::unordered_set<std::size_t> outgoing_edges;
62 template <Hashable V, Hashable E>
65 std::unordered_map<std::size_t, V> vertex_index{};
66 std::unordered_map<std::size_t, Edge<E>> edge_index{};
67 std::unordered_map<std::size_t, EdgeSet> adjacency_list{};
144 return vertex_index | std::views::values;
152 return edge_index | std::views::values;
157 std::size_t vertex_id {std::hash<V>{}(v)};
158 if (!vertex_index.contains(vertex_id)) {
159 vertex_index.emplace(vertex_id, v);
160 adjacency_list.emplace(vertex_id, EdgeSet{});
166 if (!vertex_index.contains(vertex_id)) {
169 if (adjacency_list.contains(vertex_id) && adjacency_list[vertex_id].incoming_edges.empty() && adjacency_list[vertex_id].outgoing_edges.empty()) {
170 adjacency_list.erase(vertex_id);
171 vertex_index.erase(vertex_id);
178 if (!vertex_index.contains(from_id) || !vertex_index.contains(to_id)) {
182 if (std::size_t edge_id {std::hash<E>{}(e)}; edge_index.contains(edge_id)) {
183 if (
Edge edge_info = edge_index.at(edge_id); edge_info.
from_id != from_id || edge_info.to_id != to_id) {
188 edge_index.emplace(edge_id,
Edge<E>{from_id, to_id, e});
189 adjacency_list[from_id].outgoing_edges.insert(edge_id);
190 adjacency_list[to_id].incoming_edges.insert(edge_id);
196 if (
auto it = edge_index.find(edge_id); it != edge_index.end()) {
197 const auto& [from_id, to_id, _] = it->second;
198 edge_index.erase(it);
199 adjacency_list[from_id].outgoing_edges.erase(edge_id);
200 adjacency_list[to_id].incoming_edges.erase(edge_id);
207 if (vertex_index.contains(
id)) {
214 if (edge_index.contains(
id)) {
221 if (!adjacency_list.contains(vertex_id)) {
224 auto children = adjacency_list.at(vertex_id).outgoing_edges
225 | std::views::transform([
this](
const auto& edge_id) {
226 return edge_index.at(edge_id).to_id;
228 std::unordered_set<std::size_t> children_set(children.begin(), children.end());
233 if (!adjacency_list.contains(vertex_id)) {
236 auto parents = adjacency_list.at(vertex_id).incoming_edges
237 | std::views::transform([
this](
const auto& edge_id) {
238 return edge_index.at(edge_id).from_id;
240 std::unordered_set<std::size_t> parent_set(parents.begin(), parents.end());
245 if (!adjacency_list.contains(vertex_id)) {
249 auto children = adjacency_list.at(vertex_id).outgoing_edges
250 | std::views::transform([
this](
const auto& edge_id) {
251 return edge_index.at(edge_id).to_id;
254 auto parents = adjacency_list.at(vertex_id).incoming_edges
255 | std::views::transform([
this](
const auto& edge_id) {
256 return edge_index.at(edge_id).from_id;
259 std::unordered_set<std::size_t> neighbours {children.begin(), children.end()};
260 neighbours.insert(parents.begin(), parents.end());
266 if (!adjacency_list.contains(vertex_id)) {
269 auto children {adjacency_list.at(vertex_id).outgoing_edges};
274 if (!adjacency_list.contains(vertex_id)) {
277 auto children {adjacency_list.at(vertex_id).incoming_edges};
Directed graph with hashed vertex and edge ids.
Result< std::unordered_set< std::size_t >, ErrorType > get_parents(std::size_t vertex_id) const
Get adjacent parents (incoming neighbors).
std::ranges::forward_range auto get_vertices() const &
View of all vertex payloads.
Result< std::unordered_set< std::size_t >, ErrorType > get_outgoing_edges(std::size_t vertex_id) const
Get outgoing edge ids for a vertex.
Result< V, ErrorType > get_vertex(std::size_t id) const
Fetch a vertex payload by id.
Result< std::size_t, ErrorType > delete_vertex(std::size_t vertex_id)
Delete a vertex if it has no incident edges.
Result< Edge< E >, ErrorType > get_edge(std::size_t id) const
Fetch an edge record by id.
Result< std::size_t, ErrorType > add_vertex(const V &v)
Add a vertex to the graph.
Result< std::size_t, ErrorType > delete_edge(std::size_t edge_id)
Delete an edge by id.
Result< std::size_t, ErrorType > add_edge(std::size_t from_id, std::size_t to_id, const E &e)
Add a directed edge between two vertices.
Result< std::unordered_set< std::size_t >, ErrorType > get_incoming_edges(std::size_t vertex_id) const
Get incoming edge ids for a vertex.
std::ranges::forward_range auto get_edges() const &
View of all edge records.
Result< std::unordered_set< std::size_t >, ErrorType > get_neighbours(std::size_t vertex_id) const
Get all adjacent neighbors (incoming or outgoing).
Result< std::unordered_set< std::size_t >, ErrorType > get_children(std::size_t vertex_id) const
Get adjacent children (outgoing neighbors).
Result wrapper for success or error values.
static Result error(const ERROR &e)
Construct an error result from a const reference.
static Result success(const SUCCESS &s)
Construct a success result from a const reference.
Common concepts and utilities.
ErrorType
Error codes returned by graph operations.
@ VERTEX_NOT_FREE
The vertex cannot be removed because it still has incident edges.
@ ABSENT_VERTEX
The referenced vertex ID does not exist in the graph.
@ EDGE_ALREADY_EXISTS
An edge between the two vertices already exists.
@ ABSENT_EDGE
The referenced edge ID does not exist in the graph.
Core result and error types.
Edge record for a directed graph.
bool operator==(const Edge &other) const