diff --git a/include/graph/detail/graph_cpo.hpp b/include/graph/detail/graph_cpo.hpp index 2022052..493f7ca 100644 --- a/include/graph/detail/graph_cpo.hpp +++ b/include/graph/detail/graph_cpo.hpp @@ -343,7 +343,7 @@ namespace _Vertex_id { } else if constexpr (_Strat_ref == _St_ref::_Non_member) { return vertex_id(__g, ui); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { - return ui - ranges::begin(vertices(__g)); + return static_cast(ui - ranges::begin(vertices(__g))); } else { static_assert(_Always_false<_G>, "vertices(g) is not defined or is not random-access"); } diff --git a/include/graph/views/depth_first_search.hpp b/include/graph/views/depth_first_search.hpp index de108ed..852433a 100644 --- a/include/graph/views/depth_first_search.hpp +++ b/include/graph/views/depth_first_search.hpp @@ -34,23 +34,13 @@ namespace std::graph { -/** - * @brief The element in a depth-first search stack. -*/ -template -struct dfs_element { - vertex_id_t u_id; - vertex_edge_iterator_t uv; -}; - /** * @brief Depth-first search view for vertices, given a single seed vertex. * * @tparam G Graph type - * @tparam Stack Stack type for internal use * @tparam Alloc Allocator type */ -template +template requires ranges::random_access_range> && integral> class dfs_base : public ranges::view_base { public: @@ -64,8 +54,13 @@ class dfs_base : public ranges::view_base { using edge_iterator = vertex_edge_iterator_t; private: + struct stack_elem { + vertex_id_t u_id; + vertex_edge_iterator_t uv; + }; + using Stack = stack; + using graph_ref_type = reference_wrapper; - using stack_elem = dfs_element; using parent_alloc = typename allocator_traits::template rebind_alloc< vertex_id_type>; @@ -191,14 +186,13 @@ class dfs_base : public ranges::view_base { * * @tparam G Graph type * @tparam VVF Vertex Value Function type - * @tparam Stack Stack type for internal use * @tparam Alloc Allocator type */ -template >, class Alloc = allocator> +template > requires ranges::random_access_range> && integral> -class vertices_depth_first_search_view : public dfs_base { +class vertices_depth_first_search_view : public dfs_base { public: - using base_type = dfs_base; + using base_type = dfs_base; using graph_type = G; using vertex_type = vertex_t; using vertex_id_type = vertex_id_t; @@ -206,9 +200,9 @@ class vertices_depth_first_search_view : public dfs_base { using vertex_iterator = vertex_iterator_t; using edge_reference = edge_reference_t; using edge_iterator = vertex_edge_iterator_t; - using dfs_range_type = vertices_depth_first_search_view; + using dfs_range_type = vertices_depth_first_search_view; - using vertex_value_func = VVF; + using vertex_value_func = remove_reference_t; using vertex_value_type = invoke_result_t; public: @@ -308,15 +302,15 @@ class vertices_depth_first_search_view : public dfs_base { auto cend() const { return end_sentinel(); } private: - const VVF* value_fn_ = nullptr; + const vertex_value_func* value_fn_ = nullptr; }; -template +template requires ranges::random_access_range> && integral> -class vertices_depth_first_search_view : public dfs_base { +class vertices_depth_first_search_view : public dfs_base { public: - using base_type = dfs_base; + using base_type = dfs_base; using graph_type = G; using vertex_type = vertex_t; using vertex_id_type = vertex_id_t; @@ -324,7 +318,7 @@ class vertices_depth_first_search_view : public dfs_base< using vertex_iterator = vertex_iterator_t; using edge_reference = edge_reference_t; using edge_iterator = vertex_edge_iterator_t; - using dfs_range_type = vertices_depth_first_search_view; + using dfs_range_type = vertices_depth_first_search_view; public: vertices_depth_first_search_view(graph_type& g, vertex_id_type seed, const Alloc& alloc = Alloc()) @@ -424,25 +418,20 @@ class vertices_depth_first_search_view : public dfs_base< * @tparam G Graph type * @tparam EVF Edge Value Function type * @tparam Sourced Does graph G support @c source_id()? - * @tparam Stack Stack type for use internally * @tparam Alloc Allocator type */ -template >, - class Alloc = allocator> +template > requires ranges::random_access_range> && integral> -class edges_depth_first_search_view : public dfs_base { +class edges_depth_first_search_view : public dfs_base { public: - using base_type = dfs_base; + using base_type = dfs_base; using graph_type = G; using vertex_id_type = vertex_id_t; using vertex_iterator = vertex_iterator_t; using edge_reference_type = edge_reference_t; - using dfs_range_type = edges_depth_first_search_view; + using dfs_range_type = edges_depth_first_search_view; - using edge_value_func = EVF; + using edge_value_func = remove_reference_t; using edge_value_type = invoke_result_t; public: @@ -541,19 +530,19 @@ class edges_depth_first_search_view : public dfs_base { auto cend() const { return end_sentinel(); } private: - const EVF* value_fn_ = nullptr; + const edge_value_func* value_fn_ = nullptr; }; -template +template requires ranges::random_access_range> && integral> -class edges_depth_first_search_view : public dfs_base { +class edges_depth_first_search_view : public dfs_base { public: - using base_type = dfs_base; + using base_type = dfs_base; using graph_type = G; using vertex_id_type = vertex_id_t; using vertex_iterator = vertex_iterator_t; using edge_reference_type = edge_reference_t; - using dfs_range_type = edges_depth_first_search_view; + using dfs_range_type = edges_depth_first_search_view; public: edges_depth_first_search_view(G& g, vertex_id_type seed, const Alloc& alloc = Alloc()) : base_type(g, seed, alloc) {} @@ -649,6 +638,497 @@ class edges_depth_first_search_view : public dfs }; } // namespace std::graph + +# if 1 + +namespace std::graph::views { +// +// vertices_depth_first_search(g,seed) -> vertex_descriptor[vid,v] +// vertices_depth_first_search(g,seed,vvf) -> vertex_descriptor[vid,v,value] +// +namespace _Vertices_DFS { +# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void vertices_depth_first_search() = delete; // Block unqualified name lookup +# else // ^^^ no workaround / workaround vvv + void vertices_depth_first_search(); +# endif // ^^^ workaround ^^^ + + template + 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 + }; + template + concept _Can_ref_eval = index_adjacency_list<_G> // + && requires(_G&& __g, vertex_id_t<_G> uid, _Alloc alloc) { + { _Fake_copy_init(vertices_depth_first_search_view<_G, void>(__g, uid, alloc)) }; + }; + + template + concept _Has_ref_vvf_ADL = _Has_class_or_enum_type<_G> // + && invocable<_VVF, vertex_reference_t<_G>> // + && requires(_G&& __g, const vertex_id_t<_G>& uid, _VVF vvf, _Alloc alloc) { + { + _Fake_copy_init(vertices_depth_first_search(__g, uid, vvf, alloc)) + }; // intentional ADL + }; + template + concept _Can_ref_vvf_eval = index_adjacency_list<_G> // + && invocable<_VVF, vertex_reference_t<_G>> // + && requires(_G&& __g, vertex_id_t<_G> uid, _VVF vvf, _Alloc alloc) { + { + _Fake_copy_init(vertices_depth_first_search_view<_G, _VVF>(__g, uid, vvf, alloc)) + }; + }; + + class _Cpo { + private: + enum class _St_ref { _None, _Non_member, _Auto_eval }; + enum class _St_ref_vvf { _None, _Non_member, _Auto_eval }; + + template + [[nodiscard]] static consteval _Choice_t<_St_ref> _Choose_ref() noexcept { + //static_assert(is_lvalue_reference_v<_G>); + using _UnCV = remove_cvref_t<_G>; + + if constexpr (_Has_ref_ADL<_G, _Alloc, _UnCV>) { + return {_St_ref::_Non_member, + noexcept(_Fake_copy_init(vertices_depth_first_search(declval<_G>(), declval>(), + declval<_Alloc>())))}; // intentional ADL + } else if constexpr (_Can_ref_eval<_G, _Alloc, _UnCV>) { + return {_St_ref::_Auto_eval, noexcept(_Fake_copy_init(vertices_depth_first_search_view<_G, void>( + declval<_G>(), declval>(), declval<_Alloc>())))}; + } else { + return {_St_ref::_None}; + } + } + + template + static constexpr _Choice_t<_St_ref> _Choice_ref = _Choose_ref<_G, _Alloc>(); + + template + [[nodiscard]] static consteval _Choice_t<_St_ref_vvf> _Choose_ref_vvf() noexcept { + //static_assert(is_lvalue_reference_v<_G>); + using _UnCV = remove_cvref_t<_G>; + + if constexpr (_Has_ref_vvf_ADL<_G, _VVF, _Alloc, _UnCV>) { + return {_St_ref_vvf::_Non_member, noexcept(_Fake_copy_init(vertices_depth_first_search( + declval<_G>(), declval>(), declval<_VVF>(), + declval<_Alloc>())))}; // intentional ADL + } else if constexpr (_Can_ref_vvf_eval<_G, _VVF, _Alloc, _UnCV>) { + return {_St_ref_vvf::_Auto_eval, + noexcept(_Fake_copy_init(vertices_depth_first_search_view<_G, _VVF>( + declval<_G>(), declval>(), declval<_VVF>(), declval<_Alloc>())))}; + } else { + return {_St_ref_vvf::_None}; + } + } + + template + static constexpr _Choice_t<_St_ref_vvf> _Choice_ref_vvf = _Choose_ref_vvf<_G, _VVF, _Alloc>(); + + 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. + */ + 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 + noexcept(_Choice_ref<_G&, _Alloc>._No_throw) { + 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 + } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { + return vertices_depth_first_search_view<_G, void>(__g, seed, alloc); // default impl + } else { + static_assert(_Always_false<_G>, "The default implementation of " + "vertices_depth_first_search(g,seed,alloc) cannot be evaluated and " + "there is no override defined for the graph."); + } + } + + /** + * @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 + operator()(_G&& __g, const vertex_id_t<_G>& seed, _VVF&& vvf, _Alloc alloc = _Alloc()) const + noexcept(_Choice_ref_vvf<_G&, _VVF, _Alloc>._No_throw) { + 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 + } 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 { + static_assert(_Always_false<_G>, "The default implementation of " + "vertices_depth_first_search(g,seed,vvf,alloc) cannot be evaluated and " + "there is no override defined for the graph."); + } + } + }; +} // namespace _Vertices_DFS + +inline namespace _Cpos { + inline constexpr _Vertices_DFS::_Cpo vertices_depth_first_search; +} + + +// +// edges_depth_first_search(g,seed) -> edge_descriptor[vid,uv] +// edges_depth_first_search(g,seed,evf) -> edge_descriptor[vid,uv,value] +// +namespace _Edges_DFS { +# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void edges_depth_first_search() = delete; // Block unqualified name lookup +# else // ^^^ no workaround / workaround vvv + void edges_depth_first_search(); +# endif // ^^^ workaround ^^^ + + template + 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 + }; + template + concept _Can_ref_eval = index_adjacency_list<_G> // + && requires(_G&& __g, vertex_id_t<_G> uid, _Alloc alloc) { + { _Fake_copy_init(edges_depth_first_search_view<_G, void, false>(__g, uid, alloc)) }; + }; + + template + concept _Has_ref_evf_ADL = _Has_class_or_enum_type<_G> // + && invocable<_EVF, edge_reference_t<_G>> // + && requires(_G&& __g, const vertex_id_t<_G>& uid, _EVF evf, _Alloc alloc) { + { + _Fake_copy_init(edges_depth_first_search(__g, uid, evf, alloc)) + }; // intentional ADL + }; + template + concept _Can_ref_evf_eval = + index_adjacency_list<_G> // + && invocable<_EVF, edge_reference_t<_G>> // + && requires(_G&& __g, vertex_id_t<_G> uid, _EVF evf, _Alloc alloc) { + { _Fake_copy_init(edges_depth_first_search_view<_G, _EVF, false>(__g, uid, evf, alloc)) }; + }; + + class _Cpo { + private: + enum class _St_ref { _None, _Non_member, _Auto_eval }; + enum class _St_ref_evf { _None, _Non_member, _Auto_eval }; + + template + [[nodiscard]] static consteval _Choice_t<_St_ref> _Choose_ref() noexcept { + //static_assert(is_lvalue_reference_v<_G>); + using _UnCV = remove_cvref_t<_G>; + + if constexpr (_Has_ref_ADL<_G, _Alloc, _UnCV>) { + return {_St_ref::_Non_member, + noexcept(_Fake_copy_init(edges_depth_first_search(declval<_G>(), declval>(), + declval<_Alloc>())))}; // intentional ADL + } else if constexpr (_Can_ref_eval<_G, _Alloc, _UnCV>) { + return {_St_ref::_Auto_eval, noexcept(_Fake_copy_init(edges_depth_first_search_view<_G, void, false>( + declval<_G>(), declval>(), declval<_Alloc>())))}; + } else { + return {_St_ref::_None}; + } + } + + template + static constexpr _Choice_t<_St_ref> _Choice_ref = _Choose_ref<_G, _Alloc>(); + + template + [[nodiscard]] static consteval _Choice_t<_St_ref_evf> _Choose_ref_evf() noexcept { + //static_assert(is_lvalue_reference_v<_G>); + using _UnCV = remove_cvref_t<_G>; + + if constexpr (_Has_ref_evf_ADL<_G, _EVF, _Alloc, _UnCV>) { + return {_St_ref_evf::_Non_member, noexcept(_Fake_copy_init(edges_depth_first_search( + declval<_G>(), declval>(), declval<_EVF>(), + declval<_Alloc>())))}; // intentional ADL + } else if constexpr (_Can_ref_evf_eval<_G, _EVF, _Alloc, _UnCV>) { + return {_St_ref_evf::_Auto_eval, + noexcept(_Fake_copy_init(edges_depth_first_search_view<_G, _EVF, false>( + declval<_G>(), declval>(), declval<_EVF>(), declval<_Alloc>())))}; + } else { + return {_St_ref_evf::_None}; + } + } + + template + static constexpr _Choice_t<_St_ref_evf> _Choice_ref_evf = _Choose_ref_evf<_G, _EVF, _Alloc>(); + + 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. + */ + 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 + noexcept(_Choice_ref<_G&, _Alloc>._No_throw) { + 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 + } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { + return edges_depth_first_search_view<_G, void, false>(__g, seed, alloc); // default impl + } else { + static_assert(_Always_false<_G>, "The default implementation of " + "edges_depth_first_search(g,seed,alloc) cannot be evaluated and " + "there is no override defined for the graph."); + } + } + + /** + * @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 + operator()(_G&& __g, const vertex_id_t<_G>& seed, _EVF&& evf, _Alloc alloc = _Alloc()) const + noexcept(_Choice_ref_evf<_G&, _EVF, _Alloc>._No_throw) { + 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 + } 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 { + static_assert(_Always_false<_G>, "The default implementation of " + "edges_depth_first_search(g,seed,evf,alloc) cannot be evaluated and " + "there is no override defined for the graph."); + } + } + }; +} // namespace _Edges_DFS + +inline namespace _Cpos { + inline constexpr _Edges_DFS::_Cpo edges_depth_first_search; +} + + +// +// sourced_edges_depth_first_search(g,seed) -> edge_descriptor[uid,vid,uv] +// sourced_edges_depth_first_search(g,seed,evf) -> edge_descriptor[uid,vid,uv,value] +// +namespace _Sourced_Edges_DFS { +# if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void sourced_edges_depth_first_search() = delete; // Block unqualified name lookup +# else // ^^^ no workaround / workaround vvv + void sourced_edges_depth_first_search(); +# endif // ^^^ workaround ^^^ + + template + concept _Has_ref_ADL = _Has_class_or_enum_type<_G> // + && requires(_G&& __g, const vertex_id_t<_G>& uid, _Alloc alloc) { + { _Fake_copy_init(sourced_edges_depth_first_search(__g, uid, alloc)) }; // intentional ADL + }; + template + concept _Can_ref_eval = index_adjacency_list<_G> // + && requires(_G&& __g, vertex_id_t<_G> uid, _Alloc alloc) { + { _Fake_copy_init(edges_depth_first_search_view<_G, void, true>(__g, uid, alloc)) }; + }; + + template + concept _Has_ref_evf_ADL = _Has_class_or_enum_type<_G> // + && invocable<_EVF, edge_reference_t<_G>> // + && requires(_G&& __g, const vertex_id_t<_G>& uid, _EVF evf, _Alloc alloc) { + { + _Fake_copy_init(sourced_edges_depth_first_search(__g, uid, evf, alloc)) + }; // intentional ADL + }; + template + concept _Can_ref_evf_eval = + index_adjacency_list<_G> // + && invocable<_EVF, edge_reference_t<_G>> // + && requires(_G&& __g, vertex_id_t<_G> uid, _EVF evf, _Alloc alloc) { + { _Fake_copy_init(edges_depth_first_search_view<_G, _EVF, true>(__g, uid, evf, alloc)) }; + }; + + class _Cpo { + private: + enum class _St_ref { _None, _Non_member, _Auto_eval }; + enum class _St_ref_evf { _None, _Non_member, _Auto_eval }; + + template + [[nodiscard]] static consteval _Choice_t<_St_ref> _Choose_ref() noexcept { + //static_assert(is_lvalue_reference_v<_G>); + using _UnCV = remove_cvref_t<_G>; + + if constexpr (_Has_ref_ADL<_G, _Alloc, _UnCV>) { + return {_St_ref::_Non_member, + noexcept(_Fake_copy_init(sourced_edges_depth_first_search(declval<_G>(), declval>(), + declval<_Alloc>())))}; // intentional ADL + } else if constexpr (_Can_ref_eval<_G, _Alloc, _UnCV>) { + return {_St_ref::_Auto_eval, noexcept(_Fake_copy_init(edges_depth_first_search_view<_G, void, true>( + declval<_G>(), declval>(), declval<_Alloc>())))}; + } else { + return {_St_ref::_None}; + } + } + + template + static constexpr _Choice_t<_St_ref> _Choice_ref = _Choose_ref<_G, _Alloc>(); + + template + [[nodiscard]] static consteval _Choice_t<_St_ref_evf> _Choose_ref_evf() noexcept { + //static_assert(is_lvalue_reference_v<_G>); + using _UnCV = remove_cvref_t<_G>; + + if constexpr (_Has_ref_evf_ADL<_G, _EVF, _Alloc, _UnCV>) { + return {_St_ref_evf::_Non_member, noexcept(_Fake_copy_init(sourced_edges_depth_first_search( + declval<_G>(), declval>(), declval<_EVF>(), + declval<_Alloc>())))}; // intentional ADL + } else if constexpr (_Can_ref_evf_eval<_G, _EVF, _Alloc, _UnCV>) { + return {_St_ref_evf::_Auto_eval, + noexcept(_Fake_copy_init(edges_depth_first_search_view<_G, _EVF, true>( + declval<_G>(), declval>(), declval<_EVF>(), declval<_Alloc>())))}; + } else { + return {_St_ref_evf::_None}; + } + } + + template + static constexpr _Choice_t<_St_ref_evf> _Choice_ref_evf = _Choose_ref_evf<_G, _EVF, _Alloc>(); + + 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. + */ + 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 + noexcept(_Choice_ref<_G&, _Alloc>._No_throw) { + 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 + } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { + return edges_depth_first_search_view<_G, void, true>(__g, seed, alloc); // default impl + } else { + static_assert(_Always_false<_G>, "The default implementation of " + "sourced_edges_depth_first_search(g,seed,alloc) cannot be evaluated and " + "there is no override defined for the graph."); + } + } + + /** + * @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 + operator()(_G&& __g, const vertex_id_t<_G>& seed, _EVF&& evf, _Alloc alloc = _Alloc()) const + noexcept(_Choice_ref_evf<_G&, _EVF, _Alloc>._No_throw) { + 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 + } 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 { + static_assert(_Always_false<_G>, "The default implementation of " + "sourced_edges_depth_first_search(g,seed,evf,alloc) cannot be evaluated and " + "there is no override defined for the graph."); + } + } + }; +} // namespace _Sourced_Edges_DFS + +inline namespace _Cpos { + inline constexpr _Sourced_Edges_DFS::_Cpo sourced_edges_depth_first_search; +} + + +//template >, class Alloc = allocator> +//requires ranges::random_access_range> && integral> && _detail::is_allocator_v +//constexpr auto vertices_depth_first_search(G&& g, vertex_id_t seed, const Alloc& alloc = Alloc()) { +// if constexpr (std::graph::tag_invoke::_has_vtx_dfs_adl) +// return std::graph::tag_invoke::vertices_depth_first_search(g, seed, alloc); +// else +// return vertices_depth_first_search_view(g, seed, alloc); +//} +// +//template >, class Alloc = allocator> +//requires ranges::random_access_range> && integral> && +// invocable> && _detail::is_allocator_v +//constexpr auto vertices_depth_first_search(G&& g, vertex_id_t seed, const VVF& vvf, const Alloc& alloc = Alloc()) { +// if constexpr (std::graph::tag_invoke::_has_vtx_dfs_vvf_adl) +// return std::graph::tag_invoke::vertices_depth_first_search(g, seed, vvf, alloc); +// else +// return vertices_depth_first_search_view(g, seed, vvf, alloc); +//} + +} // namespace std::graph::views + + +# else namespace std::graph::tag_invoke { // vertices_depth_first_search CPO TAG_INVOKE_DEF(vertices_depth_first_search); // vertices_depth_first_search(g,seed) -> vertices[vid,v] @@ -766,4 +1246,6 @@ sourced_edges_depth_first_search(G&& g, vertex_id_t seed, const EVF& evf, con } // namespace std::graph::views -#endif // GRAPH_DFS_HPP +# endif //0 + +#endif // GRAPH_DFS_HPP diff --git a/include/graph/views/edgelist.hpp b/include/graph/views/edgelist.hpp index 250ebd2..140406e 100644 --- a/include/graph/views/edgelist.hpp +++ b/include/graph/views/edgelist.hpp @@ -106,7 +106,7 @@ class edgelist_iterator : public edgelist_iterator_base { public: using base_type = edgelist_iterator_base; - using graph_type = G; + using graph_type = remove_reference_t; using vertex_type = vertex_t; using vertex_id_type = vertex_id_t; using vertex_iterator = vertex_iterator_t; @@ -128,9 +128,9 @@ class edgelist_iterator : public edgelist_iterator_base { public: edgelist_iterator(graph_type& g, vertex_iterator ui, const EVF& value_fn) - : base_type(), g_(g), ui_(ui), uvi_(), value_fn_(&value_fn) {} + : base_type(), g_(&g), ui_(ui), uvi_(), value_fn_(&value_fn) {} edgelist_iterator(graph_type& g, const EVF& value_fn) : edgelist_iterator(g, ranges::begin(vertices(g)), value_fn) { - this->find_non_empty_vertex(g_, ui_, uvi_); + this->find_non_empty_vertex(*g_, ui_, uvi_); } constexpr edgelist_iterator() = default; @@ -161,23 +161,23 @@ class edgelist_iterator : public edgelist_iterator_base { public: constexpr reference operator*() const { if constexpr (unordered_edge) { - if (target_id(g_, *uvi_) != vertex_id(g_, ui_)) { - value_.shadow_.source_id = source_id(g_, *uvi_); - value_.shadow_.target_id = target_id(g_, *uvi_); + if (target_id(*g_, *uvi_) != vertex_id(*g_, ui_)) { + value_.shadow_.source_id = source_id(*g_, *uvi_); + value_.shadow_.target_id = target_id(*g_, *uvi_); } else { - value_.shadow_.source_id = target_id(g_, *uvi_); - value_.shadow_.target_id = source_id(g_, *uvi_); + value_.shadow_.source_id = target_id(*g_, *uvi_); + value_.shadow_.target_id = source_id(*g_, *uvi_); } value_.shadow_.edge = &*uvi_; value_.shadow_.value = invoke(*value_fn_, *uvi_); } else { - value_.shadow_ = {vertex_id(g_, ui_), target_id(g_, *uvi_), &*uvi_, invoke(*value_fn_, *uvi_)}; + value_.shadow_ = {vertex_id(*g_, ui_), target_id(*g_, *uvi_), &*uvi_, invoke(*value_fn_, *uvi_)}; } return value_.value_; } constexpr edgelist_iterator& operator++() { - this->find_next_edge(g_, ui_, uvi_); + this->find_next_edge(*g_, ui_, uvi_); return *this; } constexpr edgelist_iterator operator++(int) const { @@ -190,11 +190,11 @@ class edgelist_iterator : public edgelist_iterator_base { //constexpr bool operator==(const edgelist_iterator& rhs) const { return uvi_ == rhs; } private: // member variables - mutable internal_value value_; - _detail::ref_to_ptr g_; - vertex_iterator ui_; - edge_iterator uvi_; - const EVF* value_fn_ = nullptr; + mutable internal_value value_; + graph_type* g_ = nullptr; + vertex_iterator ui_; + edge_iterator uvi_; + const EVF* value_fn_ = nullptr; friend bool operator==(const vertex_iterator& lhs, const edgelist_iterator& rhs) { return lhs == rhs.ui_; } }; @@ -205,7 +205,7 @@ class edgelist_iterator : public edgelist_iterator_base { public: using base_type = edgelist_iterator_base; - using graph_type = G; + using graph_type = remove_reference_t; using vertex_type = vertex_t; using vertex_id_type = vertex_id_t; using vertex_iterator = vertex_iterator_t; @@ -242,8 +242,8 @@ class edgelist_iterator : public edgelist_iterator_base { }; public: - edgelist_iterator(graph_type& g, vertex_iterator ui) : base_type(), g_(g), ui_(ui), uvi_() { - this->find_non_empty_vertex(g_, ui_, uvi_); + edgelist_iterator(graph_type& g, vertex_iterator ui) : base_type(), g_(&g), ui_(ui), uvi_() { + this->find_non_empty_vertex(*g_, ui_, uvi_); } edgelist_iterator(graph_type& g) : edgelist_iterator(g, ranges::begin(vertices(g))) {} @@ -258,22 +258,22 @@ class edgelist_iterator : public edgelist_iterator_base { public: constexpr reference operator*() const { if constexpr (unordered_edge) { - if (target_id(g_, *uvi_) != vertex_id(g_, ui_)) { - value_.shadow_.source_id = source_id(g_, *uvi_); - value_.shadow_.target_id = target_id(g_, *uvi_); + if (target_id(*g_, *uvi_) != vertex_id(*g_, ui_)) { + value_.shadow_.source_id = source_id(*g_, *uvi_); + value_.shadow_.target_id = target_id(*g_, *uvi_); } else { - value_.shadow_.source_id = target_id(g_, *uvi_); - value_.shadow_.target_id = source_id(g_, *uvi_); + value_.shadow_.source_id = target_id(*g_, *uvi_); + value_.shadow_.target_id = source_id(*g_, *uvi_); } value_.shadow_.edge = &*uvi_; } else { - value_.shadow_ = {vertex_id(g_, ui_), target_id(g_, *uvi_), &*uvi_}; + value_.shadow_ = {vertex_id(*g_, ui_), target_id(*g_, *uvi_), &*uvi_}; } return value_.value_; } constexpr edgelist_iterator& operator++() { - this->find_next_edge(g_, ui_, uvi_); + this->find_next_edge(*g_, ui_, uvi_); return *this; } constexpr edgelist_iterator operator++(int) const { @@ -286,10 +286,10 @@ class edgelist_iterator : public edgelist_iterator_base { //constexpr bool operator==(const edgelist_iterator& rhs) const { return uvi_ == rhs; } private: // member variables - mutable internal_value value_; - _detail::ref_to_ptr g_; - vertex_iterator ui_; - edge_iterator uvi_; + mutable internal_value value_; + graph_type* g_ = nullptr; + vertex_iterator ui_; + edge_iterator uvi_; friend bool operator==(const vertex_iterator& lhs, const edgelist_iterator& rhs) { return lhs == rhs.ui_; } }; @@ -389,7 +389,7 @@ namespace views { #endif // ^^^ workaround ^^^ template - concept _Has_adjlist_all_ADL = adjacency_list<_G> // + concept _Has_adjlist_all_ADL = adjacency_list<_G> // && requires(_G&& __g) { { _Fake_copy_init(edgelist(__g)) }; // intentional ADL }; @@ -399,14 +399,14 @@ namespace views { template concept _Has_adjlist_all_evf_ADL = adjacency_list<_G> && invocable> // && requires(_G&& __g, EVF evf) { - { _Fake_copy_init(edgelist(__g, evf)) }; // intentional ADL + { _Fake_copy_init(edgelist(__g, evf)) }; // intentional ADL }; template concept _Can_adjlist_all_evf_eval = adjacency_list<_G> && invocable>; template - concept _Has_adjlist_idrng_ADL = adjacency_list<_G> // + concept _Has_adjlist_idrng_ADL = adjacency_list<_G> // && requires(_G&& __g, vertex_id_t<_G> uid, vertex_id_t<_G> vid) { { _Fake_copy_init(edgelist(__g, uid, vid)) }; // intentional ADL }; @@ -414,8 +414,8 @@ namespace views { concept _Can_adjlist_idrng_eval = adjacency_list<_G>; template - concept _Has_adjlist_idrng_evf_ADL = adjacency_list<_G> // - && invocable> // + concept _Has_adjlist_idrng_evf_ADL = adjacency_list<_G> // + && invocable> // && requires(_G&& __g, vertex_id_t<_G> uid, vertex_id_t<_G> vid, EVF evf) { { _Fake_copy_init(edgelist(__g, uid, vid, evf)) }; // intentional ADL }; @@ -466,7 +466,7 @@ namespace views { return {_St_adjlist_all::_Non_member, noexcept(_Fake_copy_init(edgelist(declval<_G>(), declval())))}; // intentional ADL } else if constexpr (_Can_adjlist_all_evf_eval<_G, _UnCV, EVF>) { - return {_St_adjlist_all::_Auto_eval, noexcept(true)}; // default impl (revisit) + return {_St_adjlist_all::_Auto_eval, noexcept(true)}; // default impl (revisit) } else { return {_St_adjlist_all::_None}; } @@ -487,7 +487,7 @@ namespace views { noexcept(_Fake_copy_init(edgelist(declval<_G>(), declval>(), declval>())))}; // intentional ADL } else if constexpr (_Can_adjlist_idrng_eval<_G, _UnCV>) { - return {_St_adjlist_idrng::_Auto_eval, noexcept(true)}; // default impl (revisit) + return {_St_adjlist_idrng::_Auto_eval, noexcept(true)}; // default impl (revisit) } else { return {_St_adjlist_idrng::_None}; } @@ -527,7 +527,7 @@ namespace views { return {_St_edgelist_all::_Non_member, noexcept(_Fake_copy_init(edgelist(declval(), declval())))}; // intentional ADL } else if constexpr (_Can_edgelist_all_proj_eval) { - return {_St_edgelist_all::_Auto_eval, noexcept(true)}; // default impl (revisit) + return {_St_edgelist_all::_Auto_eval, noexcept(true)}; // default impl (revisit) } else { return {_St_edgelist_all::_None}; } diff --git a/include/graph/views/incidence.hpp b/include/graph/views/incidence.hpp index 8104c9f..1d38d08 100644 --- a/include/graph/views/incidence.hpp +++ b/include/graph/views/incidence.hpp @@ -34,7 +34,7 @@ class incidence_iterator : source_vertex) || unordered_edge>)>; - using graph_type = G; + using graph_type = remove_reference_t; using vertex_type = vertex_t; using vertex_id_type = vertex_id_t; using vertex_iterator = vertex_iterator_t; @@ -56,9 +56,9 @@ class incidence_iterator : source_vertex) { - if (target_id(g_, *iter_) != this->source_vertex_id()) { - value_.shadow_.source_id = source_id(g_, *iter_); - value_.shadow_.target_id = target_id(g_, *iter_); + if (target_id(*g_, *iter_) != this->source_vertex_id()) { + value_.shadow_.source_id = source_id(*g_, *iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); } else { - value_.shadow_.source_id = target_id(g_, *iter_); - value_.shadow_.target_id = source_id(g_, *iter_); + value_.shadow_.source_id = target_id(*g_, *iter_); + value_.shadow_.target_id = source_id(*g_, *iter_); } } else if constexpr (Sourced) { if constexpr (sourced_adjacency_list) { - value_.shadow_.source_id = source_id(g_, *iter_); - value_.shadow_.target_id = target_id(g_, *iter_); + value_.shadow_.source_id = source_id(*g_, *iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); } else { value_.shadow_.source_id = this->source_vertex_id(); - value_.shadow_.target_id = target_id(g_, *iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); } } else { - value_.shadow_.target_id = target_id(g_, *iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); } value_.shadow_.edge = &*iter_; value_.shadow_.value = invoke(*value_fn_, *iter_); @@ -126,10 +126,10 @@ class incidence_iterator : source_vertex g_; - edge_iterator iter_; - const EVF* value_fn_ = nullptr; + mutable internal_value value_; + graph_type* g_ = nullptr; + edge_iterator iter_; + const EVF* value_fn_ = nullptr; friend bool operator==(const edge_iterator& lhs, const incidence_iterator& rhs) { return lhs == rhs.iter_; } }; @@ -141,7 +141,7 @@ class incidence_iterator public: using base_type = source_vertex) || unordered_edge>)>; - using graph_type = G; + using graph_type = remove_reference_t; using vertex_type = vertex_t; using vertex_id_type = vertex_id_t; using vertex_iterator = vertex_iterator_t; @@ -179,8 +179,8 @@ class incidence_iterator public: incidence_iterator(graph_type& g, vertex_iterator ui, edge_iterator iter) - : base_type(vertex_id(g, ui)), g_(g), iter_(iter) {} - incidence_iterator(graph_type& g, vertex_id_type uid) : base_type(uid), g_(g), iter_(ranges::begin(edges(g, uid))) {} + : base_type(vertex_id(g, ui)), g_(&g), iter_(iter) {} + incidence_iterator(graph_type& g, vertex_id_type uid) : base_type(uid), g_(&g), iter_(ranges::begin(edges(g, uid))) {} constexpr incidence_iterator() = default; constexpr incidence_iterator(const incidence_iterator&) = default; @@ -194,23 +194,23 @@ class incidence_iterator constexpr reference operator*() const { if constexpr (unordered_edge) { static_assert(sourced_adjacency_list); - if (target_id(g_, *iter_) != this->source_vertex_id()) { - value_.shadow_.source_id = source_id(g_.*iter_); - value_.shadow_.target_id = target_id(g_, *iter_); + if (target_id(*g_, *iter_) != this->source_vertex_id()) { + value_.shadow_.source_id = source_id(*g_.*iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); } else { - value_.shadow_.source_id = target_id(g_.*iter_); - value_.shadow_.target_id = source_id(g_, *iter_); + value_.shadow_.source_id = target_id(*g_.*iter_); + value_.shadow_.target_id = source_id(*g_, *iter_); } } else if constexpr (Sourced) { if constexpr (sourced_adjacency_list) { - value_.shadow_.source_id = source_id(g_, *iter_); - value_.shadow_.target_id = target_id(g_, *iter_); + value_.shadow_.source_id = source_id(*g_, *iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); } else { value_.shadow_.source_id = this->source_vertex_id(); - value_.target_id = target_id(g_, *iter_); + value_.target_id = target_id(*g_, *iter_); } } else { - value_.shadow_.target_id = target_id(g_, *iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); } value_.shadow_.edge = &*iter_; return value_.value_; @@ -230,9 +230,9 @@ class incidence_iterator //constexpr bool operator==(const incidence_iterator& rhs) const { return iter_ == rhs; } private: // member variables - mutable internal_value value_; - _detail::ref_to_ptr g_; - edge_iterator iter_; + mutable internal_value value_; + graph_type* g_ = nullptr; + edge_iterator iter_; friend bool operator==(const edge_iterator& lhs, const incidence_iterator& rhs) { return lhs == rhs.iter_; } }; @@ -315,7 +315,7 @@ namespace views { static constexpr _Choice_t<_St_id> _Choice_id_evf = _Choose_id_evf<_G, EVF>(); public: - /** + /** * @brief Get the outgoing incidence edges of a vertex id. * * Complexity: O(n) @@ -347,7 +347,7 @@ namespace views { } } - /** + /** * @brief Get the outgoing incidence edges of a vertex id and include an edge value in the result. * * Complexity: O(n) diff --git a/include/graph/views/neighbors.hpp b/include/graph/views/neighbors.hpp index 97fed77..08f561b 100644 --- a/include/graph/views/neighbors.hpp +++ b/include/graph/views/neighbors.hpp @@ -39,7 +39,7 @@ class neighbor_iterator public: using base_type = source_vertex) || unordered_edge>)>; - using graph_type = G; + using graph_type = remove_reference_t; using vertex_type = vertex_t; using vertex_id_type = vertex_id_t; using vertex_reference_type = vertex_reference_t; @@ -61,9 +61,9 @@ class neighbor_iterator public: neighbor_iterator(graph_type& g, vertex_iterator ui, edge_iterator iter, const VVF& value_fn) - : base_type(vertex_id(g, ui)), g_(g), iter_(iter), value_fn_(&value_fn) {} + : base_type(vertex_id(g, ui)), g_(&g), iter_(iter), value_fn_(&value_fn) {} neighbor_iterator(graph_type& g, vertex_id_type uid, const VVF& value_fn) - : base_type(uid), g_(g), iter_(ranges::begin(edges(g, uid))), value_fn_(&value_fn) {} + : base_type(uid), g_(&g), iter_(ranges::begin(edges(g, uid))), value_fn_(&value_fn) {} constexpr neighbor_iterator() = default; constexpr neighbor_iterator(const neighbor_iterator&) = default; @@ -97,27 +97,27 @@ class neighbor_iterator if constexpr (unordered_edge) { static_assert(sourced_adjacency_list); - if (target_id(g_, *iter_) != this->source_vertex_id()) { - value_.shadow_.source_id = source_id(g_.*iter_); - value_.shadow_.target_id = target_id(g_, *iter_); - value_.shadow_.target = const_cast(&target(g_, *iter_)); + if (target_id(*g_, *iter_) != this->source_vertex_id()) { + value_.shadow_.source_id = source_id(*g_.*iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); + value_.shadow_.target = const_cast(&target(*g_, *iter_)); } else { - value_.shadow_.source_id = target_id(g_.*iter_); - value_.shadow_.target_id = source_id(g_, *iter_); - value_.shadow_.target = const_cast(&source(g_, *iter_)); + value_.shadow_.source_id = target_id(*g_.*iter_); + value_.shadow_.target_id = source_id(*g_, *iter_); + value_.shadow_.target = const_cast(&source(*g_, *iter_)); } } else if constexpr (Sourced) { if constexpr (sourced_adjacency_list) { - value_.shadow_.source_id = source_id(g_, *iter_); - value_.shadow_.target_id = target_id(g_, *iter_); + value_.shadow_.source_id = source_id(*g_, *iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); } else { value_.shadow_.source_id = this->source_vertex_id(); - value_.shadow_.target_id = target_id(g_, *iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); } - value_.shadow_.target = const_cast(&target(g_, *iter_)); + value_.shadow_.target = const_cast(&target(*g_, *iter_)); } else { - value_.shadow_.target_id = target_id(g_, *iter_); - value_.shadow_.target = const_cast(&target(g_, *iter_)); + value_.shadow_.target_id = target_id(*g_, *iter_); + value_.shadow_.target = const_cast(&target(*g_, *iter_)); } value_.shadow_.value = invoke(*value_fn_, *value_.shadow_.target); // 'value' undeclared identifier (.value not in struct?) @@ -138,10 +138,10 @@ class neighbor_iterator //constexpr bool operator==(const neighbor_iterator& rhs) const { return iter_ == rhs; } private: // member variables - mutable internal_value value_; - _detail::ref_to_ptr g_; - edge_iterator iter_; - const VVF* value_fn_ = nullptr; + mutable internal_value value_; + graph_type* g_ = nullptr; + edge_iterator iter_; + const VVF* value_fn_ = nullptr; friend bool operator==(const edge_iterator& lhs, const neighbor_iterator& rhs) { return lhs == rhs.iter_; } }; @@ -153,7 +153,7 @@ class neighbor_iterator public: using base_type = source_vertex) || unordered_edge>)>; - using graph_type = G; + using graph_type = remove_reference_t; using vertex_type = vertex_t; using vertex_id_type = vertex_id_t; using vertex_reference_type = vertex_reference_t; @@ -191,8 +191,8 @@ class neighbor_iterator public: neighbor_iterator(graph_type& g, vertex_iterator ui, edge_iterator iter) - : base_type(vertex_id(g, ui)), g_(g), iter_(iter) {} - neighbor_iterator(graph_type& g, vertex_id_type uid) : base_type(uid), g_(g), iter_(ranges::begin(edges(g, uid))) {} + : base_type(vertex_id(g, ui)), g_(&g), iter_(iter) {} + neighbor_iterator(graph_type& g, vertex_id_type uid) : base_type(uid), g_(&g), iter_(ranges::begin(edges(g, uid))) {} constexpr neighbor_iterator() = default; constexpr neighbor_iterator(const neighbor_iterator&) = default; @@ -209,27 +209,27 @@ class neighbor_iterator if constexpr (unordered_edge) { static_assert(sourced_adjacency_list); - if (target_id(g_, *iter_) != this->source_vertex_id()) { - value_.shadow_.source_id = source_id(g_.*iter_); - value_.shadow_.target_id = target_id(g_, *iter_); - value_.shadow_.target = const_cast(&target(g_, *iter_)); + if (target_id(*g_, *iter_) != this->source_vertex_id()) { + value_.shadow_.source_id = source_id(*g_.*iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); + value_.shadow_.target = const_cast(&target(*g_, *iter_)); } else { - value_.shadow_.source_id = target_id(g_.*iter_); - value_.shadow_.target_id = source_id(g_, *iter_); - value_.shadow_.target = const_cast(&source(g_, *iter_)); + value_.shadow_.source_id = target_id(*g_.*iter_); + value_.shadow_.target_id = source_id(*g_, *iter_); + value_.shadow_.target = const_cast(&source(*g_, *iter_)); } } else if constexpr (Sourced) { if constexpr (sourced_adjacency_list) { - value_.shadow_.source_id = source_id(g_, *iter_); - value_.shadow_.target_id = target_id(g_, *iter_); + value_.shadow_.source_id = source_id(*g_, *iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); } else { value_.shadow_.source_id = this->source_vertex_id(); - value_.shadow_.target_id = target_id(g_, *iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); } - value_.shadow_.target = const_cast(&target(g_, *iter_)); + value_.shadow_.target = const_cast(&target(*g_, *iter_)); } else { - value_.shadow_.target_id = target_id(g_, *iter_); - value_.shadow_.target = const_cast(&target(g_, *iter_)); + value_.shadow_.target_id = target_id(*g_, *iter_); + value_.shadow_.target = const_cast(&target(*g_, *iter_)); } return value_.value_; } @@ -248,9 +248,9 @@ class neighbor_iterator //constexpr bool operator==(const neighbor_iterator& rhs) const { return iter_ == rhs; } private: // member variables - mutable internal_value value_; - _detail::ref_to_ptr g_; - edge_iterator iter_; + mutable internal_value value_; + graph_type* g_ = nullptr; + edge_iterator iter_; friend bool operator==(const edge_iterator& lhs, const neighbor_iterator& rhs) { return lhs == rhs.iter_; } }; diff --git a/tests/examples_tests.cpp b/tests/examples_tests.cpp index 1717e5a..0402d0f 100644 --- a/tests/examples_tests.cpp +++ b/tests/examples_tests.cpp @@ -6,6 +6,8 @@ #include #include "graph/graph.hpp" #include "graph/views/breadth_first_search.hpp" +#include "graph/views/vertexlist.hpp" +#include "graph/views/incidence.hpp" #include "graph/container/compressed_graph.hpp" using std::vector; @@ -209,3 +211,78 @@ TEST_CASE("Kevin Bacon example", "[compressed][bfs][example][bacon]") { } } #endif //0 + + +class simple_graph { + // Types +public: + using vertex_id_type = size_t; + using edge_type = vertex_id_type; + using vertex_type = vector; + using vertex_range_type = vector; + + using vertex_iterator_type = std::ranges::iterator_t; + using const_vertex_iterator_type = std::ranges::iterator_t; + + + // Construction/Destruction/Assignment +public: + simple_graph(std::initializer_list init) : vertices_(init) {} + + // Range +public: + auto size() const { return vertices_.size(); } + + auto begin() { return vertices_.begin(); } + auto end() { return vertices_.end(); } + + auto begin() const { return vertices_.begin(); } + auto end() const { return vertices_.end(); } + +public: + // Member Variables +private: + vertex_range_type vertices_; +}; +//int vertex_id(const simple_graph& g, std::graph::vertex_iterator_t uvi) noexcept { +// return static_cast(uvi - std::ranges::begin(std::graph::vertices(g))); +//} +vertex_id_t target_id(const simple_graph& g, edge_reference_t uv) noexcept { + return uv; +} + +TEST_CASE("wrapped vertex-vertex-int types", "[simple][bfs][example][bacon]") { + vector actors{"Tom Cruise", "Kevin Bacon", "Hugo Weaving", "Carrie-Anne Moss", "Natalie Portman", + "Jack Nicholson", "Kelly McGillis", "Harrison Ford", "Sebastian Stan", "Mila Kunis", + "Michelle Pfeiffer", "Keanu Reeves", "Julia Roberts"}; + + simple_graph costar_adjacency_list{{1, 5, 6}, {7, 10, 0, 5, 12}, {4, 3, 11}, {2, 11}, {8, 9, 2, 12}, {0, 1}, + {7, 0}, {6, 1, 10}, {4, 9}, {4, 8}, {7, 1}, {2, 3}, + {1, 4}}; + + std::vector bacon_number(size(actors)); + + using G = simple_graph; + G& g = costar_adjacency_list; + + for (auto&& u : std::graph::vertices(costar_adjacency_list)) { + for (auto&& uv : std::graph::edges(costar_adjacency_list, u)) { + auto vid = std::graph::target_id(costar_adjacency_list, uv); + static_assert(std::integral); + } + } + + for (auto&& [uid, u] : std::graph::views::vertexlist(costar_adjacency_list)) { + for (auto&& [vid, uv] : std::graph::views::incidence(costar_adjacency_list, uid)) { + } + } + + //// 1 -> Kevin Bacon + //for (auto&& [uid, vid, u] : std::graph::views::sourced_edges_breadth_first_search(costar_adjacency_list, 1)) { + // bacon_number[vid] = bacon_number[uid] + 1; + //} + + //for (int i = 0; i < size(actors); ++i) { + // std::cout << actors[i] << " has Bacon number " << bacon_number[i] << std::endl; + //} +}