9namespace fishnet::graph::__impl {
16template<Edge E, AdjacencyContainer<
typename E::node_type> AdjContainer>
19 using node_type =
typename AdjContainer::node_type;
21 using adj_container_type = AdjContainer;
28 BaseGraph()
requires std::is_default_constructible_v<AdjContainer>: adj(){};
30 BaseGraph(AdjContainer && adjContainer): adj(
std::move(adjContainer)){}
32 BaseGraph(BaseGraph && other):adj(
std::move(other.adj)){}
34 BaseGraph(
const BaseGraph & other)
requires std::is_copy_constructible_v<AdjContainer>
37 BaseGraph & operator=(BaseGraph && other)
noexcept{
38 this->adj = std::move(other.adj);
42 BaseGraph & operator=(
const BaseGraph & other)
requires std::is_copy_assignable_v<AdjContainer> {
43 this->adj = other.adj;
47 BaseGraph(util::forward_range_of<N>
auto && nodes){
48 addNodes(std::forward<
decltype(nodes)>(nodes));
51 bool addNode(
const N & node){
52 return adj.addNode(node);
55 bool addNode(N && node){
56 return adj.addNode(node);
59 template<
typename... Args>
60 bool addNode(
const N & node, Args... args){
61 bool hasChanged = addNode(node);
62 return hasChanged && addNode(args...);
65 template<
typename... Args>
66 bool addNode(N && node, Args... args){
67 bool hasChanged = addNode(std::move(node));
68 return hasChanged && addNode(args...);
71 bool addNodes(util::forward_range_of<N>
auto && nodes){
72 return adj.addNodes(std::forward<
decltype(nodes)>(nodes));
75 bool containsNode(
const N & node)
const noexcept {
76 return adj.contains(node);
79 void removeNode(
const N & node) {
83 bool addEdge(
const N & from,
const N & to){
84 if (not containsEdge(from,to)) {
85 adj.addAdjacency(from,to);
86 if constexpr(not E::isDirected()){
87 adj.addAdjacency(to,from);
94 bool addEdge(N && from, N && to){
95 if (not containsEdge(from,to)){
96 adj.addAdjacency(from,to);
97 if constexpr(not E::isDirected()){
98 adj.addAdjacency(to,from);
105 void addEdges(util::forward_range_of<std::pair<N,N>>
auto && edges){
106 if constexpr(not E::isDirected()){
107 std::vector<std::pair<N,N>> reversed;
108 std::ranges::transform(edges,std::back_inserter(reversed),[](
auto & pair){
return std::pair(pair.second,pair.first);});
109 adj.addAdjacencies(std::move(reversed));
111 adj.addAdjacencies(edges);
114 void addEdges(util::forward_range_of<E>
auto && edges) {
115 std::vector<std::pair<N,N>> pairs;
116 std::ranges::for_each(edges,[&pairs](
const auto & e){pairs.emplace_back(e.getFrom(),e.getTo());});
120 bool addEdge(
const E & edge) {
121 N from = edge.getFrom();
123 return addEdge(from,to);
126 bool containsEdge(
const N & from,
const N & to)
const noexcept {
127 if constexpr(E::isDirected())
128 return adj.hasAdjacency(from,to);
130 return adj.hasAdjacency(from,to) && adj.hasAdjacency(to,from);
133 bool containsEdge(
const E & edge)
const noexcept {
134 return containsEdge(edge.getFrom(),edge.getTo());
137 void removeEdge(
const N & from,
const N & to){
138 adj.removeAdjacency(from,to);
139 if constexpr(not E::isDirected()){
140 adj.removeAdjacency(to,from);
144 void removeEdge(
const E & edge){
145 removeEdge(edge.getFrom(),edge.getTo());
148 inline E makeEdge(
const N & from,
const N & to)
const {
152 auto getNodes() const noexcept {
153 return std::views::all(adj.nodes());
156 auto getEdges()
const {
157 std::unordered_set<E> edgeSet;
158 for(
const auto & [from,to]: adj.getAdjacencyPairs()){
159 edgeSet.emplace(this->makeEdge(from,to));
161 std::vector<E> edges(edgeSet.begin(),edgeSet.end());
165 auto getNeighbours(
const N & node)
const noexcept {
166 return adj.adjacency(node);
169 auto getReachableFrom(
const N & node)
const noexcept {
170 if constexpr(E::isDirected()){
171 auto isReachableFrom = [&](
const N & from) {
return containsEdge(from,node);};
172 return getNodes() | std::views::filter(isReachableFrom);
174 return getNeighbours(node);
178 auto getOutboundEdges(
const N & node)
const {
179 std::vector<E> edges;
180 if(not containsNode(node))
return edges;
181 for(
const auto & neighbour : getNeighbours(node)) {
182 edges.emplace_back(this->makeEdge(node,neighbour));
187 auto getInboundEdges(
const N & node)
const {
188 std::vector<E> edges;
189 if(not containsNode(node))
return edges;
190 for(
const auto & neighbour : getReachableFrom(node)) {
191 edges.emplace_back(this->makeEdge(neighbour,node));
200 const AdjContainer & getAdjacencyContainer()
const {
204 virtual ~BaseGraph()=
default;