From a16bfa2ffb1f537eedf49e9a121e016da3b1cce7 Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Sun, 4 Feb 2024 11:39:40 -0500 Subject: [PATCH 1/6] Remove disabled tag_invoke impl for edges() --- example/CppCon2022/rr_adaptor.hpp | 40 ------------ include/graph/container/compressed_graph.hpp | 35 ----------- include/graph/container/dynamic_graph.hpp | 21 ------- include/graph/container/utility_edgelist.hpp | 6 -- include/graph/detail/graph_cpo.hpp | 65 -------------------- 5 files changed, 167 deletions(-) diff --git a/example/CppCon2022/rr_adaptor.hpp b/example/CppCon2022/rr_adaptor.hpp index 44482e1..0dcbbbd 100644 --- a/example/CppCon2022/rr_adaptor.hpp +++ b/example/CppCon2022/rr_adaptor.hpp @@ -6,8 +6,6 @@ // 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 decltype(void(T{std::declval()...}), std::true_type{}) test_is_braces_constructible(int); @@ -174,30 +172,11 @@ class rr_adaptor { 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; - } - friend constexpr const edges_range& - tag_invoke(std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_type& u) { - return u; - } - - friend constexpr edges_range& - tag_invoke(std::graph::tag_invoke::edges_fn_t, graph_type& g, const vertex_id_type uid) { - return g.vertices_[uid]; - } - friend constexpr const edges_range& - 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)); @@ -418,7 +397,6 @@ class rr_adaptor2 { 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)); } @@ -428,24 +406,6 @@ class rr_adaptor2 { 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)); - } - friend constexpr const edges_range& - tag_invoke(std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_type& u) { - return get<0>(to_tuple(u)); - } - - friend constexpr edges_range& - tag_invoke(std::graph::tag_invoke::edges_fn_t, graph_type& g, const vertex_id_type uid) { - return get<0>(to_tuple(g.vertices_[uid])); - } - friend constexpr const edges_range& - 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)); diff --git a/include/graph/container/compressed_graph.hpp b/include/graph/container/compressed_graph.hpp index 0ef7230..b6f9e65 100644 --- a/include/graph/container/compressed_graph.hpp +++ b/include/graph/container/compressed_graph.hpp @@ -772,7 +772,6 @@ class compressed_graph_base return static_cast(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_ must be a contiguous range to get next row"); vertex_type* u2 = &u + 1; @@ -802,40 +801,6 @@ 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); } -#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_ must be a contiguous range to get next row"); - vertex_type* u2 = &u + 1; - assert(static_cast(u2 - &u) < g.row_index_.size()); // in row_index_ bounds? - assert(static_cast(u.index) <= g.col_index_.size() && - static_cast(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 - tag_invoke(::std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_type& u) { - static_assert(ranges::contiguous_range, "row_index_ must be a contiguous range to get next row"); - const vertex_type* u2 = &u + 1; - assert(static_cast(u2 - &u) < g.row_index_.size()); // in row_index_ bounds? - assert(static_cast(u.index) <= g.col_index_.size() && - static_cast(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 - tag_invoke(::std::graph::tag_invoke::edges_fn_t, graph_type& g, const vertex_id_type uid) { - assert(static_cast(uid + 1) < g.row_index_.size()); // in row_index_ bounds? - assert(static_cast(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 - tag_invoke(::std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_id_type uid) { - assert(static_cast(uid + 1) < g.row_index_.size()); // in row_index_ bounds? - assert(static_cast(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); - } -#endif // target_id(g,uv), target(g,uv) diff --git a/include/graph/container/dynamic_graph.hpp b/include/graph/container/dynamic_graph.hpp index bb764aa..0a37d46 100644 --- a/include/graph/container/dynamic_graph.hpp +++ b/include/graph/container/dynamic_graph.hpp @@ -679,18 +679,8 @@ 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) { @@ -1255,23 +1245,12 @@ class dynamic_graph_base { return static_cast(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(); - } - friend constexpr const edges_type& - tag_invoke(::std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_id_type uid) { - return g.vertices_[uid].edges(); - } -#endif }; /** diff --git a/include/graph/container/utility_edgelist.hpp b/include/graph/container/utility_edgelist.hpp index 8da425a..920efdb 100644 --- a/include/graph/container/utility_edgelist.hpp +++ b/include/graph/container/utility_edgelist.hpp @@ -72,13 +72,7 @@ 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); } diff --git a/include/graph/detail/graph_cpo.hpp b/include/graph/detail/graph_cpo.hpp index dbbeb5c..bf2cd3d 100644 --- a/include/graph/detail/graph_cpo.hpp +++ b/include/graph/detail/graph_cpo.hpp @@ -7,7 +7,6 @@ # define GRAPH_CPO_HPP # define VERTICES_CPO 1 // warnings need to be tracked down -# define EDGES_CPO 1 // warnings need to be tracked down namespace std::graph { @@ -643,7 +642,6 @@ using partition_id_t = decltype(partition_id(declval(), declval> // edge_reference_t = ranges::range_reference_t> // -# if EDGES_CPO namespace _Edges { # if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 void edges() = delete; // Block unqualified name lookup @@ -779,59 +777,6 @@ namespace _Edges { inline namespace _Cpos { inline constexpr _Edges::_Cpo edges; } -# else -namespace tag_invoke { - TAG_INVOKE_DEF(edges); - - template - concept _has_edges_vtxref_adl = requires(G&& g, vertex_reference_t u) { - { edges(g, u) }; - }; - - template - concept _has_edges_vtxid_adl = requires(G&& g, vertex_id_t uid) { - { edges(g, uid) }; - }; -} // namespace tag_invoke - -/** - * @brief Get the outgoing edges of a vertex. - * - * Complexity: O(1) - * - * Default implementation: n/a. This must be specialized for each graph type. - * - * @tparam G The graph type. - * @param g A graph instance. - * @param u Vertex reference. - * @return A range of the outgoing edges. -*/ -template -requires tag_invoke::_has_edges_vtxref_adl -auto edges(G&& g, vertex_reference_t u) -> decltype(tag_invoke::edges(g, u)) { - return tag_invoke::edges(g, u); // graph author must define -} - -/** - * @brief Get the outgoing edges of a vertex id. - * - * Complexity: O(1) - * - * Default implementation: edges(g, *find_vertex(g, uid)) - * - * @tparam G The graph type. - * @param g A graph instance. - * @param uid Vertex id. - * @return A range of the outgoing edges. -*/ -template -auto edges(G&& g, vertex_id_t uid) -> decltype(tag_invoke::edges(g, uid)) { - if constexpr (tag_invoke::_has_edges_vtxid_adl) - return tag_invoke::edges(g, uid); - else - return edges(g, *find_vertex(g, uid)); -} -# endif /** * @brief The outgoing edge range type of a vertex for graph G. @@ -2083,7 +2028,6 @@ inline namespace _Cpos { namespace edgelist { -# if EDGES_CPO namespace _Edges { # if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 void edges() = delete; // Block unqualified name lookup @@ -2143,16 +2087,7 @@ namespace edgelist { inline namespace _Cpos { inline constexpr _Edges::_Cpo edges; } -# else - namespace tag_invoke { - TAG_INVOKE_DEF(edges); // edges(e) -> [edge list vertices] - } - template - auto edges(EL&& el) { - return el; - } -# endif template using edgelist_range_t = decltype(edges(declval())); From 78ebb0b636407084c27343ea3ac5f6fb89a01b9c Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Sun, 4 Feb 2024 12:04:02 -0500 Subject: [PATCH 2/6] Remove disabled tag_invoke impl for vertices(g) --- example/CppCon2022/rr_adaptor.hpp | 18 -------------- include/graph/container/compressed_graph.hpp | 16 ------------ include/graph/container/dynamic_graph.hpp | 10 -------- include/graph/detail/graph_cpo.hpp | 26 -------------------- 4 files changed, 70 deletions(-) diff --git a/example/CppCon2022/rr_adaptor.hpp b/example/CppCon2022/rr_adaptor.hpp index 0dcbbbd..81b5574 100644 --- a/example/CppCon2022/rr_adaptor.hpp +++ b/example/CppCon2022/rr_adaptor.hpp @@ -155,17 +155,8 @@ 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 ui) { return static_cast(ui - @@ -380,17 +371,8 @@ 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 ui) { return static_cast(ui - diff --git a/include/graph/container/compressed_graph.hpp b/include/graph/container/compressed_graph.hpp index b6f9e65..c0a57b0 100644 --- a/include/graph/container/compressed_graph.hpp +++ b/include/graph/container/compressed_graph.hpp @@ -739,7 +739,6 @@ 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 @@ -752,21 +751,6 @@ class compressed_graph_base 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 - 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 - 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(ui - g.row_index_.begin()); diff --git a/include/graph/container/dynamic_graph.hpp b/include/graph/container/dynamic_graph.hpp index 0a37d46..5bd0b0a 100644 --- a/include/graph/container/dynamic_graph.hpp +++ b/include/graph/container/dynamic_graph.hpp @@ -1228,18 +1228,8 @@ 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(ui - g.vertices_.begin()); diff --git a/include/graph/detail/graph_cpo.hpp b/include/graph/detail/graph_cpo.hpp index bf2cd3d..d712be7 100644 --- a/include/graph/detail/graph_cpo.hpp +++ b/include/graph/detail/graph_cpo.hpp @@ -6,8 +6,6 @@ #ifndef GRAPH_CPO_HPP # define GRAPH_CPO_HPP -# define VERTICES_CPO 1 // warnings need to be tracked down - namespace std::graph { # ifndef _MSC_VER @@ -152,7 +150,6 @@ concept adjacency_matrix = is_adjacency_matrix_v; // vertex_t = ranges::range_value_t> // vertex_reference_t = ranges::range_reference_t> // -# if VERTICES_CPO namespace _Vertices { # if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 void vertices() = delete; // Block unqualified name lookup @@ -231,29 +228,6 @@ namespace _Vertices { inline namespace _Cpos { inline constexpr _Vertices::_Cpo vertices; } -# else -namespace tag_invoke { - TAG_INVOKE_DEF(vertices); // vertices(g) -> [graph vertices] -} - -/** - * @brief Returns the vertices range for a graph G. - * - * Default implementation: n/a. - * - * Complexity: O(1) - * - * This is a customization point function that is required to be overridden for each - * graph type. - * - * @tparam G The graph type - * @param g A graph instance -*/ -template -auto vertices(G&& g) -> decltype(tag_invoke::vertices(g)) { - return tag_invoke::vertices(g); -} -# endif /** * @brief The vertex range type for a graph G. From 0a2cf2be25006b550034f49b26c2bc91d5748c4d Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Sun, 4 Feb 2024 12:04:32 -0500 Subject: [PATCH 3/6] Upgrade to fmt 10.2.1 to avoid warnings in MSVC --- cmake/FetchFMT.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FetchFMT.cmake b/cmake/FetchFMT.cmake index 9f0f214..04ecb4b 100644 --- a/cmake/FetchFMT.cmake +++ b/cmake/FetchFMT.cmake @@ -6,7 +6,7 @@ message(STATUS "Cloning External Project: fmt") FetchContent_Declare( fmt GIT_REPOSITORY https://github.com/fmtlib/fmt.git - GIT_TAG 8.1.1 + GIT_TAG 10.2.1 ) FetchContent_GetProperties(fmt) From a76f7547ae00279a644f42707da732901f9f93e4 Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Sun, 4 Feb 2024 12:20:40 -0500 Subject: [PATCH 4/6] Refactor target_id(g,uv) CPO from tag_invoke --> niebloid --- include/graph/detail/graph_cpo.hpp | 190 +++++++++++++++++++---------- 1 file changed, 127 insertions(+), 63 deletions(-) diff --git a/include/graph/detail/graph_cpo.hpp b/include/graph/detail/graph_cpo.hpp index d712be7..2c4e9fb 100644 --- a/include/graph/detail/graph_cpo.hpp +++ b/include/graph/detail/graph_cpo.hpp @@ -151,11 +151,11 @@ concept adjacency_matrix = is_adjacency_matrix_v; // vertex_reference_t = ranges::range_reference_t> // namespace _Vertices { -# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 - void vertices() = delete; // Block unqualified name lookup -# else // ^^^ no workaround / workaround vvv +# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void vertices() = delete; // Block unqualified name lookup +# else // ^^^ no workaround / workaround vvv void vertices(); -# endif // ^^^ workaround ^^^ +# endif // ^^^ workaround ^^^ template concept _Has_ref_member = _Has_class_or_enum_type<_G> && // @@ -163,7 +163,7 @@ namespace _Vertices { { _Fake_copy_init(__g.vertices()) }; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g) { { _Fake_copy_init(vertices(__g)) }; // intentional ADL }; @@ -215,7 +215,7 @@ namespace _Vertices { return __g.vertices(); } else if constexpr (_Strat_ref == _St_ref::_Non_member) { //static_assert(is_reference_v); - return vertices(__g); // intentional ADL + return vertices(__g); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { return std::forward<_G>(__g); // intentional ADL } else { @@ -274,7 +274,7 @@ namespace _Vertex_id { { _Fake_copy_init(ui->vertex_id(__g)) }; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const vertex_iterator_t<_G> ui) { { _Fake_copy_init(vertex_id(__g, ui)) }; // intentional ADL }; @@ -396,7 +396,7 @@ namespace _Find_vertex { }; template - concept _Has_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid) { { _Fake_copy_init(find_vertex(__g, uid)) }; // intentional ADL }; @@ -476,7 +476,7 @@ namespace _Partition_id { { _Fake_copy_init(u.partition_id(__g)) }; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const vertex_reference_t<_G>& u) { { _Fake_copy_init(partition_id(__g, u)) }; // intentional ADL }; @@ -487,7 +487,7 @@ namespace _Partition_id { }; template - concept _Has_id_ADL = _Has_class_or_enum_type<_G> // + concept _Has_id_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid) { { _Fake_copy_init(partition_id(__g, uid)) }; // intentional ADL }; @@ -509,7 +509,7 @@ namespace _Partition_id { return {_St_id::_Non_member, noexcept(_Fake_copy_init(partition_id(declval<_G>(), declval>())))}; // intentional ADL } else if constexpr (_Can_id_eval<_G>) { - return {_St_id::_Auto_eval, noexcept(_Fake_copy_init(vertex_id_t<_G>(0)))}; // default impl + return {_St_id::_Auto_eval, noexcept(_Fake_copy_init(vertex_id_t<_G>(0)))}; // default impl } else { return {_St_id::_None}; } @@ -561,7 +561,7 @@ namespace _Partition_id { } else if constexpr (_Strat_ref == _St_ref::_Non_member) { return partition_id(__g, u); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { - return vertex_id_t<_G>{0}; // default impl + return vertex_id_t<_G>{0}; // default impl } else { static_assert(_Always_false<_G>, "partition_id(g,u) is not defined and the default implementation cannot be evaluated"); @@ -589,7 +589,7 @@ namespace _Partition_id { if constexpr (_Strat_id == _St_id::_Non_member) { return partition_id(__g, uid); // intentional ADL } else if constexpr (_Strat_id == _St_id::_Auto_eval) { - return vertex_id_t<_G>{0}; // default impl + return vertex_id_t<_G>{0}; // default impl } else { static_assert(_Always_false<_G>, "partition_id(g,uid) is not defined and the default implementation cannot be evaluated"); @@ -617,18 +617,18 @@ using partition_id_t = decltype(partition_id(declval(), declval> // namespace _Edges { -# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 - void edges() = delete; // Block unqualified name lookup -# else // ^^^ no workaround / workaround vvv +# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void edges() = delete; // Block unqualified name lookup +# else // ^^^ no workaround / workaround vvv void edges(); -# endif // ^^^ workaround ^^^ +# endif // ^^^ workaround ^^^ template concept _Has_ref_member = requires(_G&& __g, vertex_reference_t<_G> u) { { _Fake_copy_init(u.edges(__g)) }; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const vertex_reference_t<_G>& u) { { _Fake_copy_init(edges(__g, u)) }; // intentional ADL }; @@ -636,7 +636,7 @@ namespace _Edges { concept _Can_ref_eval = _Has_class_or_enum_type<_G> && ranges::forward_range>; template - concept _Has_id_ADL = _Has_class_or_enum_type<_G> // + concept _Has_id_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid) { { _Fake_copy_init(edges(__g, uid)) }; // intentional ADL }; @@ -711,7 +711,7 @@ namespace _Edges { } else if constexpr (_Strat_ref == _St_ref::_Non_member) { return edges(__g, u); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { - return u; // default impl + return u; // default impl } else { static_assert(_Always_false<_G>, "edges(g,u) is not defined and the default implementation cannot be evaluated"); @@ -737,7 +737,7 @@ namespace _Edges { constexpr _St_id _Strat_id = _Choice_id<_G&>._Strategy; if constexpr (_Strat_id == _St_id::_Non_member) { - return edges(__g, uid); // intentional ADL + return edges(__g, uid); // intentional ADL } else if constexpr (_Strat_id == _St_id::_Auto_eval) { return *find_vertex(__g, uid); // default impl } else { @@ -890,7 +890,7 @@ namespace _Target { # endif // ^^^ workaround ^^^ template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const edge_reference_t<_G>& uv) { { _Fake_copy_init(target(__g, uv)) }; // intentional ADL }; @@ -975,7 +975,7 @@ namespace _EL_Source_id { { _Fake_copy_init(uv.source_id(__g)) }; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const edge_reference_t<_G>& uv) { { _Fake_copy_init(source_id(__g, uv)) }; // intentional ADL }; @@ -1050,7 +1050,7 @@ namespace _Source { # endif // ^^^ workaround ^^^ template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const edge_reference_t<_G>& uv) { { _Fake_copy_init(source(__g, uv)) }; // intentional ADL }; @@ -1144,7 +1144,7 @@ namespace _Edge_id { { uv.edge_id(__g) } -> convertible_to>; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const edge_reference_t<_G>& uv) { { _Fake_copy_init(edge_id(__g, uv)) } -> convertible_to>; // intentional ADL }; @@ -1238,7 +1238,7 @@ namespace _Find_vertex_edge { }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, vertex_reference_t<_G> u, const vertex_id_t<_G>& vid) { { _Fake_copy_init(find_vertex_edge(__g, u, vid)) }; // intentional ADL }; @@ -1249,7 +1249,7 @@ namespace _Find_vertex_edge { }; template - concept _Has_id_ADL = _Has_class_or_enum_type<_G> // + concept _Has_id_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, vertex_id_t<_G> uid, const vertex_id_t<_G>& vid) { { _Fake_copy_init(find_vertex_edge(__g, uid, vid)) }; // intentional ADL }; @@ -1386,7 +1386,7 @@ namespace _Contains_edge { # endif // ^^^ workaround ^^^ template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid, const vertex_id_t<_G>& vid) { { _Fake_copy_init(contains_edge(__g, uid, vid)) }; // intentional ADL }; @@ -1486,7 +1486,7 @@ namespace _NumVertices { { _Fake_copy_init(__g.num_vertices(__g)) }; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g) { { _Fake_copy_init(num_vertices(__g)) }; // intentional ADL }; @@ -1497,7 +1497,7 @@ namespace _NumVertices { }; template - concept _Has_id_ADL = _Has_class_or_enum_type<_G> // + concept _Has_id_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, partition_id_t<_G> pid) { { _Fake_copy_init(num_vertices(__g, pid)) }; // intentional ADL }; @@ -1568,7 +1568,7 @@ namespace _NumVertices { static_assert(_Strat_id == _St_id::_Auto_eval); if constexpr (_Strat_id == _St_id::_Non_member) { - return num_vertices(__g, pid); // intentional ADL + return num_vertices(__g, pid); // intentional ADL } else if constexpr (_Strat_id == _St_id::_Auto_eval) { return ranges::size(vertices(__g, pid)); // default impl } else { @@ -1596,7 +1596,7 @@ namespace _NumVertices { if constexpr (_Strat_id == _St_ref::_Member) { return __g.num_vertices(); } else if constexpr (_Strat_id == _St_ref::_Non_member) { - return num_vertices(__g); // intentional ADL + return num_vertices(__g); // intentional ADL } else if constexpr (_Strat_id == _St_ref::_Auto_eval) { return ranges::size(vertices(__g)); // default impl } else { @@ -1627,7 +1627,7 @@ namespace _Degree { { _Fake_copy_init(u.degree(__g)) }; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const vertex_reference_t<_G>& u) { { _Fake_copy_init(degree(__g, u)) }; // intentional ADL }; @@ -1638,7 +1638,7 @@ namespace _Degree { }; template - concept _Has_id_ADL = _Has_class_or_enum_type<_G> // + concept _Has_id_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid) { { _Fake_copy_init(degree(__g, uid)) }; // intentional ADL }; @@ -1711,7 +1711,7 @@ namespace _Degree { if constexpr (_Strat_ref == _St_ref::_Member) { return u.degree(__g); } else if constexpr (_Strat_ref == _St_ref::_Non_member) { - return degree(__g, u); // intentional ADL + return degree(__g, u); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { return ranges::size(edges(__g, u)); // default impl } else { @@ -1739,7 +1739,7 @@ namespace _Degree { constexpr _St_id _Strat_id = _Choice_id<_G&>._Strategy; if constexpr (_Strat_id == _St_id::_Non_member) { - return degree(__g, uid); // intentional ADL + return degree(__g, uid); // intentional ADL } else if constexpr (_Strat_id == _St_id::_Auto_eval) { return ranges::size(edges(__g, uid)); // default impl } else { @@ -1772,7 +1772,7 @@ namespace _Vertex_value { { _Fake_copy_init(u.vertex_value(__g)) }; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, vertex_reference_t<_G> u) { { _Fake_copy_init(vertex_value(__g, u)) }; // intentional ADL }; @@ -1852,7 +1852,7 @@ namespace _Edge_value { { _Fake_copy_init(uv.edge_value(__g)) }; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, edge_reference_t<_G> uv) { { _Fake_copy_init(edge_value(__g, uv)) }; // intentional ADL }; @@ -1876,7 +1876,7 @@ namespace _Edge_value { _St_ref::_Non_member, noexcept(_Fake_copy_init(edge_value(declval<_G>(), declval>())))}; // intentional ADL } else if constexpr (_Can_ref_eval<_G>) { - return {_St_ref::_Auto_eval, noexcept(_Fake_copy_init(declval>()))}; // intentional ADL + return {_St_ref::_Auto_eval, noexcept(_Fake_copy_init(declval>()))}; // intentional ADL } else { return {_St_ref::_None}; } @@ -1909,7 +1909,7 @@ namespace _Edge_value { } else if constexpr (_Strat_ref == _St_ref::_Non_member) { return edge_value(__g, uv); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { - return uv; // intentional ADL + return uv; // intentional ADL } else { static_assert(_Always_false<_G>, "edge_value(g,uv) must be defined for the graph"); } @@ -1943,7 +1943,7 @@ namespace _Graph_value { { _Fake_copy_init(__g.graph_value()) }; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g) { { _Fake_copy_init(graph_value(__g)) }; // intentional ADL }; @@ -2003,14 +2003,14 @@ inline namespace _Cpos { namespace edgelist { namespace _Edges { -# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 - void edges() = delete; // Block unqualified name lookup -# else // ^^^ no workaround / workaround vvv +# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void edges() = delete; // Block unqualified name lookup +# else // ^^^ no workaround / workaround vvv void edges(); -# endif // ^^^ workaround ^^^ +# endif // ^^^ workaround ^^^ template - concept _Has_ref_ADL = _Has_class_or_enum_type // + concept _Has_ref_ADL = _Has_class_or_enum_type // && ranges::forward_range && requires(EL&& el) { { _Fake_copy_init(edges(el)) }; // intentional ADL }; @@ -2087,7 +2087,7 @@ namespace edgelist { { _Fake_copy_init(uv.source_id(__g)) }; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const edge_reference_t<_G>& uv) { { _Fake_copy_init(source_id(__g, uv)) }; // intentional ADL }; @@ -2150,13 +2150,77 @@ namespace edgelist { template using source_id_t = decltype(source_id(declval(), declval>())); - namespace tag_invoke { - TAG_INVOKE_DEF(target_id); - } - template - auto target_id(EL&& el, edge_reference_t uv) { - return tag_invoke::target_id(el, uv); + namespace _Target_id { +# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void target_id() = delete; // Block unqualified name lookup +# else // ^^^ no workaround / workaround vvv + void target_id(); +# endif // ^^^ workaround ^^^ + + template + concept _Has_ref_member = requires(_G&& __g, edge_reference_t<_G> uv) { + { _Fake_copy_init(uv.target_id(__g)) }; + }; + template + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + && requires(_G&& __g, const edge_reference_t<_G>& uv) { + { _Fake_copy_init(target_id(__g, uv)) }; // intentional ADL + }; + + class _Cpo { + private: + enum class _St_ref { _None, _Member, _Non_member, _Auto_eval }; + + template + [[nodiscard]] static consteval _Choice_t<_St_ref> _Choose_ref() noexcept { + static_assert(is_lvalue_reference_v<_G>); + if constexpr (_Has_ref_member<_G>) { + return {_St_ref::_Member, + noexcept(_Fake_copy_init(declval>().target_id(declval<_G>())))}; + } else if constexpr (_Has_ref_ADL<_G>) { + return {_St_ref::_Non_member, noexcept(_Fake_copy_init(target_id( + declval<_G>(), declval>())))}; // intentional ADL + } else { + return {_St_ref::_None}; + } + } + + template + static constexpr _Choice_t<_St_ref> _Choice_ref = _Choose_ref<_G>(); + + public: + /** + * @brief The number of outgoing edges of a vertex. + * + * Complexity: O(1) + * + * Default implementation: size(edges(g, uv)) + * + * @tparam G The graph type. + * @param g A graph instance. + * @param uv A vertex instance. + * @return The number of outgoing edges of vertex uv. + */ + template + requires(_Choice_ref<_G&>._Strategy != _St_ref::_None) + [[nodiscard]] constexpr auto operator()(_G&& __g, edge_reference_t<_G> uv) const + noexcept(_Choice_ref<_G&>._No_throw) { + constexpr _St_ref _Strat_ref = _Choice_ref<_G&>._Strategy; + + if constexpr (_Strat_ref == _St_ref::_Member) { + return uv.target_id(__g); + } else if constexpr (_Strat_ref == _St_ref::_Non_member) { + return target_id(__g, uv); // intentional ADL + } else { + static_assert(_Always_false<_G>, "target_id(g,uv) or g.target_id(uv) is not defined"); + } + } + }; + } // namespace _Target_id + + inline namespace _Cpos { + inline constexpr _Target_id::_Cpo target_id; } template @@ -2191,7 +2255,7 @@ namespace _Partition_count { { _Fake_copy_init(__g.partition_count()) }; }; template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g) { { _Fake_copy_init(partition_count(__g)) }; // intentional ADL }; @@ -2245,7 +2309,7 @@ namespace _Partition_count { } else if constexpr (_Strat_ref == _St_ref::_Non_member) { return partition_count(__g); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { - return vertex_id_t<_G>(1); // default impl + return vertex_id_t<_G>(1); // default impl } else { static_assert(_Always_false<_G>, "partition_count(g) is not defined and the default implementation cannot be evaluated"); @@ -2331,7 +2395,7 @@ namespace _Partition_vertex_id { }; template - concept _Has_UId_ADL = _Has_class_or_enum_type<_G> // + concept _Has_UId_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, vertex_id_t<_G> uid) { { _Fake_copy_init(partition_vertex_id(__g, uid)) }; // intentional ADL }; @@ -2342,7 +2406,7 @@ namespace _Partition_vertex_id { }; template - concept _Has_UIter_ADL = _Has_class_or_enum_type<_G> // + concept _Has_UIter_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, vertex_iterator_t<_G> ui) { { _Fake_copy_init(partition_vertex_id(__g, ui)) }; // intentional ADL }; @@ -2445,7 +2509,7 @@ namespace _Partition_vertex_id { if constexpr (_Strat == _StIter::_Member) { return __g.partition_vertex_id(ui); } else if constexpr (_Strat == _StIter::_Non_member) { - return partition_vertex_id(__g, ui); // intentional ADL + return partition_vertex_id(__g, ui); // intentional ADL } else { return (*this)(__g, vertex_id(__g, ui)); // use partition_vertex_id(g, vertex_id(g,ui)) } @@ -2475,7 +2539,7 @@ namespace _Find_partition_vertex { }; template - concept _Has_UId_ADL = _Has_class_or_enum_type<_G> // + concept _Has_UId_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, partition_vertex_id_t<_G> puid) { { _Fake_copy_init(find_partition_vertex(__g, puid)) }; // intentional ADL }; @@ -2631,7 +2695,7 @@ namespace _Partition_target_id { }; template - concept _Has_UVRef__ADL = _Has_class_or_enum_type<_G> // + concept _Has_UVRef__ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, edge_reference_t<_G> uv) { { _Fake_copy_init(partition_target_id(__g, uv)) }; // intentional ADL }; @@ -2685,7 +2749,7 @@ namespace _Partition_target_id { if constexpr (_Strat == _StRef::_Member) { return __g.partition_target_id(uv); } else if constexpr (_Strat == _StRef::_Non_member) { - return partition_target_id(__g, uv); // intentional ADL + return partition_target_id(__g, uv); // intentional ADL } else { return partition_vertex_id_t<_G>{0, target_id(__g, uv)}; // assume 1 partition with all vertices } @@ -2715,7 +2779,7 @@ namespace _Partition_source_id { }; template - concept _Has_UVRef__ADL = _Has_class_or_enum_type<_G> // + concept _Has_UVRef__ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, edge_reference_t<_G> uv) { { _Fake_copy_init(partition_source_id(__g, uv)) }; // intentional ADL }; @@ -2769,7 +2833,7 @@ namespace _Partition_source_id { if constexpr (_Strat == _StRef::_Member) { return __g.partition_source_id(uv); } else if constexpr (_Strat == _StRef::_Non_member) { - return partition_source_id(__g, uv); // intentional ADL + return partition_source_id(__g, uv); // intentional ADL } else { return partition_vertex_id_t<_G>{0, source_id(__g, uv)}; // assume 1 partition with all vertices } From eaf3e6082dd886aef42d0eb1bc8651d11c3f9015 Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Sun, 4 Feb 2024 12:38:30 -0500 Subject: [PATCH 5/6] Refactor graph::edgelist::edge_value CPO tag_invoke --> neibloid --- README.md | 3 - include/graph/detail/graph_cpo.hpp | 149 ++++++++++++++--------------- 2 files changed, 71 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 4b3e0b3..628d60d 100644 --- a/README.md +++ b/README.md @@ -106,8 +106,5 @@ is being considered, subject to the size of the proposal and other priorities. Committee ([WG21](https://isocpp.org/std/the-committee)). - Bob Steagal for his [gcc-builder & clang-builder scripts](https://github.com/BobSteagall) - Jason Turner for his [cpp_starter_project](https://github.com/lefticus/cpp_starter_project) -- René Ferdinand Rivera Morell for his [duck_invoke](https://github.com/bfgroup/duck_invoke), an implementation -of tag_invoke ([P1895](https://wg21.link/P1895)) that works for both gcc and msvc. Minor modifications have -been made so it it in the std namespace. - Vincent La for his [cvs-parser](https://github.com/vincentlaucsb/csv-parser) - The ISO C++ Standards Committee (WG21) for [C++](http://eel.is/c++draft/) diff --git a/include/graph/detail/graph_cpo.hpp b/include/graph/detail/graph_cpo.hpp index 2c4e9fb..d838978 100644 --- a/include/graph/detail/graph_cpo.hpp +++ b/include/graph/detail/graph_cpo.hpp @@ -2152,11 +2152,11 @@ namespace edgelist { namespace _Target_id { -# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 - void target_id() = delete; // Block unqualified name lookup -# else // ^^^ no workaround / workaround vvv +# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void target_id() = delete; // Block unqualified name lookup +# else // ^^^ no workaround / workaround vvv void target_id(); -# endif // ^^^ workaround ^^^ +# endif // ^^^ workaround ^^^ template concept _Has_ref_member = requires(_G&& __g, edge_reference_t<_G> uv) { @@ -2227,15 +2227,76 @@ namespace edgelist { using target_id_t = decltype(target_id(declval(), declval>())); - namespace tag_invoke { - TAG_INVOKE_DEF(edge_value); - } + namespace _Edge_value { +# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void edge_value() = delete; // Block unqualified name lookup +# else // ^^^ no workaround / workaround vvv + void edge_value(); +# endif // ^^^ workaround ^^^ - template - auto edge_value(EL&& el, edge_reference_t uv) { - return tag_invoke::edge_value(el, uv); + template + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + && requires(_G&& __g, edge_reference_t<_G> uv) { + { _Fake_copy_init(edge_value(__g, uv)) }; // intentional ADL + }; + template + concept _Can_ref_eval = true; + + class _Cpo { + private: + enum class _St_ref { _None, _Member, _Non_member, _Auto_eval }; + + template + [[nodiscard]] static consteval _Choice_t<_St_ref> _Choose_ref() noexcept { + static_assert(is_lvalue_reference_v<_G>); + if constexpr (_Has_ref_ADL<_G>) { + return {_St_ref::_Non_member, noexcept(_Fake_copy_init(edge_value( + declval<_G>(), declval>())))}; // intentional ADL + } else if constexpr (_Can_ref_eval<_G>) { + return {_St_ref::_Auto_eval, noexcept(_Fake_copy_init(declval>()))}; // intentional ADL + } else { + return {_St_ref::_None}; + } + } + + template + static constexpr _Choice_t<_St_ref> _Choice_ref = _Choose_ref<_G>(); + + public: + /** + * @brief The number of outgoing edges of a vertex. + * + * Complexity: O(1) + * + * Default implementation: uv (edge) if the vertex type is a range; otherwise it must be overridden by the graph + * + * @tparam G The graph type. + * @param g A graph instance. + * @param uv A vertex instance. + * @return The number of outgoing edges of vertex uv. + */ + template + requires(_Choice_ref<_G&>._Strategy != _St_ref::_None) + [[nodiscard]] constexpr auto operator()(_G&& __g, edge_reference_t<_G> uv) const + noexcept(_Choice_ref<_G&>._No_throw) -> decltype(auto) { + constexpr _St_ref _Strat_ref = _Choice_ref<_G&>._Strategy; + + if constexpr (_Strat_ref == _St_ref::_Non_member) { + return edge_value(__g, uv); // intentional ADL + } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { + return uv; // default + } else { + static_assert(_Always_false<_G>, "edge_value(g,uv) must be defined for the graph"); + } + } + }; + } // namespace _Edge_value + + inline namespace _Cpos { + inline constexpr _Edge_value::_Cpo edge_value; } + template using edge_value_t = decltype(edge_value(declval(), declval>())); } // namespace edgelist @@ -2610,74 +2671,6 @@ template using partition_edge_range_t = vertex_edge_range_t; -// -// edges(g,u) -> vertex_edge_range_t -// edges(g,uid) -> vertex_edge_range_t -// default = edges(g,*find_vertex(g,uid)) -// -// vertex_edge_range_t = edges(g,u) -// vertex_edge_iterator_t = ranges::iterator_t> -// edge_t = ranges::range_value_t> -// edge_reference_t = ranges::range_reference_t> -// -# if 0 -namespace tag_invoke { - TAG_INVOKE_DEF(edges); - - template - concept _has_edges_vtxref_part_adl = requires(G&& g, vertex_reference_t u, partition_id_t p) { - { edges(g, u, p) }; - }; - - template - concept _has_edges_vtxid_part_adl = requires(G&& g, vertex_id_t uid, partition_id_t p) { - { edges(g, uid, p) }; - }; -} // namespace tag_invoke - -/** - * @brief Get the outgoing edges of a vertex. - * - * Complexity: O(1) - * - * Default implementation: edges(g,u) - * - * @tparam G The graph type. - * @param g A graph instance. - * @param u Vertex reference. - * @return A range of the outgoing edges. -*/ -template -requires tag_invoke::_has_edges_vtxref_part_adl -auto edges(G&& g, vertex_reference_t u, partition_id_t p) -> decltype(tag_invoke::edges(g, u, p)) { - if constexpr (tag_invoke::_has_edges_vtxref_part_adl) - return tag_invoke::edges(g, u, p); // graph author must define - else - return edges(g, u); -} - -/** - * @brief Get the outgoing edges of a vertex id. - * - * Complexity: O(1) - * - * Default implementation: edges(g, *find_vertex(g, uid), p) - * - * @tparam G The graph type. - * @param g A graph instance. - * @param uid Vertex id. - * @return A range of the outgoing edges. -*/ -template -requires tag_invoke::_has_edges_vtxid_part_adl -auto edges(G&& g, vertex_id_t uid, partition_id_t p) -> decltype(tag_invoke::edges(g, uid, p)) { - if constexpr (tag_invoke::_has_edges_vtxid_part_adl) - return tag_invoke::edges(g, uid, p); - else - return edges(g, *find_vertex(g, uid), p); -} -# endif - // // partition_target_id(g,puid) -> partition_vertex_id_t<_G> // default = partition_vertex_id_t{0, target_id(__g, uv)} From 3d058e7a771609c1249d5c3e6649103f566ab8e2 Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Wed, 7 Feb 2024 20:56:21 -0500 Subject: [PATCH 6/6] Minor cosmetic changes Fix comment indentation Replace "tag_invoke properties" with "CPO properties" in comments Update ToDo.md --- ToDo.md | 82 +++++---- include/graph/container/compressed_graph.hpp | 7 +- include/graph/container/dynamic_graph.hpp | 10 +- include/graph/views/depth_first_search.hpp | 171 ++++++++++--------- 4 files changed, 142 insertions(+), 128 deletions(-) diff --git a/ToDo.md b/ToDo.md index ee19fdd..1aed436 100644 --- a/ToDo.md +++ b/ToDo.md @@ -20,14 +20,15 @@ ## Open ### ToDo -- Graph API +- Graph Container Interface (GCI) - [ ] Common - - [ ] Apply tag_invoke design in P2300 [wait to see if we want to use tag_invoke] + - [ ] Use Neibloid style for all CPOs - [x] Ranges - [ ] Concepts and type_traits - - [x] graph: adjacency_list, sourced_adjacency_list, adjacency_matrix, undirected_incidence_graph + - [x] graph: adjacency_list, sourced_adjacency_list, adjacency_matrix - [ ] **view concepts: vertex_view, edge_view, neighbor_view returned from graph views** - [ ] **function concepts: VVF, EVF** + - [ ] Edgelist concept(s) - [ ] Graph API - [ ] depth() CPO? bfs, dfs. size() is different; depth for BFS takes extra work and is diff concept. - [x] cancel() CPO? bfs, dfs: no, member only @@ -37,24 +38,29 @@ - [x] view functions should be in std::graph::view - [ ] add range overloads to appropriate views (DFS, BFS, topo_sort, etc.) - [ ] vertexlist - - [ ] Copy VVF to iterator (not reference) - - [ ] Accept VVF(g,u) & allow vertex_value? + - [ ] Use VVF&& instead of const VVF& - [x] verify it is a std\::ranges\::view<> - [x] Implement vertexlist(g,vr) - [x] Implement vertexlist(g,vr,vvf) + - [ ] Implement basic_vertexlist(g,vr) + - [ ] Implement basic_vertexlist(g,vr,vvf) + - [ ] Extend support for vvf(uid), in addition to vvf(u) - [ ] incidence - - [ ] Copy EVF to iterator (not reference) + - [ ] Use EVF&& instead of const EVF& - [ ] unit tests for undirected_graph\ - [x] verify it is a std\::ranges\::view<> - [ ] neighbors - - [ ] Copy VVF to iterator (not reference) + - [ ] Use VVF&& instead of const VVF& + - [ ] Extend support for vvf(uid), in addition to vvf(u) - [ ] unit tests for undirected_graph\ - [x] verify it is a std\::ranges\::view<> + - [ ] Implement basic_neighbors(g,vr) + - [ ] Implement basic_neighbors(g,vr,vvf) - [ ] edgelist - - [ ] Copy EVF to iterator (not reference) + - [ ] Use EVF&& instead of const EVF& - [ ] unit tests for undirected_graph\ - [x] verify it is a std\::ranges\::view<> - - [x] vertices_depth_first_search_view + - [x] vertices_dfs_view - [x] validate results & add unit tests - [x] support Cancelable - [x] support VVF @@ -63,8 +69,8 @@ - [x] verify it is a std::ranges::view<> - [x] create CPOs - [x] Use real_target_id(g,uv,src) for both directed_incidence_graph & undirected_incidence_graph to consolidate code - - [x] Add allocator parameter & use with _colors - - [x] edges_depth_first_search_view + - [ ] basic_vertices_dfs_view + - [x] edges_dfs_view - [x] validate results & add unit tests - [x] support Cancelable - [x] support EVF @@ -73,32 +79,43 @@ - [x] support begin, end, depth/size, empty, swap free functions - [x] verify it is a std::ranges::view<> - [x] create CPOs: edges, sourced_edges - - [x] Use real_target_id(g,uv,src) for both directed_incidence_graph & undirected_incidence_graph to consolidate code - - [x] Add allocator parameter & use with _colors - - [ ] **bfs_vertex_range** - - [ ] **bfs_edge_range** - - [ ] topological_sort_vertex_range - - [ ] topological_sort_edge_range + - [ ] basic__edges_dfs_view + - [ ] vertices_bfs_view + - [ ] edges_bfs_view + - [ ] topological_sort_vertices_view + - [ ] topological_sort_edges_view - [ ] allow options to exclude vertex/edge reference on results (Andrew) + - [ ] Common + - [ ] Add depth(search) CPO for dfs, bfs, topo_sort + - [ ] Add size(search) CPO for dfs, bfs, topo_sort - Algorithms - - [ ] Common - - [ ] Add depth(search) CPO for dfs, bfs, topo_sort - - [ ] Add size(search) CPO for dfs, bfs, topo_sort - [ ] Algorithms (full & simplified/book) - - [ ] Shortest Paths - - [x] Dijkstra book (impl from AndrewL) - - [ ] **dijkstra_shortest_path** - - [ ] **bellman_ford_shortest_path** + - [x] Shortest Paths + - [x] Dijkstra_clrs (book impl from AndrewL) + - [x] dijkstra_shortest_path + - [x] bellman_ford_shortest_path + - [ ] Clustering + - [ ] Triangle counting + - [ ] Communities + - [ ] Label propagation - [ ] Components - [ ] connected_components - - [ ] strongly_connected_components + - [ ] strongly_connected_components (Kosaraju & Tarjan) - [ ] biconnected_components - [ ] articulation_points + - [ ] Directed Acyclic Graphs + - [ ] Topological Sort, Single Source + - [ ] Maximal Independent Set + - [ ] Maximal Independent Set + - [ ] Link Analysis + - [ ] Jaccard Coefficient + - [ ] Minimal Spanning Tree + - [ ] Kruskal Minimum Spanning Tree + - [ ] Prim Minimal Spanning Tree - [ ] Others to consider + - [ ] page_rank; not a good candidate for the standard because there are too many options; better as an example - [ ] Edgelist algorithms (prove design; not for P1709) - - [ ] Maximal Independent Set (edgelist) - [ ] Union Find (edgelist) - - [ ] page_rank - [ ] betweenness_centrality - [ ] triangle_count - [ ] Minimum spanning tree @@ -118,16 +135,13 @@ - [ ] validate & add unit tests - Graph Containers (data structures) - [x] compressed_graph (for P1709) - - [ ] **Use concepts for load, load_edges, load_vertices, ctors** - - [x] Support VV=void - - [x] Support EV=void - - [x] Use copyable_vertex & copyable_edge concepts in graph ctors, load functions - - [x] Add ctor with initializer_list for simple demo + - [ ] Implement load_graph(), load_vertices(), load_edges() CPOs (define concepts) - [ ] dynamic_graph - - [ ] **Use concepts for load, load_edges, load_vertices, ctors** + - [ ] Implement load_graph(), load_vertices(), load_edges() CPOs (define concepts) - [ ] test push_or_insert() to assure it does the right thing for const, value, &, &&, ... - [ ] graph with map-based vertices (requires different algorithm impl) - [x] Use copyable_vertex & copyable_edge concepts in graph ctors, load functions + - [ ] Support non-integral vertex_ids - [ ] constexpr graph based on std::array - [ ] undirected_adjacency_list - [x] directed_adjacency_vector (retired) @@ -168,6 +182,8 @@ - C\+\+20 and C\+\+23 - [ ] modules - [ ] coroutines (simplify DFS, BFS & TopoSort?) +- [ ] Examples + - [ ] ABC - Documentation - [x] Decprecate original "graph" repository - [ ] README.md diff --git a/include/graph/container/compressed_graph.hpp b/include/graph/container/compressed_graph.hpp index c0a57b0..ab0d21d 100644 --- a/include/graph/container/compressed_graph.hpp +++ b/include/graph/container/compressed_graph.hpp @@ -738,7 +738,7 @@ class compressed_graph_base //v_vector_type v_; // v_[n] holds the edge value for col_index_[n] //row_values_type row_value_; // row_value_[r] holds the value for row_index_[r], for VV!=void -private: // tag_invoke properties +private: // CPO properties friend constexpr vertices_type vertices(compressed_graph_base& g) { if (g.row_index_.empty()) return vertices_type(g.row_index_); // really empty @@ -908,7 +908,7 @@ class compressed_graph : public compressed_graph_base>& ilist, const Alloc& alloc = Alloc()) : base_type(ilist, alloc) {} -private: // tag_invoke properties +private: // CPO 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_; } @@ -969,9 +969,6 @@ class compressed_graph constexpr compressed_graph(const initializer_list>& ilist, const Alloc& alloc = Alloc()) : base_type(ilist, alloc) {} - -public: // Operations -private: // tag_invoke properties }; } // namespace std::graph::container diff --git a/include/graph/container/dynamic_graph.hpp b/include/graph/container/dynamic_graph.hpp index 5bd0b0a..37425ca 100644 --- a/include/graph/container/dynamic_graph.hpp +++ b/include/graph/container/dynamic_graph.hpp @@ -376,7 +376,7 @@ class dynamic_edge_value { private: value_type value_ = value_type(); -private: // tag_invoke properties +private: // CPO properties friend constexpr value_type& edge_value(graph_type& g, edge_type& uv) noexcept { return uv.value_; } friend constexpr const value_type& edge_value(const graph_type& g, const edge_type& uv) noexcept { return uv.value_; } }; @@ -678,7 +678,7 @@ class dynamic_vertex_base { private: edges_type edges_; -private: // tag_invoke properties +private: // CPO properties 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_; } @@ -748,7 +748,7 @@ class dynamic_vertex : public dynamic_vertex_base - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid, _Alloc alloc) { { _Fake_copy_init(vertices_depth_first_search(__g, uid, alloc)) }; // intentional ADL }; @@ -721,16 +721,16 @@ namespace views { public: /** - * @brief Single Source, Breadth First Search for vertices - * - * Complexity: O(V + E) - * - * @tparam G The graph type. - * @tparam Alloc The allocator type. - * @param g A graph instance. - * @param seed The vertex id to start the search. - * @return A forward range for the breadth first search. - */ + * @brief Single Source, Breadth First Search for vertices + * + * Complexity: O(V + E) + * + * @tparam G The graph type. + * @tparam Alloc The allocator type. + * @param g A graph instance. + * @param seed The vertex id to start the search. + * @return A forward range for the breadth first search. + */ template > requires(_Choice_ref<_G&, _Alloc>._Strategy != _St_ref::_None) [[nodiscard]] constexpr auto operator()(_G&& __g, const vertex_id_t<_G>& seed, _Alloc alloc = _Alloc()) const @@ -738,7 +738,7 @@ namespace views { constexpr _St_ref _Strat_ref = _Choice_ref<_G&, _Alloc>._Strategy; if constexpr (_Strat_ref == _St_ref::_Non_member) { - return vertices_depth_first_search(__g, seed, alloc); // intentional ADL + return vertices_depth_first_search(__g, seed, alloc); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { return vertices_depth_first_search_view<_G, void>(__g, seed, alloc); // default impl } else { @@ -749,20 +749,20 @@ namespace views { } /** - * @brief Single Source, Breadth First Search for vertices with VVF - * - * Complexity: O(V + E) - * - * @tparam G The graph type. - * @tparam VVF The vertex value function type. - * @tparam Alloc The allocator type. - * - * @param g A graph instance. - * @param vvf The vertex value function. - * @param seed The vertex id to start the search. - * - * @return A forward range for the breadth first search. - */ + * @brief Single Source, Breadth First Search for vertices with VVF + * + * Complexity: O(V + E) + * + * @tparam G The graph type. + * @tparam VVF The vertex value function type. + * @tparam Alloc The allocator type. + * + * @param g A graph instance. + * @param vvf The vertex value function. + * @param seed The vertex id to start the search. + * + * @return A forward range for the breadth first search. + */ template > requires(_Choice_ref_vvf<_G&, _VVF, _Alloc>._Strategy != _St_ref_vvf::_None) [[nodiscard]] constexpr auto @@ -771,7 +771,7 @@ namespace views { constexpr _St_ref_vvf _Strat_ref_vvf = _Choice_ref_vvf<_G&, _VVF, _Alloc>._Strategy; if constexpr (_Strat_ref_vvf == _St_ref_vvf::_Non_member) { - return vertices_depth_first_search(__g, seed, vvf, alloc); // intentional ADL + return vertices_depth_first_search(__g, seed, vvf, alloc); // intentional ADL } else if constexpr (_Strat_ref_vvf == _St_ref_vvf::_Auto_eval) { return vertices_depth_first_search_view<_G, _VVF>(__g, seed, vvf, alloc); // default impl } else { @@ -800,7 +800,7 @@ namespace views { # endif // ^^^ workaround ^^^ template - concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid, _Alloc alloc) { { _Fake_copy_init(edges_depth_first_search(__g, uid, alloc)) }; // intentional ADL }; @@ -870,18 +870,18 @@ namespace views { public: /** - * @brief Single Source, Breadth First Search for edges - * - * Complexity: O(V + E) - * - * @tparam G The graph type. - * @tparam Alloc The allocator type. - * - * @param g A graph instance. - * @param seed The vertex id to start the search. - * - * @return A forward range for the breadth first search. - */ + * @brief Single Source, Breadth First Search for edges + * + * Complexity: O(V + E) + * + * @tparam G The graph type. + * @tparam Alloc The allocator type. + * + * @param g A graph instance. + * @param seed The vertex id to start the search. + * + * @return A forward range for the breadth first search. + */ template > requires(_Choice_ref<_G&, _Alloc>._Strategy != _St_ref::_None) [[nodiscard]] constexpr auto operator()(_G&& __g, const vertex_id_t<_G>& seed, _Alloc alloc = _Alloc()) const @@ -889,7 +889,7 @@ namespace views { constexpr _St_ref _Strat_ref = _Choice_ref<_G&, _Alloc>._Strategy; if constexpr (_Strat_ref == _St_ref::_Non_member) { - return edges_depth_first_search(__g, seed, alloc); // intentional ADL + return edges_depth_first_search(__g, seed, alloc); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { return edges_depth_first_search_view<_G, void, false>(__g, seed, alloc); // default impl } else { @@ -900,20 +900,20 @@ namespace views { } /** - * @brief Single Source, Breadth First Search for edges with EVF - * - * Complexity: O(V + E) - * - * @tparam G The graph type. - * @tparam EVF The vertex value function type. - * @tparam Alloc The allocator type. - * - * @param g A graph instance. - * @param evf The vertex value function. - * @param seed The vertex id to start the search. - * - * @return A forward range for the breadth first search. - */ + * @brief Single Source, Breadth First Search for edges with EVF + * + * Complexity: O(V + E) + * + * @tparam G The graph type. + * @tparam EVF The vertex value function type. + * @tparam Alloc The allocator type. + * + * @param g A graph instance. + * @param evf The vertex value function. + * @param seed The vertex id to start the search. + * + * @return A forward range for the breadth first search. + */ template > requires(_Choice_ref_evf<_G&, _EVF, _Alloc>._Strategy != _St_ref_evf::_None) [[nodiscard]] constexpr auto @@ -922,7 +922,7 @@ namespace views { constexpr _St_ref_evf _Strat_ref_evf = _Choice_ref_evf<_G&, _EVF, _Alloc>._Strategy; if constexpr (_Strat_ref_evf == _St_ref_evf::_Non_member) { - return edges_depth_first_search(__g, seed, alloc); // intentional ADL + return edges_depth_first_search(__g, seed, alloc); // intentional ADL } else if constexpr (_Strat_ref_evf == _St_ref_evf::_Auto_eval) { return edges_depth_first_search_view<_G, _EVF, false>(__g, seed, evf, alloc); // default impl } else { @@ -1023,18 +1023,18 @@ namespace views { public: /** - * @brief Single Source, Breadth First Search for source edges - * - * Complexity: O(V + E) - * - * @tparam G The graph type. - * @tparam Alloc The allocator type. - * - * @param g A graph instance. - * @param seed The vertex id to start the search. - * - * @return A forward range for the breadth first search. - */ + * @brief Single Source, Breadth First Search for source edges. + * + * Complexity: O(V + E) + * + * @tparam G The graph type. + * @tparam Alloc The allocator type. + * + * @param g A graph instance. + * @param seed The vertex id to start the search. + * + * @return A forward range for the breadth first search. + */ template > requires(_Choice_ref<_G&, _Alloc>._Strategy != _St_ref::_None) [[nodiscard]] constexpr auto operator()(_G&& __g, const vertex_id_t<_G>& seed, _Alloc alloc = _Alloc()) const @@ -1042,7 +1042,7 @@ namespace views { constexpr _St_ref _Strat_ref = _Choice_ref<_G&, _Alloc>._Strategy; if constexpr (_Strat_ref == _St_ref::_Non_member) { - return sourced_edges_depth_first_search(__g, seed, alloc); // intentional ADL + return sourced_edges_depth_first_search(__g, seed, alloc); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { return edges_depth_first_search_view<_G, void, true>(__g, seed, alloc); // default impl } else { @@ -1052,21 +1052,22 @@ namespace views { } } + /** - * @brief Single Source, Breadth First Search for edges with EVF - * - * Complexity: O(V + E) - * - * @tparam G The graph type. - * @tparam EVF The vertex value function type. - * @tparam Alloc The allocator type. - * - * @param g A graph instance. - * @param evf The vertex value function. - * @param seed The vertex id to start the search. - * - * @return A forward range for the breadth first search. - */ + * @brief Single Source, Breadth First Search for edges with EVF + * + * Complexity: O(V + E) + * + * @tparam G The graph type. + * @tparam EVF The vertex value function type. + * @tparam Alloc The allocator type. + * + * @param g A graph instance. + * @param evf The vertex value function. + * @param seed The vertex id to start the search. + * + * @return A forward range for the breadth first search. + */ template > requires(_Choice_ref_evf<_G&, _EVF, _Alloc>._Strategy != _St_ref_evf::_None) [[nodiscard]] constexpr auto @@ -1075,7 +1076,7 @@ namespace views { constexpr _St_ref_evf _Strat_ref_evf = _Choice_ref_evf<_G&, _EVF, _Alloc>._Strategy; if constexpr (_Strat_ref_evf == _St_ref_evf::_Non_member) { - return sourced_edges_depth_first_search(__g, seed, alloc); // intentional ADL + return sourced_edges_depth_first_search(__g, seed, alloc); // intentional ADL } else if constexpr (_Strat_ref_evf == _St_ref_evf::_Auto_eval) { return edges_depth_first_search_view<_G, _EVF, true>(__g, seed, evf, alloc); // default impl } else {