Skip to content

Commit 37ab1c3

Browse files
committed
add Graph
1 parent 3dcaef2 commit 37ab1c3

File tree

3 files changed

+622
-0
lines changed

3 files changed

+622
-0
lines changed

include/gf2/core/Graph.h

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// SPDX-License-Identifier: Zlib
2+
// Copyright (c) 2023-2025 Julien Bernard
3+
#ifndef GF_GRAPH_H
4+
#define GF_GRAPH_H
5+
6+
#include <cassert>
7+
8+
#include <functional>
9+
#include <limits>
10+
#include <set>
11+
#include <vector>
12+
13+
#include "CoreApi.h"
14+
#include "Range.h"
15+
16+
namespace gf {
17+
18+
/*
19+
* VertexId
20+
*/
21+
22+
enum class VertexId : std::size_t { };
23+
using VertexRange = RangeId<VertexId>;
24+
25+
constexpr VertexId NoVertex = VertexId{ std::numeric_limits<std::size_t>::max() };
26+
27+
constexpr std::size_t to_index(VertexId id)
28+
{
29+
return static_cast<std::size_t>(id);
30+
}
31+
32+
/*
33+
* EdgeId
34+
*/
35+
36+
enum class EdgeId : std::size_t { };
37+
using EdgeRange = RangeId<EdgeId>;
38+
39+
constexpr EdgeId NoEdge = EdgeId{ std::numeric_limits<std::size_t>::max() };
40+
41+
constexpr std::size_t to_index(EdgeId id)
42+
{
43+
return static_cast<std::size_t>(id);
44+
}
45+
46+
/*
47+
* Graph
48+
*/
49+
50+
class GF_CORE_API Graph {
51+
public:
52+
explicit Graph(std::size_t n = 0);
53+
54+
// vertices
55+
56+
VertexId add_vertex();
57+
VertexRange vertices() const;
58+
std::size_t vertex_count() const;
59+
bool is_valid(VertexId v) const;
60+
void remove_vertex(VertexId v);
61+
62+
// edges
63+
64+
EdgeId add_edge(VertexId source, VertexId target);
65+
EdgeRange edges() const;
66+
std::size_t edge_count() const;
67+
bool is_valid(EdgeId e) const;
68+
void remove_edge(EdgeId e);
69+
70+
VertexId source(EdgeId e) const;
71+
VertexId target(EdgeId e) const;
72+
73+
// in edges
74+
75+
using InEdgeRange = IteratorRange<std::set<EdgeId>::const_iterator>;
76+
InEdgeRange in_edges(VertexId v) const;
77+
78+
// out edges
79+
80+
using OutEdgeRange = IteratorRange<std::set<EdgeId>::const_iterator>;
81+
OutEdgeRange out_edges(VertexId v) const;
82+
83+
//
84+
85+
void clear();
86+
87+
private:
88+
struct Vertex {
89+
VertexId id;
90+
};
91+
92+
struct Edge {
93+
EdgeId id;
94+
VertexId source;
95+
VertexId target;
96+
};
97+
98+
void erase_edge(Edge& edge);
99+
100+
std::size_t m_next_vertex_id = 0;
101+
std::size_t m_next_edge_id = 0;
102+
std::size_t m_vertex_count = 0;
103+
std::size_t m_edge_count = 0;
104+
std::vector<Vertex> m_vertices;
105+
std::vector<Edge> m_edges;
106+
std::vector<std::set<EdgeId>> m_in_edges;
107+
std::vector<std::set<EdgeId>> m_out_edges;
108+
};
109+
110+
GF_CORE_API std::vector<VertexId> topological_sort(const Graph& graph);
111+
112+
struct GF_CORE_API GraphShortestPath {
113+
VertexId previous = NoVertex;
114+
double distance = 0.0;
115+
};
116+
117+
using GraphRouteCostFunction = std::function<double(EdgeId)>;
118+
119+
GF_CORE_API std::vector<GraphShortestPath> compute_shortest_path(const Graph& graph, VertexId origin, GraphRouteCostFunction function);
120+
121+
template<typename V, typename E>
122+
class DataGraph : public Graph {
123+
public:
124+
explicit DataGraph(std::size_t n = 0)
125+
: Graph(n)
126+
{
127+
if (n > 0) {
128+
m_vertex_data.reserve(n);
129+
m_edge_data.reserve(n);
130+
}
131+
}
132+
133+
VertexId add_vertex(V v)
134+
{
135+
auto id = Graph::add_vertex();
136+
m_vertex_data.push_back(std::move(v));
137+
return id;
138+
}
139+
140+
V& operator()(VertexId id)
141+
{
142+
return m_vertex_data[to_index(id)];
143+
}
144+
145+
const V& operator()(VertexId id) const
146+
{
147+
return m_vertex_data[to_index(id)];
148+
}
149+
150+
EdgeId add_edge(VertexId source, VertexId target, E e)
151+
{
152+
auto id = Graph::add_edge(source, target);
153+
m_edge_data.push_back(std::move(e));
154+
return id;
155+
}
156+
157+
E& operator()(EdgeId id)
158+
{
159+
return m_edge_data[to_index(id)];
160+
}
161+
162+
const E& operator()(EdgeId id) const
163+
{
164+
return m_edge_data[to_index(id)];
165+
}
166+
167+
private:
168+
std::vector<V> m_vertex_data;
169+
std::vector<E> m_edge_data;
170+
};
171+
172+
}
173+
174+
#endif // GF_GRAPH_H

include/gf2/core/Range.h

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,133 @@ namespace gf {
149149
return { std::size_t(0), size };
150150
}
151151

152+
/*
153+
* RangeId
154+
*/
155+
156+
template<typename Id>
157+
class RangeId {
158+
public:
159+
class Iterator {
160+
public:
161+
using difference_type = std::ptrdiff_t;
162+
using value_type = Id;
163+
using pointer = value_type;
164+
using reference = value_type;
165+
using iterator_category = std::bidirectional_iterator_tag;
166+
167+
constexpr Iterator(std::size_t index)
168+
: m_index(index)
169+
{
170+
}
171+
172+
constexpr void swap(Iterator& other) noexcept
173+
{
174+
std::swap(m_index, other.m_index);
175+
}
176+
177+
constexpr reference operator*() noexcept
178+
{
179+
return Id{ m_index };
180+
}
181+
182+
constexpr pointer operator->() noexcept
183+
{
184+
return Id{ m_index };
185+
}
186+
187+
constexpr Iterator& operator++() noexcept
188+
{
189+
++m_index;
190+
return *this;
191+
}
192+
193+
constexpr Iterator operator++(int) noexcept
194+
{
195+
Iterator copy = *this;
196+
++m_index;
197+
return copy;
198+
}
199+
200+
constexpr Iterator& operator--() noexcept
201+
{
202+
--m_index;
203+
return *this;
204+
}
205+
206+
constexpr bool operator!=(const Iterator& other) const noexcept
207+
{
208+
return m_index != other.m_index;
209+
}
210+
211+
constexpr bool operator==(const Iterator& other) const noexcept
212+
{
213+
return m_index == other.m_index;
214+
}
215+
216+
private:
217+
std::size_t m_index;
218+
};
219+
220+
constexpr RangeId(std::size_t size)
221+
: m_size(size)
222+
{
223+
}
224+
225+
constexpr Iterator begin() const noexcept
226+
{
227+
return Iterator{ 0 };
228+
}
229+
230+
constexpr Iterator end() const noexcept
231+
{
232+
return Iterator{ m_size };
233+
}
234+
235+
constexpr std::size_t size() const noexcept
236+
{
237+
return m_size;
238+
}
239+
240+
private:
241+
std::size_t m_size;
242+
};
243+
244+
template<typename Id>
245+
inline void swap(typename RangeId<Id>::Iterator& lhs, typename RangeId<Id>::Iterator& rhs) noexcept
246+
{
247+
lhs.swap(rhs);
248+
}
249+
250+
/*
251+
* IteratorRange
252+
*/
253+
254+
template<typename Iterator>
255+
class IteratorRange {
256+
public:
257+
IteratorRange(Iterator begin, Iterator end)
258+
: m_begin(begin)
259+
, m_end(end)
260+
{
261+
}
262+
263+
Iterator begin() const noexcept
264+
{
265+
return m_begin;
266+
}
267+
268+
Iterator end() const noexcept
269+
{
270+
return m_end;
271+
}
272+
273+
private:
274+
Iterator m_begin;
275+
Iterator m_end;
276+
};
277+
278+
152279
/*
153280
* Range2D
154281
*/

0 commit comments

Comments
 (0)