Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Idx adj list #76

Merged
merged 10 commits into from
Nov 16, 2023
70 changes: 67 additions & 3 deletions example/CppCon2022/rr_adaptor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// https://www.reddit.com/r/cpp/comments/4yp7fv/c17_structured_bindings_convert_struct_to_a_tuple/
// https://gist.github.com/utilForever/1a058050b8af3ef46b58bcfa01d5375d

#define EDGES_CPO 1

template <class T, class... TArgs>
decltype(void(T{std::declval<TArgs>()...}), std::true_type{}) test_is_braces_constructible(int);

Expand Down Expand Up @@ -39,10 +41,42 @@ auto to_tuple(T&& object) noexcept {
return std::make_tuple();
}
}

template <class T>
using to_tuple_t = decltype(to_tuple(std::declval<T>()));


template <class T>
constexpr auto& to_tuple_value(T&& object, const int param) noexcept {
using type = std::decay_t<T>;
if constexpr (is_braces_constructible<type, any_type, any_type, any_type, any_type>{}) {
auto&& [p1, p2, p3, p4] = object;
switch (param) {
case 0: return p1;
case 1: return p2;
case 2: return p3;
case 3: return p4;
}
} else if constexpr (is_braces_constructible<type, any_type, any_type, any_type>{}) {
auto&& [p1, p2, p3] = object;
switch (param) {
case 0: return p1;
case 1: return p2;
case 2: return p3;
}
} else if constexpr (is_braces_constructible<type, any_type, any_type>{}) {
auto&& [p1, p2] = object;
switch (param) {
case 0: return p1;
case 1: return p2;
}
} else if constexpr (is_braces_constructible<type, any_type>{}) {
auto&& [p1] = object;
return p1;
} else {
return std::make_tuple();
}
}

//template <class C>
//concept has_push_back = requires(C& container, std::ranges::range_reference_t<C> val) {
// { container.push_back(val) };
Expand Down Expand Up @@ -123,18 +157,30 @@ class rr_adaptor {
}

private: // tag_invoke definitions
#if VERTICES_CPO
friend constexpr vertices_range& vertices(graph_type& g) { return g.vertices_; }
friend constexpr const vertices_range& vertices(const graph_type& g) { return g.vertices_; }
#else
friend constexpr vertices_range& tag_invoke(std::graph::tag_invoke::vertices_fn_t, graph_type& g) {
return g.vertices_;
}
friend constexpr const vertices_range& tag_invoke(std::graph::tag_invoke::vertices_fn_t, const graph_type& g) {
return g.vertices_;
}
#endif

friend vertex_id_type vertex_id(const graph_type& g, std::ranges::iterator_t<vertices_range> ui) {
return static_cast<vertex_id_type>(ui -
std::ranges::begin(g.vertices_)); // overriden to assure correct type returned
}

#if EDGES_CPO
friend constexpr edges_range& edges(graph_type& g, vertex_type& u) { return u; }
friend constexpr const edges_range& edges(const graph_type& g, const vertex_type& u) { return u; }

friend constexpr edges_range& edges(graph_type& g, const vertex_id_type uid) { return g.vertices_[uid]; }
friend constexpr const edges_range& edges(const graph_type& g, const vertex_id_type uid) { return g.vertices_[uid]; }
#else
friend constexpr edges_range& tag_invoke(std::graph::tag_invoke::edges_fn_t, graph_type& g, vertex_type& u) {
return u;
}
Expand All @@ -151,6 +197,7 @@ class rr_adaptor {
tag_invoke(std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_id_type uid) {
return g.vertices_[uid];
}
#endif

friend constexpr vertex_id_type target_id(const graph_type& g, const edge_type& uv) noexcept {
return get<0>(to_tuple(uv));
Expand All @@ -166,11 +213,11 @@ class rr_adaptor {
}

// edge_value(g,uv)
friend constexpr edge_value_type& edge_value(graph_type& g, edge_type& uv) {
friend constexpr edge_value_type edge_value(graph_type& g, edge_type& uv) {
auto t = to_tuple(uv);
return get<1>(t);
}
friend constexpr const edge_value_type& edge_value(const graph_type& g, const edge_type& uv) {
friend constexpr const edge_value_type edge_value(const graph_type& g, const edge_type& uv) {
auto t = to_tuple(uv);
return get<1>(t);
}
Expand Down Expand Up @@ -354,18 +401,34 @@ class rr_adaptor2 {
}

private:
#if VERTICES_CPO
friend constexpr vertices_range& vertices(graph_type& g) { return g.vertices_; }
friend constexpr const vertices_range& vertices(const graph_type& g) { return g.vertices_; }
#else
friend constexpr vertices_range& tag_invoke(std::graph::tag_invoke::vertices_fn_t, graph_type& g) {
return g.vertices_;
}
friend constexpr const vertices_range& tag_invoke(std::graph::tag_invoke::vertices_fn_t, const graph_type& g) {
return g.vertices_;
}
#endif

friend vertex_id_type vertex_id(const graph_type& g, std::ranges::iterator_t<vertices_range> ui) {
return static_cast<vertex_id_type>(ui -
std::ranges::begin(g.vertices_)); // overriden to assure correct type returned
}

#if EDGES_CPO
friend constexpr edges_range& edges(graph_type& g, vertex_type& u) { return get<0>(to_tuple(u)); }
friend constexpr const edges_range& edges(const graph_type& g, const vertex_type& u) { return get<0>(to_tuple(u)); }

friend constexpr edges_range& edges(graph_type& g, const vertex_id_type uid) {
return get<0>(to_tuple(g.vertices_[uid]));
}
friend constexpr const edges_range& edges(const graph_type& g, const vertex_id_type uid) {
return get<0>(to_tuple(g.vertices_[uid]));
}
#else
friend constexpr edges_range& tag_invoke(std::graph::tag_invoke::edges_fn_t, graph_type& g, vertex_type& u) {
return get<0>(to_tuple(u));
}
Expand All @@ -382,6 +445,7 @@ class rr_adaptor2 {
tag_invoke(std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_id_type uid) {
return get<0>(to_tuple(g.vertices_[uid]));
}
#endif

friend constexpr vertex_id_type target_id(const graph_type& g, const edge_type& uv) noexcept {
return get<0>(to_tuple(uv));
Expand Down
61 changes: 54 additions & 7 deletions include/graph/container/compressed_graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ class csr_row_values<EV, void, GV, VId, EIndex, Alloc> {
using value_type = void;
using size_type = size_t; //VId;

public: // Properties
public: // Properties
[[nodiscard]] constexpr size_type size() const noexcept { return 0; }
[[nodiscard]] constexpr bool empty() const noexcept { return true; }
[[nodiscard]] constexpr size_type capacity() const noexcept { return 0; }
Expand Down Expand Up @@ -342,7 +342,7 @@ class csr_col_values<void, VV, GV, VId, EIndex, Alloc> {
using value_type = void;
using size_type = size_t; //VId;

public: // Properties
public: // Properties
[[nodiscard]] constexpr size_type size() const noexcept { return 0; }
[[nodiscard]] constexpr bool empty() const noexcept { return true; }
[[nodiscard]] constexpr size_type capacity() const noexcept { return 0; }
Expand Down Expand Up @@ -481,7 +481,7 @@ class compressed_graph_base
}

public:
public: // Operations
public: // Operations
void reserve_vertices(size_type count) {
row_index_.reserve(count + 1); // +1 for terminating row
row_values_base::reserve(count);
Expand Down Expand Up @@ -739,28 +739,74 @@ class compressed_graph_base
//row_values_type row_value_; // row_value_[r] holds the value for row_index_[r], for VV!=void

private: // tag_invoke properties
#if VERTICES_CPO
friend constexpr vertices_type vertices(compressed_graph_base& g) {
if (g.row_index_.empty())
return vertices_type(g.row_index_); // really empty
else
return vertices_type(g.row_index_.begin(), g.row_index_.end() - 1); // don't include terminating row
}
friend constexpr const_vertices_type vertices(const compressed_graph_base& g) {
if (g.row_index_.empty())
return const_vertices_type(g.row_index_); // really empty
else
return const_vertices_type(g.row_index_.begin(), g.row_index_.end() - 1); // don't include terminating row
}
#else
friend constexpr vertices_type tag_invoke(::std::graph::tag_invoke::vertices_fn_t, compressed_graph_base& g) {
if (g.row_index_.empty())
return vertices_type(g.row_index_); // really empty
return vertices_type(g.row_index_); // really empty
else
return vertices_type(g.row_index_.begin(), g.row_index_.end() - 1); // don't include terminating row
}
friend constexpr const_vertices_type tag_invoke(::std::graph::tag_invoke::vertices_fn_t,
const compressed_graph_base& g) {
if (g.row_index_.empty())
return const_vertices_type(g.row_index_); // really empty
return const_vertices_type(g.row_index_); // really empty
else
return const_vertices_type(g.row_index_.begin(), g.row_index_.end() - 1); // don't include terminating row
}
#endif

friend vertex_id_type vertex_id(const compressed_graph_base& g, const_iterator ui) {
return static_cast<vertex_id_type>(ui - g.row_index_.begin());
}

#if EDGES_CPO
friend constexpr edges_type edges(graph_type& g, vertex_type& u) {
static_assert(ranges::contiguous_range<row_index_vector>, "row_index_ must be a contiguous range to get next row");
vertex_type* u2 = &u + 1;
assert(static_cast<size_t>(u2 - &u) < g.row_index_.size()); // in row_index_ bounds?
assert(static_cast<size_t>(u.index) <= g.col_index_.size() &&
static_cast<size_t>(u2->index) <= g.col_index_.size()); // in col_index_ bounds?
return edges_type(g.col_index_.begin() + u.index, g.col_index_.begin() + u2->index);
}
friend constexpr const_edges_type edges(const graph_type& g, const vertex_type& u) {
static_assert(ranges::contiguous_range<row_index_vector>, "row_index_ must be a contiguous range to get next row");
const vertex_type* u2 = &u + 1;
assert(static_cast<size_t>(u2 - &u) < g.row_index_.size()); // in row_index_ bounds?
assert(static_cast<size_t>(u.index) <= g.col_index_.size() &&
static_cast<size_t>(u2->index) <= g.col_index_.size()); // in col_index_ bounds?
return const_edges_type(g.col_index_.begin() + u.index, g.col_index_.begin() + u2->index);
}

friend constexpr edges_type edges(graph_type& g, const vertex_id_type uid) {
assert(static_cast<size_t>(uid + 1) < g.row_index_.size()); // in row_index_ bounds?
assert(static_cast<size_t>(g.row_index_[uid + 1].index) <= g.col_index_.size()); // in col_index_ bounds?
return edges_type(g.col_index_.begin() + g.row_index_[uid].index,
g.col_index_.begin() + g.row_index_[uid + 1].index);
}
friend constexpr const_edges_type edges(const graph_type& g, const vertex_id_type uid) {
assert(static_cast<size_t>(uid + 1) < g.row_index_.size()); // in row_index_ bounds?
assert(static_cast<size_t>(g.row_index_[uid + 1].index) <= g.col_index_.size()); // in col_index_ bounds?
return const_edges_type(g.col_index_.begin() + g.row_index_[uid].index,
g.col_index_.begin() + g.row_index_[uid + 1].index);
}
#else
friend constexpr edges_type tag_invoke(::std::graph::tag_invoke::edges_fn_t, graph_type& g, vertex_type& u) {
static_assert(ranges::contiguous_range<row_index_vector>, "row_index_ must be a contiguous range to get next row");
vertex_type* u2 = &u + 1;
assert(static_cast<size_t>(u2 - &u) < g.row_index_.size()); // in row_index_ bounds?
assert(static_cast<size_t>(u2 - &u) < g.row_index_.size()); // in row_index_ bounds?
assert(static_cast<size_t>(u.index) <= g.col_index_.size() &&
static_cast<size_t>(u2->index) <= g.col_index_.size()); // in col_index_ bounds?
return edges_type(g.col_index_.begin() + u.index, g.col_index_.begin() + u2->index);
Expand All @@ -769,7 +815,7 @@ class compressed_graph_base
tag_invoke(::std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_type& u) {
static_assert(ranges::contiguous_range<row_index_vector>, "row_index_ must be a contiguous range to get next row");
const vertex_type* u2 = &u + 1;
assert(static_cast<size_t>(u2 - &u) < g.row_index_.size()); // in row_index_ bounds?
assert(static_cast<size_t>(u2 - &u) < g.row_index_.size()); // in row_index_ bounds?
assert(static_cast<size_t>(u.index) <= g.col_index_.size() &&
static_cast<size_t>(u2->index) <= g.col_index_.size()); // in col_index_ bounds?
return const_edges_type(g.col_index_.begin() + u.index, g.col_index_.begin() + u2->index);
Expand All @@ -789,6 +835,7 @@ class compressed_graph_base
return const_edges_type(g.col_index_.begin() + g.row_index_[uid].index,
g.col_index_.begin() + g.row_index_[uid + 1].index);
}
#endif


// target_id(g,uv), target(g,uv)
Expand Down
23 changes: 21 additions & 2 deletions include/graph/container/dynamic_graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -679,13 +679,18 @@ class dynamic_vertex_base {
edges_type edges_;

private: // tag_invoke properties
#if EDGES_CPO
friend constexpr edges_type& edges(graph_type& g, vertex_type& u) { return u.edges_; }
friend constexpr const edges_type& edges(const graph_type& g, const vertex_type& u) { return u.edges_; }
#else
friend constexpr edges_type& tag_invoke(::std::graph::tag_invoke::edges_fn_t, graph_type& g, vertex_type& u) {
return u.edges_;
}
friend constexpr const edges_type&
tag_invoke(::std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_type& u) {
return u.edges_;
}
#endif

friend constexpr typename edges_type::iterator
find_vertex_edge(graph_type& g, vertex_id_type uid, vertex_id_type vid) {
Expand Down Expand Up @@ -1212,7 +1217,7 @@ class dynamic_graph_base {
constexpr typename vertices_type::value_type& operator[](size_type i) noexcept { return vertices_[i]; }
constexpr const typename vertices_type::value_type& operator[](size_type i) const noexcept { return vertices_[i]; }

public: // Operations
public: // Operations
void reserve_vertices(size_type count) {
if constexpr (reservable<vertices_type>) // reserve if we can; otherwise ignored
vertices_.reserve(count);
Expand All @@ -1233,18 +1238,31 @@ class dynamic_graph_base {
vertices_type vertices_;

private: // tag_invoke properties
#if VERTICES_CPO
friend constexpr vertices_type& vertices(dynamic_graph_base& g) { return g.vertices_; }
friend constexpr const vertices_type& vertices(const dynamic_graph_base& g) { return g.vertices_; }
#else
friend constexpr vertices_type& tag_invoke(::std::graph::tag_invoke::vertices_fn_t, dynamic_graph_base& g) {
return g.vertices_;
}
friend constexpr const vertices_type& tag_invoke(::std::graph::tag_invoke::vertices_fn_t,
const dynamic_graph_base& g) {
return g.vertices_;
}
#endif

friend vertex_id_type vertex_id(const dynamic_graph_base& g, typename vertices_type::const_iterator ui) {
return static_cast<vertex_id_type>(ui - g.vertices_.begin());
}

#if EDGES_CPO
friend constexpr edges_type& edges(graph_type& g, const vertex_id_type uid) { //
return g.vertices_[uid].edges();
}
friend constexpr const edges_type& edges(const graph_type& g, const vertex_id_type uid) {
return g.vertices_[uid].edges();
}
#else
friend constexpr edges_type&
tag_invoke(::std::graph::tag_invoke::edges_fn_t, graph_type& g, const vertex_id_type uid) {
return g.vertices_[uid].edges();
Expand All @@ -1253,6 +1271,7 @@ class dynamic_graph_base {
tag_invoke(::std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_id_type uid) {
return g.vertices_[uid].edges();
}
#endif
};

/**
Expand Down Expand Up @@ -1612,7 +1631,7 @@ class dynamic_graph : public dynamic_graph_base<EV, VV, GV, VId, Sourced, Traits
private:
value_type value_; ///< Graph value

private: // tag_invoke properties
private: // tag_invoke properties
friend constexpr value_type& graph_value(graph_type& g) { return g.value_; }
friend constexpr const value_type& graph_value(const graph_type& g) { return g.value_; }
};
Expand Down
4 changes: 4 additions & 0 deletions include/graph/container/utility_edgelist.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,13 @@ class utility_edgelist {
bool is_directed() { return directed_; }

private:
#if EDGES_CPO
friend constexpr storage_type& edges(utility_edgelist& el) { return el.storage_; }
#else
friend constexpr storage_type& tag_invoke(::std::graph::edgelist::tag_invoke::edges_fn_t, utility_edgelist& el) {
return el.storage_;
}
#endif

friend constexpr VSourceId& source_id(utility_edgelist& el, value_type& e) { return std::get<0>(e); }

Expand Down
Loading