diff --git a/example/CppCon2022/rr_adaptor.hpp b/example/CppCon2022/rr_adaptor.hpp index 4f1975c..7906146 100644 --- a/example/CppCon2022/rr_adaptor.hpp +++ b/example/CppCon2022/rr_adaptor.hpp @@ -113,7 +113,7 @@ class rr_adaptor { template rr_adaptor(VVR& vertex_values, // const ERng& erng, // - const EProj& eproj = EProj(), // EProj(ERng::value_type&) -> edge_descriptor + const EProj& eproj = EProj(), // EProj(ERng::value_type&) -> edge_info bool dup_edges = false) : vertex_values_(vertex_values) { vertex_id_type max_vid = max_vertex_id(erng, eproj); diff --git a/include/graph/algorithm/common_shortest_paths.hpp b/include/graph/algorithm/common_shortest_paths.hpp index 6b0ca5a..1122a81 100644 --- a/include/graph/algorithm/common_shortest_paths.hpp +++ b/include/graph/algorithm/common_shortest_paths.hpp @@ -82,49 +82,49 @@ constexpr void init_shortest_paths(Distances& distances, Predecessors& predecess // Vertex visitor concepts template concept has_on_initialize_vertex = // For exposition only - requires(Visitor& v, vertex_descriptor, vertex_reference_t, void> vdesc) { + requires(Visitor& v, vertex_info, vertex_reference_t, void> vdesc) { { v.on_initialize_vertex(vdesc) }; }; template concept has_on_discover_vertex = // For exposition only - requires(Visitor& v, vertex_descriptor, vertex_reference_t, void> vdesc) { + requires(Visitor& v, vertex_info, vertex_reference_t, void> vdesc) { { v.on_discover_vertex(vdesc) }; }; template concept has_on_examine_vertex = // For exposition only - requires(Visitor& v, vertex_descriptor, vertex_reference_t, void> vdesc) { + requires(Visitor& v, vertex_info, vertex_reference_t, void> vdesc) { { v.on_examine_vertex(vdesc) }; }; template concept has_on_finish_vertex = // For exposition only - requires(Visitor& v, vertex_descriptor, vertex_reference_t, void> vdesc) { + requires(Visitor& v, vertex_info, vertex_reference_t, void> vdesc) { { v.on_finish_vertex(vdesc) }; }; // Edge visitor concepts template concept has_on_examine_edge = // For exposition only - requires(Visitor& v, edge_descriptor, true, edge_reference_t, void> edesc) { + requires(Visitor& v, edge_info, true, edge_reference_t, void> edesc) { { v.on_examine_edge(edesc) }; }; template concept has_on_edge_relaxed = // For exposition only - requires(Visitor& v, edge_descriptor, true, edge_reference_t, void> edesc) { + requires(Visitor& v, edge_info, true, edge_reference_t, void> edesc) { { v.on_edge_relaxed(edesc) }; }; template concept has_on_edge_not_relaxed = // For exposition only - requires(Visitor& v, edge_descriptor, true, edge_reference_t, void> edesc) { + requires(Visitor& v, edge_info, true, edge_reference_t, void> edesc) { { v.on_edge_not_relaxed(edesc) }; }; template concept has_on_edge_minimized = // For exposition only - requires(Visitor& v, edge_descriptor, true, edge_reference_t, void> edesc) { + requires(Visitor& v, edge_info, true, edge_reference_t, void> edesc) { { v.on_edge_minimized(edesc) }; }; template concept has_on_edge_not_minimized = // For exposition only - requires(Visitor& v, edge_descriptor, true, edge_reference_t, void> edesc) { + requires(Visitor& v, edge_info, true, edge_reference_t, void> edesc) { { v.on_edge_not_minimized(edesc) }; }; diff --git a/include/graph/algorithm/dijkstra_clrs.hpp b/include/graph/algorithm/dijkstra_clrs.hpp index c814a9e..b3a4c58 100644 --- a/include/graph/algorithm/dijkstra_clrs.hpp +++ b/include/graph/algorithm/dijkstra_clrs.hpp @@ -28,26 +28,26 @@ concept edge_weight_function2 = // e.g. weight(uv) basic_edge_weight_function2>, plus>>; -class null_range_type : public std::vector { +class _null_range_type : public std::vector { using T = size_t; using Allocator = std::allocator; using Base = std::vector; public: - null_range_type() noexcept(noexcept(Allocator())) = default; - explicit null_range_type(const Allocator& alloc) noexcept {} - null_range_type(Base::size_type count, const T& value, const Allocator& alloc = Allocator()) {} - explicit null_range_type(Base::size_type count, const Allocator& alloc = Allocator()) {} + _null_range_type() noexcept(noexcept(Allocator())) = default; + explicit _null_range_type(const Allocator& alloc) noexcept {} + _null_range_type(Base::size_type count, const T& value, const Allocator& alloc = Allocator()) {} + explicit _null_range_type(Base::size_type count, const Allocator& alloc = Allocator()) {} template - null_range_type(InputIt first, InputIt last, const Allocator& alloc = Allocator()) {} - null_range_type(const null_range_type& other) : Base() {} - null_range_type(const null_range_type& other, const Allocator& alloc) {} - null_range_type(null_range_type&& other) noexcept {} - null_range_type(null_range_type&& other, const Allocator& alloc) {} - null_range_type(std::initializer_list init, const Allocator& alloc = Allocator()) {} + _null_range_type(InputIt first, InputIt last, const Allocator& alloc = Allocator()) {} + _null_range_type(const _null_range_type& other) : Base() {} + _null_range_type(const _null_range_type& other, const Allocator& alloc) {} + _null_range_type(_null_range_type&& other) noexcept {} + _null_range_type(_null_range_type&& other, const Allocator& alloc) {} + _null_range_type(std::initializer_list init, const Allocator& alloc = Allocator()) {} }; -inline static null_range_type null_predecessors; +inline static _null_range_type null_predecessors; template @@ -80,6 +80,9 @@ constexpr auto print_types(Ts...) { * The edge weight function must not throw an exception. * The edge weight function must not modify the graph, the edge, or the vertex (nor any of their associated data). */ + +#if 1 // not using Identifiers (original) + template = 0); std::ranges::fill(distance, std::numeric_limits::max()); @@ -129,7 +132,61 @@ void dijkstra_clrs( //weight_type w = weight(uv); if (distance[uid] + w < distance[vid]) { distance[vid] = distance[uid] + w; - if constexpr (!is_same_v) + if constexpr (!is_same_v) + predecessor[vid] = uid; + Q.push({vid, distance[vid]}); + } + } + } +} + +#else // using Identifiers + +template (edge_identifier_t)>> +requires random_access_range> && // + integral> && // + is_arithmetic_v> && // + convertible_to, range_value_t> && // + edge_weight_function +void dijkstra_clrs( + G&& g, // graph + vertex_identifier_t seed, // starting vertex_id + Distance& distance, // out: distance[uid] of uid from seed + Predecessor& predecessor, // out: predecessor[uid] of uid in path + WF&& weight = [](edge_identifier_t uv) { return range_value_t(1); }) // default weight(uv) -> 1 +{ + using id_type = vertex_id_t; + using weight_type = invoke_result_t>; + const id_type seed_id = vertex_id(g, seed); + + size_t N(num_vertices(g)); + assert(seed_id < N && seed_id >= 0); + + std::ranges::fill(distance, std::numeric_limits::max()); + distance[seed_id] = 0; + + struct weighted_vertex { + id_type vertex_id = id_type(); + weight_type weight = weight_type(); + }; + + using q_compare = decltype([](const weighted_vertex& a, const weighted_vertex& b) { return a.weight > b.weight; }); + std::priority_queue, q_compare> Q; + + Q.push({seed_id, distance[seed_id]}); + + while (!Q.empty()) { + auto uid = Q.top().vertex_id; + Q.pop(); + + for (auto&& [v_identifier, uv_identifier, w] : views::incidence(g, find_vertex(g, uid), weight)) { + id_type vid = vertex_id(v_identifier); + if (distance[uid] + w < distance[vid]) { + distance[vid] = distance[uid] + w; + if constexpr (!is_same_v) predecessor[vid] = uid; Q.push({vid, distance[vid]}); } @@ -137,4 +194,6 @@ void dijkstra_clrs( } } +#endif // Identifiers + } // namespace graph diff --git a/include/graph/algorithm/experimental/co_cmn.hpp b/include/graph/algorithm/experimental/co_cmn.hpp index 236a6af..c10adcb 100644 --- a/include/graph/algorithm/experimental/co_cmn.hpp +++ b/include/graph/algorithm/experimental/co_cmn.hpp @@ -20,12 +20,12 @@ concept edge_weight_function = // e.g. weight(uv) is_arithmetic_v>> && basic_edge_weight_function, plus>; -// These types comprise the bfs value type, made up of bfs_events and variant. +// These types comprise the bfs value type, made up of bfs_events and variant. // monostate is used to indicate that the value is not set and to make it default-constructible. template -using bfs_vertex_value_t = vertex_descriptor, reference_wrapper>, VValue>; +using bfs_vertex_value_t = vertex_info, reference_wrapper>, VValue>; template -using bfs_edge_value_t = edge_descriptor, true, reference_wrapper>, void>; +using bfs_edge_value_t = edge_info, true, reference_wrapper>, void>; template using bfs_variant_value_t = std::variant, bfs_edge_value_t>; diff --git a/include/graph/algorithm/experimental/visitor_dijkstra.hpp b/include/graph/algorithm/experimental/visitor_dijkstra.hpp index 227dddd..0c70d7b 100644 --- a/include/graph/algorithm/experimental/visitor_dijkstra.hpp +++ b/include/graph/algorithm/experimental/visitor_dijkstra.hpp @@ -64,8 +64,8 @@ class dijkstra_visitor_base { // Types public: using graph_type = G; - using vertex_desc_type = vertex_descriptor, vertex_reference_t, void>; - using sourced_edge_desc_type = edge_descriptor, true, edge_reference_t, void>; + using vertex_desc_type = vertex_info, vertex_reference_t, void>; + using sourced_edge_desc_type = edge_info, true, edge_reference_t, void>; // Visitor Functions public: diff --git a/include/graph/algorithm/mst.hpp b/include/graph/algorithm/mst.hpp index 1bc02b3..dd66b45 100644 --- a/include/graph/algorithm/mst.hpp +++ b/include/graph/algorithm/mst.hpp @@ -167,9 +167,9 @@ void kruskal(IELR&& e, // graph OELR&& t, // tree CompareOp compare // edge value comparitor ) { - using edge_descriptor = range_value_t; - using VId = remove_const_t; - using EV = edge_descriptor::value_type; + using edge_info = range_value_t; + using VId = remove_const_t; + using EV = edge_info::value_type; std::vector> e_copy; std::ranges::transform(e, back_inserter(e_copy), @@ -241,8 +241,8 @@ void inplace_kruskal(IELR&& e, // graph OELR&& t, // tree CompareOp compare // edge value comparitor ) { - using edge_descriptor = range_value_t; - using VId = remove_const_t; + using edge_info = range_value_t; + using VId = remove_const_t; VId N = 0; auto outer_compare = [&](auto&& i, auto&& j) { diff --git a/include/graph/container/compressed_graph.hpp b/include/graph/container/compressed_graph.hpp index 1291b6e..a8eb114 100644 --- a/include/graph/container/compressed_graph.hpp +++ b/include/graph/container/compressed_graph.hpp @@ -1106,7 +1106,7 @@ class compressed_graph const Alloc& alloc = Alloc()) : base_type(erng, vrng, eprojection, vprojection, partition_start_ids, alloc) {} - // initializer list using edge_descriptor + // initializer list using edge_info constexpr compressed_graph(const std::initializer_list>& ilist, const Alloc& alloc = Alloc()) : base_type(ilist, alloc) {} }; diff --git a/include/graph/detail/descriptor.hpp b/include/graph/detail/descriptor.hpp new file mode 100644 index 0000000..2321e66 --- /dev/null +++ b/include/graph/detail/descriptor.hpp @@ -0,0 +1,488 @@ +#pragma once + +#include + +#ifndef GRAPH_DESCRIPTOR_HPP +# define GRAPH_DESCRIPTOR_HPP + +namespace graph { + +// Descriptor Change Notes +// +// Implications in the change for descriptors: +// 1. The vertex functions in the Graph Container Interface will replace vertex id and vertex reference with a vertex descriptor, +// and edge functions will replace edge reference with vertex descriptor. +// 2. The second implication is that the number of concepts, views and functions will shrink because of this. +// 3. It will become easier to write generic algorithms without specializations for vertices in random-access vs. bidirectional +// containers. +// 4. It becomes much harder to detect if uv.target_id(g) is defined, so member functions may not be auto-detected by CPOs. +// +// Practically, a descriptor is an integral index for contiguous and random-access containers and an iterator for other containers. +// +// Rename vertex_descriptor to vertex_info, etc. +// + +// Questions +// 1. How to provide the raw vertex & edge ranges? (non-descriptor ranges) +// a. special ranges? (e.g. raw_vertices_range(g), raw_edges_range(g,u)) +// + +// "Concepts" for descriptors +// 1. descriptor_iterator +// 2. descriptor_value: index or iterator +// +// 3. descriptor_view | descriptor_subrange_view +// a. size() +// b. begin(), end() +// c. id(descriptor) -> vertex_id_t +// d. find(id) -> +// +// 5. inner_iterator: iterator of the underlying container +// 6. inner_value_type: vertex or edge value +// 7. inner_id_type: index or key + +template +struct is_tuple_like : std::false_type {}; +template +struct is_tuple_like> : public std::true_type {}; +template +struct is_tuple_like> : public std::true_type {}; + +template +inline constexpr bool is_tuple_like_v = is_tuple_like::value; + + +template +struct tuple_tail { + using type = T; +}; +template +struct tuple_tail> { + using type = tuple; +}; +template +struct tuple_tail> { + using type = U; +}; +template +using tuple_tail_t = typename tuple_tail::type; + + +# if 0 +template +struct edge_descriptor_traits { + using inner_iterator = I; + using difference_type = iter_difference_t; + using value_type = conditional_t, difference_type, inner_iterator>; + + // container inner_id_type inner_target_type inner_value_type + // ========================= ================ ==================== ==================== + // vector difference_type int int + // vector> difference_type int pair + // deque difference_type int int + // deque> difference_type int pair + // map int int pair + // set int int int + // list int int int + // list> int int tuple + // list> int int pair + // + + using inner_value_type = iter_value_t; + + using inner_id_type = conditional_t< + random_access_iterator, // + difference_type, // + conditional_t>, tuple_element_t<0, iter_value_t>, iter_value_t>>; +}; +# endif //0 + +template +struct _descriptor_traits { + using inner_iterator = I; + using difference_type = iter_difference_t; + using value_type = conditional_t, difference_type, inner_iterator>; + + // container inner_id_type inner_value_type + // ========================= ================ ==================== + // vector> difference_type vector + // vector> difference_type map + // vector> difference_type set + // deque> difference_type deque + // deque> difference_type map + // map> int vector + // + + using inner_value_type = iter_value_t; + + // The type used to lookup an element in the container. + using inner_id_type = + conditional_t, // + difference_type, // + conditional_t, tuple_element_t<0, inner_value_type>, void>>; + + //using inner_target_id_type = + // conditional_t, tuple_element_t<0, inner_value_type>, inner_value_type>; +}; + + +/** + * @brief An iterator that uses a descriptor (integral index or iterator) for a container. + * + * An integral index is used for random-access containers, while an iterator is used for other containers. + * + * A descriptor enables an abstraction that allows the same code to be used for different types of containers + * without loss of efficiency from the underlying container. For instance, if an integral index is used + * for a contiguous container, the code will be as efficient as if the index were used directly. + * If it's used for a map (bidirectional container), the iterator will be dereferenced to get the associated + * value, avoiding a log(n) lookup if the id were to be used. + * + * @tparam I Iterator type of the underlying container. + */ +template > +class _descriptor_iterator { +public: + using this_type = _descriptor_iterator; + using traits = Traits; + + using inner_iterator = I; + using inner_id_type = typename traits::inner_id_type; + using inner_value_type = typename traits::inner_value_type; + + using difference_type = typename traits::difference_type; + using value_type = typename traits::value_type; + using pointer = std::add_pointer_t>; + using reference = std::add_lvalue_reference_t>; + using iterator_category = std::forward_iterator_tag; + using iterator_concept = iterator_category; + + _descriptor_iterator() = default; + explicit _descriptor_iterator(value_type descriptor) : descriptor_(descriptor) {} + // copy & move constructors and assignment operators are default + + template + requires convertible_to, inner_iterator> + explicit _descriptor_iterator(R& r, inner_iterator iter) { + if constexpr (integral) { + descriptor_ = static_cast(std::distance(std::ranges::begin(r), iter)); + } else { + descriptor_ = iter; + } + } + + // + // dereference + // + reference operator*() const noexcept { return descriptor_; } + pointer operator->() const noexcept { return &descriptor_; } + + // + // operators ++ + // + _descriptor_iterator& operator++() { + ++descriptor_; + return *this; + } + _descriptor_iterator operator++(int) { + _descriptor_iterator tmp = *this; + ++descriptor_; + return tmp; + } + + // + // operators ==, != + // + auto operator==(const _descriptor_iterator& rhs) const { return descriptor_ == rhs.descriptor_; } + +private: + value_type descriptor_ = value_type(); // integral index or iterator, depending on container type +}; + +template +struct descriptor_value { + using type = T; +}; +template +struct descriptor_value> { + using type = U; +}; +template +struct descriptor_value> { + using type = U; +}; +template +using descriptor_value_t = typename descriptor_value::type; + + +// Helper to detect if T has a member function named size +template +class _has_size { +private: + // Check if the expression T().size() is valid + template + static auto check(int) -> decltype(std::declval().size(), std::true_type()); + + // Fallback if the above is not valid + template + static std::false_type check(...); + +public: + // Result is true if the first check is valid, false otherwise + static constexpr bool value = decltype(check(0))::value; +}; + +// Helper variable template for easier usage +template +inline constexpr bool has_size_v = _has_size::value; + + +// Helper to detect if T has a member function named size +template +class _ident_type { +private: + // Check if the expression T().size() is valid + template + static auto check(int) -> decltype(std::ranges::size(declval())); + + // Fallback if the above is not valid + template + static iterator_t check(...); + +public: + // Result is true if the first check is valid, false otherwise + using type = decltype(check(0)); +}; + +// Helper variable template for easier usage +template +using _ident_t = _ident_type::type; + + +template +class descriptor_view : public std::ranges::view_interface> { +public: + //using size_type = range_size_t; + using inner_iterator = iterator_t; // iterator of the underlying container + using iterator = _descriptor_iterator; // + + using value_type = descriptor_value_t>; + using difference_type = iter_difference_t; + using id_type = difference_type; // e.g. vertex_id_t + using descriptor_type = iter_value_t; // integral index or iterator, depending on container type + + descriptor_view() = default; + constexpr explicit descriptor_view(C&& c) : c_(c) {} + + auto size() const + requires sized_range + { + return std::ranges::size(c_); + } + + iterator begin() const { return std::ranges::begin(c_); } + iterator end() const { return std::ranges::end(c_); } + + /** + * @brief Get the vertex id for a descriptor. + * + * @param desc The descriptor. This must refer to a valid element in the container. + * @return vertex id. + */ + id_type id(descriptor_type& desc) const { + if constexpr (integral) { + return desc; + } else if constexpr (random_access_range) { + return static_cast(std::distance(c_.begin(), desc)); + } else if constexpr (is_tuple_like_v>) { + return std::get<0>(*desc); // e.g., pair::first used for map + } else { + static_assert( + random_access_range, + "id cannot be determined for a forward range or a bidirectional range without a tuple-like value type"); + return id_type(); + } + } + + /** + * @brief Find an element in the container, given an id. + * + * This assumes that the full range of id's in the container is [0, size(c_)). If a subrange is needed, use + * subrange_find. + * + * @param id The id to search for. + * @return Descriptor iterator to the element. If the element is not found, the iterator is equal to end(). + */ + iterator find(id_type id) const { + if constexpr (integral) { + return iterator(id); + } else if constexpr (random_access_range) { + return iterator(c_.begin() + id); + } else if constexpr (bidirectional_range) { + return iterator(c_.find(id)); // map or set + } else { + static_assert(random_access_range, + "find(id) cannot be evaluated for a forward range because there is no id/key in the container"); + } + return end(); + } + +private: + reference_wrapper c_; +}; + +template +class descriptor_subrange_view : public std::ranges::view_interface> { +public: + //using size_type = range_size_t; + using inner_iterator = iterator_t; // iterator of the underlying container + using iterator = _descriptor_iterator; // + + using value_type = descriptor_value_t>; + using difference_type = iter_difference_t; + using id_type = difference_type; // e.g. vertex_id_t + using descriptor_type = iter_value_t; // integral index or iterator, depending on container type + + descriptor_subrange_view() = default; + constexpr explicit descriptor_subrange_view(C&& c) + : c_(c), first_(c, std::ranges::begin(c)), last_(c, std::ranges::end(c)) {} + + auto size() const + requires sized_range + { + return std::ranges::size(c_); + } + + iterator begin() const { return first_; } + iterator end() const { return last_; } + + /** + * @brief Get the vertex id for a descriptor. + * + * @param desc The descriptor. This must refer to a valid element in the container. + * @return vertex id. + */ + id_type id(descriptor_type& desc) const { + if constexpr (integral) { + return desc; + } else if constexpr (random_access_range) { + return static_cast(std::distance(c_.begin(), desc)); + } else if constexpr (is_tuple_like_v>) { + return std::get<0>(*desc); // e.g., pair::first used for map + } else { + static_assert( + random_access_range, + "id cannot be determined for a forward range or a bidirectional range without a tuple-like value type"); + return id_type(); + } + } + + /** + * @brief Find an element in the container, given an id. + * + * This assumes that the full range of id's in the container is [0, size(c_)). If a subrange is needed, use + * subrange_find. + * + * @param id The id to search for. + * @return Descriptor iterator to the element. If the element is not found, the iterator is equal to end(). + */ + iterator find(id_type id) const { + if constexpr (integral) { + return iterator(id); + } else if constexpr (random_access_range) { + return iterator(c_.begin() + id); + } else if constexpr (bidirectional_range) { + return iterator(c_.find(id)); // map or set + } else { + static_assert(random_access_range, + "find(id) cannot be evaluated for a forward range because there is no id/key in the container"); + } + return last_; + } + + /** + * @brief Find an element in a container, given an id, constrained to the range [first_, last_). + * + * The id must be in the range [first_, last_) of the container. If it isn't, the iterator will be equal to end() + * which is also last_. + * + * Note: The first/last constraint is really for edges in a CSR. Vertices in a CSR and edges in vertex> + * will include all elements in the container. Specialization for different conditions could reduce the number of + * constraints. + * + * @param id The id to search for. It must be in the range [first_, last_) of the container. + * @return Descriptor iterator to the element. If the element is not found, the iterator is equal to end(). + */ + iterator subrange_find(id_type id) const { + if constexpr (integral) { + if (id >= *first_ && id < *last_) { + return iterator(c_, c_.begin() + id); + } + } else if constexpr (random_access_range) { + if ((id >= *first_ - c_.begin()) && (id < *last_ - c_.begin())) { + return iterator(c_.begin() + id); + } + } else if constexpr (bidirectional_range) { + return iterator(c_.find(id)); // map or set + } else { + static_assert(random_access_range, + "find(id) cannot be evaluated for a forward range because there is no id/key in the container"); + } + return last_; + } + +private: + reference_wrapper c_; + + // first_ and last_ may be a sub-range of the container (e.g. for a CSR). + iterator first_; + iterator last_; +}; + + +# if 0 +template +using _descriptor_view = subrange<_descriptor_iterator>, _descriptor_iterator>>; + +template +auto to_descriptor_view(R&& r) { + using dview = _descriptor_view; + using diter = iterator_t; + using dvalue = range_value_t; + if constexpr (integral) { + return dview{diter(0), diter(static_cast(size(r)))}; + } else { + return dview{diter(std::ranges::begin(r)), diter(std::ranges::end(r))}; + } +} + +// The concrete value of a descriptor is the underlying type the descriptor points to. + +// value_type of the inner iterator of the descriptor_view +template +using _concrete_value_type = iter_value_t::inner_iterator>; + +/** + * @brief Returns a reference to the concrete value of a descriptor. + * + * @tparam DV Descriptor value_type. + * @tparam R Underlying range type of values referenced by the descriptor. + * + * @param r Underlying range of concrete values. + * @param dvalue Descriptor value. + * + * @return Reference to the concrete value. + */ +template +auto& _concrete_value(R&& r, DV&& dvalue) { + if constexpr (integral) { + return r[dvalue]; // could also be *(r.begin() + dvalue), or r.begin()[dvalue] + } else { + return *dvalue; + } +} +# endif + +} // namespace graph + + +#endif // GRAPH_DESCRIPTOR_HPP diff --git a/include/graph/detail/graph_cpo.hpp b/include/graph/detail/graph_cpo.hpp index 297916c..5a66bff 100644 --- a/include/graph/detail/graph_cpo.hpp +++ b/include/graph/detail/graph_cpo.hpp @@ -1,11 +1,15 @@ #pragma once // (included from graph.hpp) -#include "graph/graph_descriptors.hpp" +#include "graph/graph_info.hpp" +#include "graph/detail/descriptor.hpp" #ifndef GRAPH_CPO_HPP # define GRAPH_CPO_HPP +# define USE_VERTEX_DESCRIPTOR 0 +# define USE_EDGE_DESCRIPTOR 0 + namespace graph { // The non-standard naming of these structs is intentional to avoid conflicts with @@ -93,9 +97,9 @@ concept _el_index_tuple_edge = _el_tuple_edge<_E> && // integral>; // -// Suport the use of edge_descriptor for edgelist edge definitions -// (Only types and values needed from edge_descriptor are used and there is no -// explicit use of edge_descriptor. This is deemed more flexible and no +// Suport the use of edge_info for edgelist edge definitions +// (Only types and values needed from edge_info are used and there is no +// explicit use of edge_info. This is deemed more flexible and no // functionality is compromised for it.) // template // For exposition only @@ -109,29 +113,6 @@ concept _el_basic_sourced_index_edge_desc = _el_basic_sourced_edge_desc<_E> && integral && integral; -// Tags are defined in tag_invoke namespace to avoid conflicts with function names -// in graph, allowing customization for default behavior. -// -// graphs must use tags like graph::tag_invoke::vertex_id_fn_t when defining -// CPO specialization. -// -// Minimal requirements for a graph with random_access vertices(g) -// vertices(g), edges(g,u), target_id(g,u) -// To have vertex_id_t be something other than size_t -// vertex_id(g,ui) -// Properties, as supported by the graph: -// edge_value(g,uv), vertex_value(g,uv), graph_value(g) -// - -// Additional functions to consider for future -// reserve_vertices(g,n) - noop if n/a -// reserve_edges(g,n) - noop if n/a -// -// load_graph(g,erng,vrng,eproj,vproj) -// -// Graph reference of graph type G.** Graph - - template using graph_reference_t = std::add_lvalue_reference; @@ -189,7 +170,7 @@ namespace _Vertices { { _Fake_copy_init(__g.vertices()) }; }; template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g) { { _Fake_copy_init(vertices(__g)) }; // intentional ADL }; @@ -241,7 +222,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 { @@ -300,7 +281,7 @@ namespace _Vertex_id { { _Fake_copy_init(ui->vertex_id(__g)) }; }; template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const vertex_iterator_t<_G> ui) { { _Fake_copy_init(vertex_id(__g, ui)) }; // intentional ADL }; @@ -477,7 +458,7 @@ namespace _Find_vertex { }; template - concept _Has_ADL = _HasClassOrEnumType<_G> // + concept _Has_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid) { { _Fake_copy_init(find_vertex(__g, uid)) }; // intentional ADL }; @@ -564,7 +545,7 @@ namespace _Edges { { _Fake_copy_init(u.edges(__g)) }; }; template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const vertex_reference_t<_G>& u) { { _Fake_copy_init(edges(__g, u)) }; // intentional ADL }; @@ -572,7 +553,7 @@ namespace _Edges { concept _Can_ref_eval = _HasClassOrEnumType<_G> && forward_range>; template - concept _Has_id_ADL = _HasClassOrEnumType<_G> // + concept _Has_id_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid) { { _Fake_copy_init(edges(__g, uid)) }; // intentional ADL }; @@ -647,7 +628,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(_AlwaysFalse<_G>, "edges(g,u) is not defined and the default implementation cannot be evaluated"); } @@ -671,14 +652,25 @@ namespace _Edges { noexcept(_Choice_id<_G&>._No_throw) -> decltype(auto) { constexpr _St_id _Strat_id = _Choice_id<_G&>._Strategy; +# if USE_EDGE_DESCRIPTOR + if constexpr (_Strat_id == _St_id::_Non_member) { + return to_descriptor_view(edges(__g, uid)); // intentional ADL + } else if constexpr (_Strat_id == _St_id::_Auto_eval) { + return to_descriptor_view(*find_vertex(__g, uid)); // default impl + } else { + static_assert(_AlwaysFalse<_G>, + "edges(g,uid) is not defined and the default implementation cannot be evaluated"); + } +# else 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 { static_assert(_AlwaysFalse<_G>, "edges(g,uid) is not defined and the default implementation cannot be evaluated"); } +# endif } }; } // namespace _Edges @@ -701,6 +693,22 @@ using vertex_edge_range_t = decltype(edges(declval(), declval using vertex_edge_iterator_t = iterator_t>; +# if USE_EDGE_DESCRIPTOR +/** + * @brief The edge descriptor type for graph G. + * The edge descriptor is an integral index value or an iterator to the edge value. + * @tparam G The graph type. +*/ +template +using edge_descriptor_t = range_value_t>; + +/** + * @brief The concrete edge type for graph G. + * @tparam G The graph type. +*/ +//template +//using edge_t = _concrete_value_type>; +# else /** * @brief The edge type for graph G. * @tparam G The graph type. @@ -714,7 +722,7 @@ using edge_t = range_value_t>; */ template using edge_reference_t = range_reference_t>; - +# endif // // num_edges(g,) -> integral default = n=0; for (const auto& u : vertices(g)) n += distance(edges(g,u)) @@ -732,7 +740,7 @@ namespace _NumEdges { { _Fake_copy_init(__g.num_edges()) }; }; template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g) { { _Fake_copy_init(num_edges(__g)) }; // intentional ADL }; @@ -822,6 +830,16 @@ namespace _Target_id { void target_id(); # endif // ^^^ workaround ^^^ +# if USE_EDGE_DESCRIPTOR + template + concept _Has_adjl_ref_member = requires(_G&& __g, edge_descriptor_t<_G> uv) { + { _Fake_copy_init(uv.target_id(__g)) }; + }; + template + concept _Has_adjl_ref_ADL = requires(_G&& __g, edge_descriptor_t<_G> uv) { + { _Fake_copy_init(target_id(__g, uv)) }; // intentional ADL + }; +# else template concept _Has_adjl_ref_member = requires(_G&& __g, edge_reference_t<_G> uv) { { _Fake_copy_init(uv.target_id(__g)) }; @@ -830,6 +848,7 @@ namespace _Target_id { concept _Has_adjl_ref_ADL = requires(_G&& __g, edge_reference_t<_G> uv) { { _Fake_copy_init(target_id(__g, uv)) }; // intentional ADL }; +#endif template concept _Is_basic_id_adj = integral<_al_edge_t<_G>>; // vertex> @@ -898,7 +917,7 @@ namespace _Target_id { noexcept(_Fake_copy_init(declval>()))}; // first element of tuple/pair } else if constexpr (_is_edge_desc<_E>) { return {_St_edgl_ref::_EDesc_id, - noexcept(_Fake_copy_init(declval()))}; // target_id of edge_descriptor + noexcept(_Fake_copy_init(declval()))}; // target_id of edge_info } else { return {_St_edgl_ref::_None}; } @@ -949,7 +968,7 @@ namespace _Target_id { * * Default implementation: * get<0>(e) for tuple or pair - * e.source_id for edge_descriptor + * e.source_id for edge_info * * @tparam G The graph type. * @param g A graph instance. @@ -1020,7 +1039,7 @@ namespace _Source_id { { _Fake_copy_init(uv.source_id(__g)) }; }; template - concept _Has_adjl_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_adjl_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const edge_reference_t<_G>& uv) { { _Fake_copy_init(source_id(__g, uv)) }; // intentional ADL }; @@ -1030,7 +1049,7 @@ namespace _Source_id { { _Fake_copy_init(__e.source_id()) }; }; template - concept _Has_edgl_ref_ADL = _HasClassOrEnumType<_E> // + concept _Has_edgl_ref_ADL = _HasClassOrEnumType<_E> // && requires(_E&& __e) { { _Fake_copy_init(source_id(__e)) }; // intentional ADL }; @@ -1077,7 +1096,7 @@ namespace _Source_id { noexcept(_Fake_copy_init(declval>()))}; // first element of tuple/pair } else if constexpr (_is_edge_desc<_E>) { return {_St_edgl_ref::_EDesc_id, - noexcept(_Fake_copy_init(declval()))}; // source_id of edge_descriptor + noexcept(_Fake_copy_init(declval()))}; // source_id of edge_info } else { return {_St_edgl_ref::_None}; } @@ -1123,7 +1142,7 @@ namespace _Source_id { * * Default implementation: * get<1>(e) for tuple or pair - * e.target_id for edge_descriptor + * e.target_id for edge_info * * @tparam E The edgelist value_type. * @param e A edgelist edge instance. @@ -1139,7 +1158,7 @@ namespace _Source_id { } else if constexpr (_Strat_ref == _St_edgl_ref::_Non_member) { return source_id(__e); // intentional ADL } else if constexpr (_Strat_ref == _St_edgl_ref::_Tuple_id) { - return get<1>(__e); // first element of tuple/pair + return get<1>(__e); // first element of tuple/pair } else if constexpr (_Strat_ref == _St_edgl_ref::_EDesc_id) { return __e.source_id; } else { @@ -1176,7 +1195,7 @@ namespace _Target { # endif // ^^^ workaround ^^^ template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const edge_reference_t<_G>& uv) { { _Fake_copy_init(target(__g, uv)) }; // intentional ADL }; @@ -1260,7 +1279,7 @@ namespace _Source { # endif // ^^^ workaround ^^^ template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const edge_reference_t<_G>& uv) { { _Fake_copy_init(source(__g, uv)) }; // intentional ADL }; @@ -1353,7 +1372,7 @@ namespace _Find_vertex_edge { }; template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_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 }; @@ -1364,7 +1383,7 @@ namespace _Find_vertex_edge { }; template - concept _Has_id_ADL = _HasClassOrEnumType<_G> // + concept _Has_id_ADL = _HasClassOrEnumType<_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 }; @@ -1501,7 +1520,7 @@ namespace _Contains_edge { # endif // ^^^ workaround ^^^ template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_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 }; @@ -1557,7 +1576,7 @@ namespace _Contains_edge { * @tparam G The graph type. * @param g A graph instance. * @param uv An edge reference. - * @return An edge_descriptor with the source_id and target_id. + * @return An edge_info with the source_id and target_id. */ template requires(_Choice_ref<_G&>._Strategy != _St_ref::_None) @@ -1600,7 +1619,7 @@ namespace _Partition_id { { _Fake_copy_init(u.partition_id(__g)) }; }; template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const vertex_reference_t<_G>& u) { { _Fake_copy_init(partition_id(__g, u)) }; // intentional ADL }; @@ -1611,7 +1630,7 @@ namespace _Partition_id { }; template - concept _Has_id_ADL = _HasClassOrEnumType<_G> // + concept _Has_id_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid) { { _Fake_copy_init(partition_id(__g, uid)) }; // intentional ADL }; @@ -1633,7 +1652,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}; } @@ -1685,7 +1704,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(_AlwaysFalse<_G>, "partition_id(g,u) is not defined and the default implementation cannot be evaluated"); @@ -1713,7 +1732,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(_AlwaysFalse<_G>, "partition_id(g,uid) is not defined and the default implementation cannot be evaluated"); @@ -1746,7 +1765,7 @@ namespace _NumVertices { { _Fake_copy_init(__g.num_vertices(__g)) }; }; template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g) { { _Fake_copy_init(num_vertices(__g)) }; // intentional ADL }; @@ -1757,7 +1776,7 @@ namespace _NumVertices { }; template - concept _Has_id_ADL = _HasClassOrEnumType<_G> // + concept _Has_id_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, partition_id_t<_G> pid) { { _Fake_copy_init(num_vertices(__g, pid)) }; // intentional ADL }; @@ -1829,7 +1848,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 size(vertices(__g, pid)); // default impl } else { @@ -1857,7 +1876,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 size(vertices(__g)); // default impl } else { @@ -1888,7 +1907,7 @@ namespace _Degree { { _Fake_copy_init(u.degree(__g)) }; }; template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const vertex_reference_t<_G>& u) { { _Fake_copy_init(degree(__g, u)) }; // intentional ADL }; @@ -1899,7 +1918,7 @@ namespace _Degree { }; template - concept _Has_id_ADL = _HasClassOrEnumType<_G> // + concept _Has_id_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid) { { _Fake_copy_init(degree(__g, uid)) }; // intentional ADL }; @@ -1972,7 +1991,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 size(edges(__g, u)); // default impl } else { @@ -2000,7 +2019,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 size(edges(__g, uid)); // default impl } else { @@ -2033,7 +2052,7 @@ namespace _Vertex_value { { _Fake_copy_init(u.vertex_value(__g)) }; }; template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, vertex_reference_t<_G> u) { { _Fake_copy_init(vertex_value(__g, u)) }; // intentional ADL }; @@ -2113,7 +2132,7 @@ namespace _Edge_value { { _Fake_copy_init(uv.edge_value(__g)) }; }; template - concept _Has_adjl_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_adjl_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, edge_reference_t<_G> uv) { { _Fake_copy_init(edge_value(__g, uv)) }; // intentional ADL }; @@ -2128,7 +2147,7 @@ namespace _Edge_value { { _Fake_copy_init(__e.edge_value()) }; }; template - concept _Has_edgl_ref_ADL = _HasClassOrEnumType<_E> // + concept _Has_edgl_ref_ADL = _HasClassOrEnumType<_E> // && requires(_E&& __e) { { _Fake_copy_init(edge_value(__e)) }; // intentional ADL }; @@ -2181,7 +2200,7 @@ namespace _Edge_value { noexcept(_Fake_copy_init(declval>()))}; // first element of tuple/pair } else if constexpr (_is_edge_desc<_E>) { return {_St_edgl_ref::_EDesc_id, - noexcept(_Fake_copy_init(declval()))}; // edge_value of edge_descriptor + noexcept(_Fake_copy_init(declval()))}; // edge_value of edge_info } else { return {_St_edgl_ref::_None}; } @@ -2217,7 +2236,7 @@ namespace _Edge_value { } else if constexpr (_Strat_ref == _St_adjl_ref::_Non_member) { return edge_value(__g, uv); // intentional ADL } else if constexpr (_Strat_ref == _St_adjl_ref::_Auto_eval) { - return uv; // intentional ADL + return uv; // intentional ADL } else { static_assert(_AlwaysFalse<_G>, "edge_value(g,uv) must be defined for the graph"); } @@ -2230,7 +2249,7 @@ namespace _Edge_value { * * Default implementation: * get<2>(e) for tuple - * e.value for edge_descriptor + * e.value for edge_info * * @tparam E The edgelist value_type. * @param e A edgelist edge instance. @@ -2246,7 +2265,7 @@ namespace _Edge_value { } else if constexpr (_Strat_ref == _St_edgl_ref::_Non_member) { return edge_value(__e); // intentional ADL } else if constexpr (_Strat_ref == _St_edgl_ref::_Tuple_id) { - return get<2>(__e); // first element of tuple/pair + return get<2>(__e); // first element of tuple/pair } else if constexpr (_Strat_ref == _St_edgl_ref::_EDesc_id) { return __e.value; } else { @@ -2293,7 +2312,7 @@ namespace _Graph_value { { _Fake_copy_init(__g.graph_value()) }; }; template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g) { { _Fake_copy_init(graph_value(__g)) }; // intentional ADL }; @@ -2365,7 +2384,7 @@ namespace _Num_partitions { { _Fake_copy_init(__g.num_partitions()) }; }; template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g) { { _Fake_copy_init(num_partitions(__g)) }; // intentional ADL }; @@ -2419,7 +2438,7 @@ namespace _Num_partitions { } else if constexpr (_Strat_ref == _St_ref::_Non_member) { return num_partitions(__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(_AlwaysFalse<_G>, "num_partitions(g) is not defined and the default implementation cannot be evaluated"); @@ -2449,7 +2468,7 @@ namespace _HasEdge { { _Fake_copy_init(__g.has_edge()) }; }; template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g) { { _Fake_copy_init(has_edge(__g)) }; // intentional ADL }; diff --git a/include/graph/detail/graph_using.hpp b/include/graph/detail/graph_using.hpp index 40ba5db..d548f18 100644 --- a/include/graph/detail/graph_using.hpp +++ b/include/graph/detail/graph_using.hpp @@ -20,6 +20,9 @@ using std::declval; using std::allocator; using std::allocator_traits; +using std::iter_difference_t; +using std::iter_value_t; + // functional types using std::plus; using std::less; @@ -30,6 +33,7 @@ using std::invoke; // optional types using std::optional; +using std::conditional_t; // type traits using std::is_arithmetic_v; diff --git a/include/graph/edgelist.hpp b/include/graph/edgelist.hpp index 0e7e46f..ad0444a 100644 --- a/include/graph/edgelist.hpp +++ b/include/graph/edgelist.hpp @@ -55,11 +55,11 @@ // tuple // tuple // -// edge_descriptor : {source_id, target_id} -// edge_descriptor : {source_id, target_id, EV} +// edge_info : {source_id, target_id} +// edge_info : {source_id, target_id, EV} // -// edge_descriptor : {source_id, target_id, edge} -// edge_descriptor : {source_id, target_id, edge, EV} +// edge_info : {source_id, target_id, edge} +// edge_info : {source_id, target_id, edge, EV} // // Naming conventions // ----------------------------------------------------------------------------- diff --git a/include/graph/graph.hpp b/include/graph/graph.hpp index 3b5a08c..7a4c41d 100644 --- a/include/graph/graph.hpp +++ b/include/graph/graph.hpp @@ -24,7 +24,7 @@ #include #include -#include "graph_descriptors.hpp" +#include "graph_info.hpp" #include "detail/graph_cpo.hpp" @@ -51,8 +51,8 @@ // EI uvi,vwi Edge iterator // EVF evf Edge Value Function: evf(uv) -> value // -// ELR elr Edge List Range; an arbitrary range where its values can be projected to be an edge_descriptor. -// Proj proj Projection function: proj(y) -> edge_descriptor<...>, where y is the value type of an ELR +// ELR elr Edge List Range; an arbitrary range where its values can be projected to be an edge_info. +// Proj proj Projection function: proj(y) -> edge_info<...>, where y is the value type of an ELR #ifndef GRAPH_HPP # define GRAPH_HPP diff --git a/include/graph/graph_descriptors.hpp b/include/graph/graph_info.hpp similarity index 79% rename from include/graph/graph_descriptors.hpp rename to include/graph/graph_info.hpp index b1ff86b..4aa29fb 100644 --- a/include/graph/graph_descriptors.hpp +++ b/include/graph/graph_info.hpp @@ -4,12 +4,12 @@ namespace graph { // -// vertex_descriptor +// vertex_info // for(auto&& [uid, u] : vertexlist(g)) // for(auto&& [uid, u, value] : vertexlist(g, [](vertex_reference_t u) { return ...; } ) // template -struct vertex_descriptor { +struct vertex_info { using id_type = VId; // e.g. vertex_id_t using vertex_type = V; // e.g. vertex_reference_t using value_type = VV; // e.g. vertex_value_t @@ -19,7 +19,7 @@ struct vertex_descriptor { value_type value; }; template -struct vertex_descriptor { +struct vertex_info { using id_type = VId; using vertex_type = V; using value_type = void; @@ -28,7 +28,7 @@ struct vertex_descriptor { vertex_type vertex; }; template -struct vertex_descriptor { +struct vertex_info { using id_type = VId; using vertex_type = void; using value_type = VV; @@ -37,7 +37,7 @@ struct vertex_descriptor { value_type value; }; template -struct vertex_descriptor { +struct vertex_info { using id_type = VId; using vertex_type = void; using value_type = void; @@ -46,10 +46,10 @@ struct vertex_descriptor { }; template -using copyable_vertex_t = vertex_descriptor; // {id, value} +using copyable_vertex_t = vertex_info; // {id, value} // -// edge_descriptor +// edge_info // // for(auto&& [target_id, uv] : incidence(g,u)) // for(auto&& [target_id, uv, value] : incidence(g,u, [](edge_reference_t uv) { return ...; }) @@ -58,7 +58,7 @@ using copyable_vertex_t = vertex_descriptor; // {id, value} // for(auto&& [source_id, target_id, uv, value] : incidence(g,u, [](edge_reference_t uv) { return ...; }) // template -struct edge_descriptor { +struct edge_info { using source_id_type = VId; // e.g. vertex_id_t when Sourced==true, or void using target_id_type = VId; // e.g. vertex_id_t using edge_type = E; // e.g. edge_reference_t or void @@ -71,7 +71,7 @@ struct edge_descriptor { }; template -struct edge_descriptor { +struct edge_info { using source_id_type = VId; using target_id_type = VId; using edge_type = E; @@ -82,7 +82,7 @@ struct edge_descriptor { edge_type edge; }; template -struct edge_descriptor { +struct edge_info { using source_id_type = VId; using target_id_type = VId; using edge_type = void; @@ -92,7 +92,7 @@ struct edge_descriptor { target_id_type target_id; }; template -struct edge_descriptor { +struct edge_info { using source_id_type = VId; using target_id_type = VId; using edge_type = void; @@ -104,7 +104,7 @@ struct edge_descriptor { }; template -struct edge_descriptor { +struct edge_info { using source_id_type = void; using target_id_type = VId; using edge_type = E; @@ -115,7 +115,7 @@ struct edge_descriptor { value_type value; }; template -struct edge_descriptor { +struct edge_info { using source_id_type = void; using target_id_type = VId; using edge_type = E; @@ -126,7 +126,7 @@ struct edge_descriptor { }; template -struct edge_descriptor { +struct edge_info { using source_id_type = void; using target_id_type = VId; using edge_type = void; @@ -136,7 +136,7 @@ struct edge_descriptor { value_type value; }; template -struct edge_descriptor { +struct edge_info { using source_id_type = void; using target_id_type = VId; using edge_type = void; @@ -151,7 +151,7 @@ struct edge_descriptor { // for(auto&& [vid,uv] : edges_view(g, u) ) // //template -//using targeted_edge = edge_descriptor; // {target_id, edge, [, value]} +//using targeted_edge = edge_info; // {target_id, edge, [, value]} // // sourced_edge @@ -159,7 +159,7 @@ struct edge_descriptor { // for(auto&& [uid,vid,uv] : sourced_edges_view(g, u) ) // //template -//using sourced_edge = edge_descriptor; // {source_id, target_id, edge, [, value]} +//using sourced_edge = edge_info; // {source_id, target_id, edge, [, value]} // // edgelist_edge @@ -167,19 +167,19 @@ struct edge_descriptor { // for(auto&& [uid,vid,uv] : edges_view(g) ) // template -using edgelist_edge = edge_descriptor; // {source_id, target_id [, edge] [, value]} +using edgelist_edge = edge_info; // {source_id, target_id [, edge] [, value]} // // copyable_edge_t // template -using copyable_edge_t = edge_descriptor; // {source_id, target_id [, value]} +using copyable_edge_t = edge_info; // {source_id, target_id [, value]} // -// neighbor_descriptor (for adjacency) +// neighbor_info (for adjacency) // template -struct neighbor_descriptor { +struct neighbor_info { using source_id_type = VId; // e.g. vertex_id_t when Sourced==true, or void using target_id_type = VId; // e.g. vertex_id_t using vertex_type = V; // e.g. vertex_reference_t or void @@ -192,7 +192,7 @@ struct neighbor_descriptor { }; template -struct neighbor_descriptor { +struct neighbor_info { using source_id_type = void; using target_id_type = VId; using vertex_type = V; @@ -204,7 +204,7 @@ struct neighbor_descriptor { }; template -struct neighbor_descriptor { +struct neighbor_info { using source_id_type = void; using target_id_type = VId; using vertex_type = V; @@ -215,7 +215,7 @@ struct neighbor_descriptor { }; template -struct neighbor_descriptor { +struct neighbor_info { using source_id_type = void; using target_id_type = VId; using vertex_type = void; @@ -226,7 +226,7 @@ struct neighbor_descriptor { }; template -struct neighbor_descriptor { +struct neighbor_info { using source_id_type = void; using target_id_type = VId; using vertex_type = void; @@ -236,7 +236,7 @@ struct neighbor_descriptor { }; template -struct neighbor_descriptor { +struct neighbor_info { using source_id_type = VId; using target_id_type = VId; using vertex_type = V; @@ -248,7 +248,7 @@ struct neighbor_descriptor { }; template -struct neighbor_descriptor { +struct neighbor_info { using source_id_type = VId; using target_id_type = VId; using vertex_type = void; @@ -260,7 +260,7 @@ struct neighbor_descriptor { }; template -struct neighbor_descriptor { +struct neighbor_info { using source_id_type = VId; using target_id_type = VId; using vertex_type = void; @@ -273,8 +273,8 @@ struct neighbor_descriptor { // // copyable_edge_t // -template // For exposition only -using copyable_neighbor_t = neighbor_descriptor; // {source_id, target_id [, value]} +template // For exposition only +using copyable_neighbor_t = neighbor_info; // {source_id, target_id [, value]} // // view concepts @@ -294,8 +294,8 @@ concept copyable_neighbor = std::convertible_to> template inline constexpr bool is_sourced_v = false; template -inline constexpr bool is_sourced_v> = true; +inline constexpr bool is_sourced_v> = true; template -inline constexpr bool is_sourced_v> = true; +inline constexpr bool is_sourced_v> = true; } // namespace graph diff --git a/include/graph/views/breadth_first_search.hpp b/include/graph/views/breadth_first_search.hpp index b563a75..24bca04 100644 --- a/include/graph/views/breadth_first_search.hpp +++ b/include/graph/views/breadth_first_search.hpp @@ -244,7 +244,7 @@ class vertices_breadth_first_search_view : public bfs_base { class iterator { public: using iterator_category = std::input_iterator_tag; - using value_type = vertex_descriptor; + using value_type = vertex_info; using reference = value_type&; using const_reference = const value_type&; using rvalue_reference = value_type&&; @@ -258,7 +258,7 @@ class vertices_breadth_first_search_view : public bfs_base { // shadow_vertex_value_type: ptr if vertex_value_type is ref or ptr, value otherwise using shadow_vertex_type = remove_reference_t; using shadow_value_type = - vertex_descriptor, shadow_vertex_type*, _detail::ref_to_ptr>; + vertex_info, shadow_vertex_type*, _detail::ref_to_ptr>; union internal_value { value_type value_; @@ -364,7 +364,7 @@ class vertices_breadth_first_search_view : public bfs_base; + using value_type = vertex_info; using reference = value_type&; using const_reference = const value_type&; using rvalue_reference = value_type&&; @@ -377,7 +377,7 @@ class vertices_breadth_first_search_view : public bfs_base; - using shadow_value_type = vertex_descriptor, shadow_vertex_type*, void>; + using shadow_value_type = vertex_info, shadow_vertex_type*, void>; union internal_value { value_type value_; @@ -485,7 +485,7 @@ class edges_breadth_first_search_view : public bfs_base { class iterator { public: using iterator_category = std::input_iterator_tag; - using value_type = edge_descriptor; + using value_type = edge_info; using reference = value_type&; using const_reference = const value_type&; using rvalue_reference = value_type&&; @@ -499,7 +499,7 @@ class edges_breadth_first_search_view : public bfs_base { // shadow_vertex_value_type: ptr if vertex_value_type is ref or ptr, value otherwise using shadow_edge_type = remove_reference_t; using shadow_value_type = - edge_descriptor>; + edge_info>; union internal_value { value_type value_; @@ -600,7 +600,7 @@ class edges_breadth_first_search_view : public bfs_base class iterator { public: using iterator_category = std::input_iterator_tag; - using value_type = edge_descriptor; + using value_type = edge_info; using reference = value_type&; using const_reference = const value_type&; using rvalue_reference = value_type&&; @@ -613,7 +613,7 @@ class edges_breadth_first_search_view : public bfs_base // avoid difficulty in undefined vertex reference value in value_type // shadow_vertex_value_type: ptr if vertex_value_type is ref or ptr, value otherwise using shadow_edge_type = remove_reference_t; - using shadow_value_type = edge_descriptor; + using shadow_value_type = edge_info; union internal_value { value_type value_; @@ -678,8 +678,8 @@ class edges_breadth_first_search_view : public bfs_base namespace views { // - // vertices_breadth_first_search(g,seed) -> vertex_descriptor[vid,v] - // vertices_breadth_first_search(g,seed,vvf) -> vertex_descriptor[vid,v,value] + // vertices_breadth_first_search(g,seed) -> vertex_info[vid,v] + // vertices_breadth_first_search(g,seed,vvf) -> vertex_info[vid,v,value] // namespace _Vertices_BFS { # if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 @@ -689,7 +689,7 @@ namespace views { # endif // ^^^ workaround ^^^ template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid, _Alloc alloc) { { _Fake_copy_init(vertices_breadth_first_search(__g, uid, alloc)) }; // intentional ADL }; @@ -776,7 +776,7 @@ namespace views { constexpr _St_ref _Strat_ref = _Choice_ref<_G&, _Alloc>._Strategy; if constexpr (_Strat_ref == _St_ref::_Non_member) { - return vertices_breadth_first_search(__g, seed, alloc); // intentional ADL + return vertices_breadth_first_search(__g, seed, alloc); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { return vertices_breadth_first_search_view<_G, void>(__g, seed, alloc); // default impl } else { @@ -809,7 +809,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_breadth_first_search(__g, seed, vvf, alloc); // intentional ADL + return vertices_breadth_first_search(__g, seed, vvf, alloc); // intentional ADL } else if constexpr (_Strat_ref_vvf == _St_ref_vvf::_Auto_eval) { return vertices_breadth_first_search_view<_G, _VVF>(__g, seed, vvf, alloc); // default impl } else { @@ -827,8 +827,8 @@ namespace views { // - // edges_breadth_first_search(g,seed) -> edge_descriptor[vid,uv] - // edges_breadth_first_search(g,seed,evf) -> edge_descriptor[vid,uv,value] + // edges_breadth_first_search(g,seed) -> edge_info[vid,uv] + // edges_breadth_first_search(g,seed,evf) -> edge_info[vid,uv,value] // namespace _Edges_BFS { # if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 @@ -838,7 +838,7 @@ namespace views { # endif // ^^^ workaround ^^^ template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid, _Alloc alloc) { { _Fake_copy_init(edges_breadth_first_search(__g, uid, alloc)) }; // intentional ADL }; @@ -927,7 +927,7 @@ namespace views { constexpr _St_ref _Strat_ref = _Choice_ref<_G&, _Alloc>._Strategy; if constexpr (_Strat_ref == _St_ref::_Non_member) { - return edges_breadth_first_search(__g, seed, alloc); // intentional ADL + return edges_breadth_first_search(__g, seed, alloc); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { return edges_breadth_first_search_view<_G, void, false>(__g, seed, alloc); // default impl } else { @@ -960,7 +960,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_breadth_first_search(__g, seed, alloc); // intentional ADL + return edges_breadth_first_search(__g, seed, alloc); // intentional ADL } else if constexpr (_Strat_ref_evf == _St_ref_evf::_Auto_eval) { return edges_breadth_first_search_view<_G, _EVF, false>(__g, seed, evf, alloc); // default impl } else { @@ -978,8 +978,8 @@ namespace views { // - // sourced_edges_breadth_first_search(g,seed) -> edge_descriptor[uid,vid,uv] - // sourced_edges_breadth_first_search(g,seed,evf) -> edge_descriptor[uid,vid,uv,value] + // sourced_edges_breadth_first_search(g,seed) -> edge_info[uid,vid,uv] + // sourced_edges_breadth_first_search(g,seed,evf) -> edge_info[uid,vid,uv,value] // namespace _Sourced_Edges_BFS { # if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 @@ -1080,7 +1080,7 @@ namespace views { constexpr _St_ref _Strat_ref = _Choice_ref<_G&, _Alloc>._Strategy; if constexpr (_Strat_ref == _St_ref::_Non_member) { - return sourced_edges_breadth_first_search(__g, seed, alloc); // intentional ADL + return sourced_edges_breadth_first_search(__g, seed, alloc); // intentional ADL } else if constexpr (_Strat_ref == _St_ref::_Auto_eval) { return edges_breadth_first_search_view<_G, void, true>(__g, seed, alloc); // default impl } else { @@ -1113,7 +1113,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_breadth_first_search(__g, seed, alloc); // intentional ADL + return sourced_edges_breadth_first_search(__g, seed, alloc); // intentional ADL } else if constexpr (_Strat_ref_evf == _St_ref_evf::_Auto_eval) { return edges_breadth_first_search_view<_G, _EVF, true>(__g, seed, evf, alloc); // default impl } else { diff --git a/include/graph/views/depth_first_search.hpp b/include/graph/views/depth_first_search.hpp index 8488331..2bd7a56 100644 --- a/include/graph/views/depth_first_search.hpp +++ b/include/graph/views/depth_first_search.hpp @@ -230,7 +230,7 @@ class vertices_depth_first_search_view : public dfs_base { class iterator { public: using iterator_category = std::input_iterator_tag; - using value_type = vertex_descriptor; + using value_type = vertex_info; using reference = value_type&; using const_reference = const value_type&; using rvalue_reference = value_type&&; @@ -244,7 +244,7 @@ class vertices_depth_first_search_view : public dfs_base { // shadow_vertex_value_type: ptr if vertex_value_type is ref or ptr, value otherwise using shadow_vertex_type = remove_reference_t; using shadow_value_type = - vertex_descriptor, shadow_vertex_type*, _detail::ref_to_ptr>; + vertex_info, shadow_vertex_type*, _detail::ref_to_ptr>; union internal_value { value_type value_; @@ -340,7 +340,7 @@ class vertices_depth_first_search_view : public dfs_base; + using value_type = vertex_info; using reference = value_type&; using const_reference = const value_type&; using rvalue_reference = value_type&&; @@ -353,7 +353,7 @@ class vertices_depth_first_search_view : public dfs_base; - using shadow_value_type = vertex_descriptor, shadow_vertex_type*, void>; + using shadow_value_type = vertex_info, shadow_vertex_type*, void>; union internal_value { value_type value_; @@ -456,7 +456,7 @@ class edges_depth_first_search_view : public dfs_base { class iterator { public: using iterator_category = std::input_iterator_tag; - using value_type = edge_descriptor; + using value_type = edge_info; using reference = value_type&; using const_reference = const value_type&; using rvalue_reference = value_type&&; @@ -470,7 +470,7 @@ class edges_depth_first_search_view : public dfs_base { // shadow_vertex_value_type: ptr if vertex_value_type is ref or ptr, value otherwise using shadow_edge_type = remove_reference_t; using shadow_value_type = - edge_descriptor>; + edge_info>; union internal_value { value_type value_; @@ -565,7 +565,7 @@ class edges_depth_first_search_view : public dfs_base; + using value_type = edge_info; using reference = value_type&; using const_reference = const value_type&; using rvalue_reference = value_type&&; @@ -578,7 +578,7 @@ class edges_depth_first_search_view : public dfs_base; - using shadow_value_type = edge_descriptor; + using shadow_value_type = edge_info; union internal_value { value_type value_; @@ -640,8 +640,8 @@ class edges_depth_first_search_view : public dfs_base vertex_descriptor[vid,v] - // vertices_depth_first_search(g,seed,vvf) -> vertex_descriptor[vid,v,value] + // vertices_depth_first_search(g,seed) -> vertex_info[vid,v] + // vertices_depth_first_search(g,seed,vvf) -> vertex_info[vid,v,value] // namespace _Vertices_DFS { # if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 @@ -651,7 +651,7 @@ namespace views { # endif // ^^^ workaround ^^^ template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid, _Alloc alloc) { { _Fake_copy_init(vertices_depth_first_search(__g, uid, alloc)) }; // intentional ADL }; @@ -739,7 +739,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 { @@ -772,7 +772,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 { @@ -790,8 +790,8 @@ namespace views { // - // edges_depth_first_search(g,seed) -> edge_descriptor[vid,uv] - // edges_depth_first_search(g,seed,evf) -> edge_descriptor[vid,uv,value] + // edges_depth_first_search(g,seed) -> edge_info[vid,uv] + // edges_depth_first_search(g,seed,evf) -> edge_info[vid,uv,value] // namespace _Edges_DFS { # if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 @@ -801,7 +801,7 @@ namespace views { # endif // ^^^ workaround ^^^ template - concept _Has_ref_ADL = _HasClassOrEnumType<_G> // + concept _Has_ref_ADL = _HasClassOrEnumType<_G> // && requires(_G&& __g, const vertex_id_t<_G>& uid, _Alloc alloc) { { _Fake_copy_init(edges_depth_first_search(__g, uid, alloc)) }; // intentional ADL }; @@ -890,7 +890,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 { @@ -923,7 +923,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 { @@ -941,8 +941,8 @@ namespace views { // - // 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] + // sourced_edges_depth_first_search(g,seed) -> edge_info[uid,vid,uv] + // sourced_edges_depth_first_search(g,seed,evf) -> edge_info[uid,vid,uv,value] // namespace _Sourced_Edges_DFS { # if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 @@ -1043,7 +1043,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 { @@ -1077,7 +1077,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 { diff --git a/include/graph/views/edgelist.hpp b/include/graph/views/edgelist.hpp index a0ff653..dfb24fa 100644 --- a/include/graph/views/edgelist.hpp +++ b/include/graph/views/edgelist.hpp @@ -2,21 +2,21 @@ #include "graph/graph.hpp" // -// edgelist(g) -> edge_descriptor -> {source_id, target_id, edge&} -// edgelist(g,evf) -> edge_descriptor -> {source_id, target_id, edge&, value} +// edgelist(g) -> edge_info -> {source_id, target_id, edge&} +// edgelist(g,evf) -> edge_info -> {source_id, target_id, edge&, value} // -// edgelist(g,uid) -> edge_descriptor -> {source_id, target_id, edge&} -// edgelist(g,uid,evf) -> edge_descriptor -> {source_id, target_id, edge&, value} +// edgelist(g,uid) -> edge_info -> {source_id, target_id, edge&} +// edgelist(g,uid,evf) -> edge_info -> {source_id, target_id, edge&, value} // -// edgelist(elr,proj) -> edge_descriptor -> {source_id, target_id, edge&}, where VId is defined by proj and E is range_value_t& -// edgelist(elr,proj) -> edge_descriptor -> {source_id, target_id, edge&, Value}, where VId and Value defined by proj and E is range_value_t& +// edgelist(elr,proj) -> edge_info -> {source_id, target_id, edge&}, where VId is defined by proj and E is range_value_t& +// edgelist(elr,proj) -> edge_info -> {source_id, target_id, edge&, Value}, where VId and Value defined by proj and E is range_value_t& // Note: proj(range_value_t&) is a projection and determines whether to return a value member or not // -// basic_edgelist(g) -> edge_descriptor -> {source_id, target_id} +// basic_edgelist(g) -> edge_info -> {source_id, target_id} // -// basic_edgelist(g,uid) -> edge_descriptor -> {source_id, target_id} +// basic_edgelist(g,uid) -> edge_info -> {source_id, target_id} // -// basic_edgelist(elr,proj) -> edge_descriptor -> {source_id, target_id}, where VId is defined by proj +// basic_edgelist(elr,proj) -> edge_info -> {source_id, target_id}, where VId is defined by proj // Note: proj(range_value_t&) is a projection and determines whether to return a value member or not // // given: auto evf = [&g](edge_reference_t uv) { return edge_value(uv); } @@ -118,7 +118,7 @@ class edgelist_iterator : public edgelist_iterator_base { using edge_value_type = invoke_result_t; using iterator_category = forward_iterator_tag; - using value_type = edge_descriptor; + using value_type = edge_info; using difference_type = range_difference_t; using pointer = value_type*; using const_pointer = const value_type*; @@ -146,7 +146,7 @@ class edgelist_iterator : public edgelist_iterator_base { // shadow_vertex_value_type: ptr if vertex_value_type is ref or ptr, value otherwise using shadow_edge_type = remove_reference_t; using shadow_value_type = - edge_descriptor>; + edge_info>; union internal_value { value_type value_; @@ -220,7 +220,7 @@ class edgelist_iterator : public edgelist_iterator_base { using edge_value_type = void; using iterator_category = forward_iterator_tag; - using value_type = edge_descriptor; + using value_type = edge_info; using difference_type = range_difference_t; using pointer = value_type*; using const_pointer = const value_type*; @@ -232,7 +232,7 @@ class edgelist_iterator : public edgelist_iterator_base { // avoid difficulty in undefined vertex reference value in value_type // shadow_vertex_value_type: ptr if vertex_value_type is ref or ptr, value otherwise using shadow_edge_type = remove_reference_t; - using shadow_value_type = edge_descriptor; + using shadow_value_type = edge_info; union internal_value { value_type value_; @@ -299,7 +299,7 @@ class edgelist_iterator : public edgelist_iterator_base { /** - * @brief Iterator for a range with values that can be projected to a edge_descriptor. + * @brief Iterator for a range with values that can be projected to a edge_info. * * @tparam ELR Graph type * @tparam Proj Edge Value Function type @@ -318,7 +318,7 @@ class edgelist_range_iterator { using value_type = invoke_result_t; using vertex_id_type = - typename value_type::target_id_type; // If this generates an error then value_type is not an edge_descriptor + typename value_type::target_id_type; // If this generates an error then value_type is not an edge_info using iterator_category = forward_iterator_tag; @@ -544,7 +544,7 @@ namespace views { * @tparam G The graph type. * @param g A graph instance. * @return A range of edges in graph g where the range value_type is - * edge_descriptor,false,vertex_reference_t,void> + * edge_info,false,vertex_reference_t,void> */ template requires(_Choice_all<_G&>._Strategy != _St_adjlist_all::_None) @@ -575,7 +575,7 @@ namespace views { * @tparam G The graph type. * @param g A graph instance. * @return A range of edges in graph g where the range value_type is - * edge_descriptor,false,vertex_reference_t,void> + * edge_info,false,vertex_reference_t,void> */ template requires(_Choice_all_evf<_G&, EVF>._Strategy != _St_adjlist_all::_None) @@ -607,7 +607,7 @@ namespace views { * @tparam G The graph type. * @param __g A graph instance. * @return A range of edges in graph __g where the range value_type is - * edge_descriptor,false,vertex_reference_t,void> + * edge_info,false,vertex_reference_t,void> */ template requires(_Choice_idrng<_G&>._Strategy != _St_adjlist_idrng::_None) @@ -639,7 +639,7 @@ namespace views { * @tparam _G The graph type. * @param g A graph instance. * @return A range of edges in graph g where the range value_type is - * edge_descriptor,false,vertex_reference_t<_G>,void> + * edge_info,false,vertex_reference_t<_G>,void> */ template requires(_Choice_idrng_evf<_G&, EVF>._Strategy != _St_adjlist_idrng::_None) @@ -666,8 +666,8 @@ namespace views { * @brief Create an edgelist from an arbitrary range using a projection. * * The projection must return a value of one of the following types: - * edge_descriptor&, void> - * edge_descriptor&, Value> + * edge_info&, void> + * edge_info&, Value> * where Id is an integral type defined by proj, and Value is also a type defined by proj. * * Complexity: O(n) @@ -676,12 +676,12 @@ namespace views { * ??? * * @tparam ELR The Edge List Range type. This can be any forward_range. - * @tparam Proj The projection function type that converts a range_value_t to an edge_descriptor. + * @tparam Proj The projection function type that converts a range_value_t to an edge_info. * @param elr The Edge List Range instance. - * @param proj The projection instance that converts a range_value_t to an edge_descriptor. If - * the range_value_t is already a valid edge_descriptor then identity can be used. - * @return A range of edge_descriptors projected from elr. The value member type can be void or non-void. - * If it is void, the value member will not exist in the returned edge_descriptor. + * @param proj The projection instance that converts a range_value_t to an edge_info. If + * the range_value_t is already a valid edge_info then identity can be used. + * @return A range of edge_infos projected from elr. The value member type can be void or non-void. + * If it is void, the value member will not exist in the returned edge_info. */ template requires(_Choice_elr_proj._Strategy != _St_adjlist_all::_None) diff --git a/include/graph/views/incidence.hpp b/include/graph/views/incidence.hpp index 6c5e1cc..5a4d976 100644 --- a/include/graph/views/incidence.hpp +++ b/include/graph/views/incidence.hpp @@ -4,10 +4,10 @@ #include // -// incidence(g,uid) -> edge_descriptor -> {target_id, edge&} -// incidence(g,uid,evf) -> edge_descriptor -> {target_id, edge&, value} +// incidence(g,uid) -> edge_info -> {target_id, edge&} +// incidence(g,uid,evf) -> edge_info -> {target_id, edge&, value} // -// basic_incidence(g,uid,evf) -> edge_descriptor -> {target_id} +// basic_incidence(g,uid,evf) -> edge_info -> {target_id} // // given: auto evf = [&g](edge_reference_t uv) { return edge_value(g,uv) }; // @@ -47,7 +47,7 @@ class incidence_iterator : _detail::_source_vertex; using iterator_category = forward_iterator_tag; - using value_type = edge_descriptor; + using value_type = edge_info; using difference_type = range_difference_t; using pointer = value_type*; using const_pointer = const value_type*; @@ -72,9 +72,8 @@ class incidence_iterator : _detail::_source_vertex; - using shadow_value_type = - edge_descriptor>; + using shadow_edge_type = remove_reference_t; + using shadow_value_type = edge_info>; union internal_value { value_type value_; @@ -154,7 +153,7 @@ class incidence_iterator using edge_value_type = void; using iterator_category = forward_iterator_tag; - using value_type = edge_descriptor; + using value_type = edge_info; using difference_type = range_difference_t; using pointer = value_type*; using const_pointer = const value_type*; @@ -166,7 +165,7 @@ class incidence_iterator // avoid difficulty in undefined vertex reference value in value_type // shadow_vertex_value_type: ptr if vertex_value_type is ref or ptr, value otherwise using shadow_edge_type = remove_reference_t; - using shadow_value_type = edge_descriptor; + using shadow_value_type = edge_info; union internal_value { value_type value_; @@ -312,7 +311,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) @@ -343,7 +342,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 96d5e7c..a37ba71 100644 --- a/include/graph/views/neighbors.hpp +++ b/include/graph/views/neighbors.hpp @@ -3,10 +3,10 @@ #include "graph/graph_utility.hpp" // -// neighbors(g,uid) -> neighbor_descriptor -> {target_id, vertex&} -// neighbors(g,uid,vvf) -> neighbor_descriptor -> {target_id, vertex&, value]} +// neighbors(g,uid) -> neighbor_info -> {target_id, vertex&} +// neighbors(g,uid,vvf) -> neighbor_info -> {target_id, vertex&, value]} // -// basic_neighbors(g,uid) -> neighbor_descriptor -> {target_id} +// basic_neighbors(g,uid) -> neighbor_info -> {target_id} // // given: auto vvf = [&g](vertex_reference_t v) { return vertex_value(g,v); } // @@ -51,7 +51,7 @@ class neighbor_iterator using edge_type = edge_t; using iterator_category = forward_iterator_tag; - using value_type = neighbor_descriptor; + using value_type = neighbor_info; using difference_type = range_difference_t; using pointer = value_type*; using const_pointer = const value_type*; @@ -78,7 +78,7 @@ class neighbor_iterator // shadow_vertex_value_type: ptr if vertex_value_type is ref or ptr, value otherwise using shadow_vertex_type = remove_reference_t; using shadow_value_type = - neighbor_descriptor>; + neighbor_info>; union internal_value { value_type value_; @@ -165,7 +165,7 @@ class neighbor_iterator using edge_type = edge_t; using iterator_category = forward_iterator_tag; - using value_type = neighbor_descriptor; + using value_type = neighbor_info; using difference_type = range_difference_t; using pointer = value_type*; using const_pointer = const value_type*; @@ -177,7 +177,7 @@ class neighbor_iterator // avoid difficulty in undefined vertex reference value in value_type // shadow_vertex_value_type: ptr if vertex_value_type is ref or ptr, value otherwise using shadow_vertex_type = remove_reference_t; - using shadow_value_type = neighbor_descriptor; + using shadow_value_type = neighbor_info; union internal_value { value_type value_; diff --git a/include/graph/views/vertexlist.hpp b/include/graph/views/vertexlist.hpp index e1e3770..4ca20cd 100644 --- a/include/graph/views/vertexlist.hpp +++ b/include/graph/views/vertexlist.hpp @@ -3,8 +3,8 @@ #include "graph/graph_utility.hpp" #include // -// vertexlist(g) -> vertex_descriptor -> {id, vertex& [,value]} -// basic_vertexlist(g) -> vertex_descriptor -> {id} +// vertexlist(g) -> vertex_info -> {id, vertex& [,value]} +// basic_vertexlist(g) -> vertex_info -> {id} // // given: vvf = [&g](vertex_reference_t u) -> decl_type(vertex_value(g)) { return vertex_value(g,u);} // (trailing return type is required if defined inline as vertexlist parameter) @@ -41,7 +41,7 @@ class vertexlist_iterator { using vertex_value_type = invoke_result_t; using iterator_category = forward_iterator_tag; - using value_type = vertex_descriptor, vertex_reference_type, vertex_value_type>; + using value_type = vertex_info, vertex_reference_type, vertex_value_type>; using difference_type = range_difference_t; using pointer = value_type*; using const_pointer = const value_type*; @@ -53,7 +53,7 @@ class vertexlist_iterator { // shadow_vertex_value_type: ptr if vertex_value_type is ref or ptr, value otherwise using shadow_vertex_type = remove_reference_t; using shadow_value_type = - vertex_descriptor, shadow_vertex_type*, _detail::ref_to_ptr>; + vertex_info, shadow_vertex_type*, _detail::ref_to_ptr>; union internal_value { value_type value_; @@ -123,7 +123,7 @@ class vertexlist_iterator { using vertex_value_type = void; using iterator_category = forward_iterator_tag; - using value_type = vertex_descriptor; + using value_type = vertex_info; using difference_type = range_difference_t; using pointer = value_type*; using const_pointer = const value_type*; @@ -135,7 +135,7 @@ class vertexlist_iterator { // avoid difficulty in undefined vertex reference value in value_type // shadow_vertex_value_type: ptr if vertex_value_type is ref or ptr, value otherwise using shadow_vertex_type = remove_reference_t; - using shadow_value_type = vertex_descriptor; + using shadow_value_type = vertex_info; union internal_value { value_type value_; @@ -375,16 +375,16 @@ namespace views { } /** - * @brief The number of outgoing edges of a vertex. + * @brief A range of vertices for a graph. * * Complexity: O(1) * - * Default implementation: size(edges(g, u)) + * Default implementation: * * @tparam G The graph type. * @param g A graph instance. - * @param u A vertex instance. - * @return The number of outgoing edges of vertex u. + * @param vr A range of vertices. + * @return A range of vertices. */ template requires(_Choice_rng<_G, Rng>._Strategy != _St_rng::_None) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8f27a27..c849f74 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -60,6 +60,7 @@ set(UNITTEST_SOURCES "tc_tests.cpp" "cc_tests.cpp" + "descriptor_tests.cpp" "tests.cpp" ) diff --git a/tests/bellman_shortest_paths_tests.cpp b/tests/bellman_shortest_paths_tests.cpp index c550199..db47319 100644 --- a/tests/bellman_shortest_paths_tests.cpp +++ b/tests/bellman_shortest_paths_tests.cpp @@ -92,9 +92,9 @@ auto to_string(const Predecessors& predecessors) { } template -using visited_vertex_t = vertex_descriptor, vertex_reference_t, void>; +using visited_vertex_t = vertex_info, vertex_reference_t, void>; template -using visited_edge_t = edge_descriptor, true, edge_reference_t, void>; +using visited_edge_t = edge_info, true, edge_reference_t, void>; template class empty_bellman_ford_visitor { diff --git a/tests/cc_tests.cpp b/tests/cc_tests.cpp index 9a5abd2..4f5ab80 100644 --- a/tests/cc_tests.cpp +++ b/tests/cc_tests.cpp @@ -57,7 +57,7 @@ TEST_CASE("strongly connected components test", "[strong cc]") { using value = std::ranges::range_value_t; vertex_id_t N = static_cast>(size(vertices(g))); - using edge_desc = graph::edge_descriptor, true, void, double>; + using edge_desc = graph::edge_info, true, void, double>; auto edge_proj = [](const value& val) -> edge_desc { return edge_desc{std::get<0>(val), std::get<1>(val), std::get<2>(val)}; }; diff --git a/tests/descriptor_tests.cpp b/tests/descriptor_tests.cpp new file mode 100644 index 0000000..7091fd9 --- /dev/null +++ b/tests/descriptor_tests.cpp @@ -0,0 +1,822 @@ +#include +#include +#include // contiguous +#include // random access +#include // bidirectional +#include // bidirectional +#include // forward + +#include "graph/detail/descriptor.hpp" + +#define ENABLE_DESCRIPTOR_TESTS 0 + +using namespace graph; + +using std::move; +using std::conditional_t; +using std::is_same_v; +using std::iterator_traits; +using std::vector; +using std::deque; +using std::map; +using std::list; +using std::forward_list; + +// concepts +using std::ranges::contiguous_range; +using std::ranges::random_access_range; +using std::ranges::bidirectional_range; +using std::ranges::forward_range; + +using std::forward_iterator; +using std::bidirectional_iterator; +using std::random_access_iterator; +using std::contiguous_iterator; + +using std::sentinel_for; +using std::sized_sentinel_for; +using std::disable_sized_sentinel_for; + +// ranges +//using std::ranges::begin; +//using std::ranges::end; + +// type traits +using std::ranges::range_value_t; +using std::ranges::range_size_t; +using std::ranges::iterator_t; +using std::declval; + +// We need an advance function to return the updated iterator +template +I advance(I it, std::iter_difference_t n) { + std::advance(it, n); + return it; +} + +TEST_CASE("Tuple tail") { + using Tuple = std::tuple; + using Tail = tuple_tail_t; + static_assert(is_same_v>); + + Tuple t{1, 2.0, '3'}; +} + +#if ENABLE_DESCRIPTOR_TESTS +TEMPLATE_TEST_CASE("Identifier iterator for contiguous container vector", + "[descriptor]", + (vector), + (const vector)) { + using Container = TestType; + using Iterator = _descriptor_iterator>; + using difference_type = typename iterator_traits::difference_type; + Container v = {1, 2, 3, 4, 5}; + + SECTION("iterator traits") { + using value_type = typename iterator_traits::value_type; + + static_assert(is_same_v::difference_type, + typename iterator_traits>::difference_type>); + static_assert(is_same_v::value_type, + typename iterator_traits>::difference_type>); // integral index + static_assert(is_same_v::pointer, const value_type*>); + static_assert(is_same_v::reference, const value_type&>); + static_assert(is_same_v::iterator_category, std::forward_iterator_tag>); + static_assert(is_same_v); + } + + SECTION("contiguous iterator concept") { + //static_assert(sentinel_for); + //static_assert(is_same_v() - declval())>); + //static_assert(sized_sentinel_for); + static_assert(forward_iterator); + //static_assert(bidirectional_iterator); + //static_assert(random_access_iterator); + //static_assert(contiguous_iterator); + } + + SECTION("construction") { + Iterator it; + Iterator it0(0); + Iterator it1(1); + REQUIRE(*it == 0); + REQUIRE(*it0 == 0); + REQUIRE(*it1 == 1); + } + SECTION("copy") { + Iterator it(1); + Iterator it1(it); + Iterator it2; + it2 = it1; + REQUIRE(*it1 == 1); + REQUIRE(*it2 == 1); + } + + SECTION("move") { + Iterator it(1); + Iterator it1(move(it)); + Iterator it2; + it2 = move(it1); + REQUIRE(*it1 == 1); + REQUIRE(*it2 == 1); + } + + SECTION("increment and add") { + Iterator it(1); + REQUIRE(*it == 1); + REQUIRE(*(it++) == 1); + REQUIRE(*it == 2); + REQUIRE(*(++it) == 3); + REQUIRE(*it == 3); + //REQUIRE(*(it + 2) == 5); + //REQUIRE(*(2 + it) == 5); + //REQUIRE(*(it += 2) == 5); + //REQUIRE(*it == 5); + } + + //SECTION("decrement and subtract") { + // Iterator it(5); + // REQUIRE(*it == 5); + // REQUIRE(*(it--) == 5); + // REQUIRE(*it == 4); + // REQUIRE(*(--it) == 3); + // REQUIRE(*it == 3); + // REQUIRE(*(it - 2) == 1); + // REQUIRE(*(it -= 2) == 1); + // REQUIRE(*it == 1); + //} + + SECTION("compare equality") { + Iterator it(1); + Iterator it1(1); + Iterator it2(2); + REQUIRE(it == it1); + REQUIRE(it != it2); + REQUIRE(it1 == it); + REQUIRE(it1 != it2); + REQUIRE(it2 != it); + REQUIRE(it2 != it1); + } + + //SECTION("compare relative") { + // Iterator it(1); + // Iterator it1(1); + // Iterator it2(2); + // REQUIRE(it == it1); + // REQUIRE(it != it2); + // REQUIRE(it < it2); + // REQUIRE(it <= it2); + // REQUIRE(it2 > it); + // REQUIRE(it2 >= it); + //} + + // operator[] is not tested because it will return a reference to a non-existing element for contiguous_iterator +} + +TEMPLATE_TEST_CASE("Identifier iterator for random access container deque", + "[descriptor]", + (deque), + (const deque)) { + using Container = TestType; + using Iterator = _descriptor_iterator>; + using difference_type = typename iterator_traits::difference_type; + Container v = {1, 2, 3, 4, 5}; + + SECTION("iterator traits") { + using value_type = typename iterator_traits::value_type; + + static_assert(is_same_v::difference_type, + typename iterator_traits>::difference_type>); + static_assert(is_same_v::value_type, iter_difference_t>); + static_assert(is_same_v::pointer, const value_type*>); + static_assert(is_same_v::reference, const value_type&>); + static_assert(is_same_v::iterator_category, std::forward_iterator_tag>); + //static_assert(is_same_v::iterator_concept>); // not contiguous + } + + SECTION("random access iterator concept") { + //static_assert(sentinel_for); + //static_assert(is_same_v() - declval())>); + //static_assert(sized_sentinel_for); + static_assert(forward_iterator); + //static_assert(bidirectional_iterator); + //static_assert(random_access_iterator); + //static_assert(contiguous_iterator); + } + + SECTION("construction") { + Iterator it; + Iterator it0(0); + Iterator it1(1); + REQUIRE(*it == 0); + REQUIRE(*it0 == 0); + REQUIRE(*it1 == 1); + } + SECTION("copy") { + Iterator it(1); + Iterator it1(it); + Iterator it2; + it2 = it1; + REQUIRE(*it1 == 1); + REQUIRE(*it2 == 1); + } + + SECTION("move") { + Iterator it(1); + Iterator it1(move(it)); + Iterator it2; + it2 = move(it1); + REQUIRE(*it1 == 1); + REQUIRE(*it2 == 1); + } + + SECTION("increment and add") { + Iterator it(1); + REQUIRE(*it == 1); + REQUIRE(*(it++) == 1); + REQUIRE(*it == 2); + REQUIRE(*(++it) == 3); + REQUIRE(*it == 3); + //REQUIRE(*(it + 2) == 5); + //REQUIRE(*(2 + it) == 5); + //REQUIRE(*(it += 2) == 5); + //REQUIRE(*it == 5); + } + + //SECTION("decrement and subtract") { + // Iterator it(5); + // REQUIRE(*it == 5); + // REQUIRE(*(it--) == 5); + // REQUIRE(*it == 4); + // REQUIRE(*(--it) == 3); + // REQUIRE(*it == 3); + // REQUIRE(*(it - 2) == 1); + // REQUIRE(*(it -= 2) == 1); + // REQUIRE(*it == 1); + //} + + SECTION("compare equality") { + Iterator it(1); + Iterator it1(1); + Iterator it2(2); + REQUIRE(it == it1); + REQUIRE(it != it2); + REQUIRE(it1 == it); + REQUIRE(it1 != it2); + REQUIRE(it2 != it); + REQUIRE(it2 != it1); + } + + //SECTION("compare relative") { + // Iterator it(advance(begin(v), 1)); + // Iterator it1(advance(begin(v), 1)); + // Iterator it2(advance(begin(v), 2)); + // REQUIRE(it == it1); + // REQUIRE(it != it2); + // REQUIRE(it < it2); + // REQUIRE(it <= it2); + // REQUIRE(it2 > it); + // REQUIRE(it2 >= it); + //} + + // operator[] is not tested because it will return a reference to a non-existing element for contiguous_iterator +} + +TEMPLATE_TEST_CASE("Identifier iterator for bidirectional container map", + "[descriptor]", + (map), + (const map)) { + using Container = TestType; + using Iterator = _descriptor_iterator>; + using difference_type = typename iterator_traits::difference_type; + Container v = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}}; + + SECTION("iterator traits") { + using value_type = typename iterator_traits::value_type; + + static_assert(is_same_v::difference_type, + typename iterator_traits>::difference_type>); + static_assert(is_same_v::value_type, iterator_t>); + static_assert(is_same_v::pointer, const value_type*>); + static_assert(is_same_v::reference, const value_type&>); + static_assert(is_same_v::iterator_category, std::forward_iterator_tag>); + //static_assert(is_same_v::iterator_concept>); // not contiguous + } + + SECTION("forward iterator concept") { + //static_assert(sentinel_for); + //static_assert(is_same_v() - declval())>); + //static_assert(sized_sentinel_for); + static_assert(forward_iterator); + //static_assert(bidirectional_iterator); + //static_assert(random_access_iterator); + //static_assert(contiguous_iterator); + } + + SECTION("construction") { + Iterator it; + Iterator it0(advance(begin(v), 0)); + Iterator it1(advance(begin(v), 1)); + //REQUIRE(*it == 0); + REQUIRE(*it0 == advance(begin(v), 0)); + REQUIRE(*it1 == advance(begin(v), 1)); + } + SECTION("copy") { + Iterator it(advance(begin(v), 1)); + Iterator it1(it); + Iterator it2; + it2 = it1; + REQUIRE(*it1 == advance(begin(v), 1)); + REQUIRE(*it2 == advance(begin(v), 1)); + } + + SECTION("move") { + Iterator it(advance(begin(v), 1)); + Iterator it1(move(it)); + Iterator it2; + it2 = move(it1); + REQUIRE(*it1 == advance(begin(v), 1)); + REQUIRE(*it2 == advance(begin(v), 1)); + } + + SECTION("increment and add") { + Iterator it(advance(begin(v), 1)); + REQUIRE(*it == advance(begin(v), 1)); + REQUIRE(*(it++) == advance(begin(v), 1)); + REQUIRE(*it == advance(begin(v), 2)); + REQUIRE(*(++it) == advance(begin(v), 3)); + REQUIRE(*it == advance(begin(v), 3)); + //REQUIRE(*(it + 2) == advance(begin(v), 5)); + //REQUIRE(*(2 + it) == advance(begin(v), 5)); + //REQUIRE(*(it += 2) == advance(begin(v), 5)); + //REQUIRE(*it == advance(begin(v), 5)); + } + + //SECTION("decrement and subtract") { + // Iterator it(advance(begin(v), 5)); + // REQUIRE(*it == advance(begin(v), 5)); + // REQUIRE(*(it--) == advance(begin(v), 5)); + // REQUIRE(*it == advance(begin(v), 4)); + // REQUIRE(*(--it) == advance(begin(v), 3)); + // REQUIRE(*it == advance(begin(v), 3)); + // //REQUIRE(*(it - 2) == advance(begin(v), 1)); + // //REQUIRE(*(it -= 2) == advance(begin(v), 1)); + // //REQUIRE(*it == advance(begin(v), 1)); + //} + + SECTION("compare equality") { + Iterator it(advance(begin(v), 1)); + Iterator it1(advance(begin(v), 1)); + Iterator it2(advance(begin(v), 2)); + REQUIRE(it == it1); + REQUIRE(it != it2); + REQUIRE(it1 == it); + REQUIRE(it1 != it2); + REQUIRE(it2 != it); + REQUIRE(it2 != it1); + } + + //SECTION("compare relative") { + // Iterator it(advance(begin(v), 1)); + // Iterator it1(advance(begin(v), 1)); + // Iterator it2(advance(begin(v), 2)); + // REQUIRE(it == it1); + // REQUIRE(it != it2); + // REQUIRE(it < it2); + // REQUIRE(it <= it2); + // REQUIRE(it2 > it); + // REQUIRE(it2 >= it); + //} + + // operator[] is not tested because it will return a reference to a non-existing element for contiguous_iterator +} + +TEMPLATE_TEST_CASE("Identifier iterator for bidirectional container list", + "[descriptor]", + (list), + (const list)) { + using Container = TestType; + using Iterator = _descriptor_iterator>; + using difference_type = typename iterator_traits::difference_type; + Container v = {1, 2, 3, 4, 5}; + + SECTION("iterator traits") { + using value_type = typename iterator_traits::value_type; + + static_assert(is_same_v::difference_type, + typename iterator_traits>::difference_type>); + static_assert(is_same_v::value_type, iterator_t>); + static_assert(is_same_v::pointer, const value_type*>); + static_assert(is_same_v::reference, const value_type&>); + static_assert(is_same_v::iterator_category, std::forward_iterator_tag>); + //static_assert(is_same_v::iterator_concept>); // not contiguous + } + + SECTION("forward iterator concept") { + //static_assert(sentinel_for); + //static_assert(is_same_v() - declval())>); + //static_assert(sized_sentinel_for); + static_assert(forward_iterator); + //static_assert(bidirectional_iterator); + //static_assert(random_access_iterator); + //static_assert(contiguous_iterator); + } + + SECTION("construction") { + Iterator it; + Iterator it0(advance(begin(v), 0)); + Iterator it1(advance(begin(v), 1)); + //REQUIRE(*it == 0); + REQUIRE(*it0 == advance(begin(v), 0)); + REQUIRE(*it1 == advance(begin(v), 1)); + } + SECTION("copy") { + Iterator it(advance(begin(v), 1)); + Iterator it1(it); + Iterator it2; + it2 = it1; + REQUIRE(*it1 == advance(begin(v), 1)); + REQUIRE(*it2 == advance(begin(v), 1)); + } + + SECTION("move") { + Iterator it(advance(begin(v), 1)); + Iterator it1(move(it)); + Iterator it2; + it2 = move(it1); + REQUIRE(*it1 == advance(begin(v), 1)); + REQUIRE(*it2 == advance(begin(v), 1)); + } + + SECTION("increment and add") { + Iterator it(advance(begin(v), 1)); + REQUIRE(*it == advance(begin(v), 1)); + REQUIRE(*(it++) == advance(begin(v), 1)); + REQUIRE(*it == advance(begin(v), 2)); + REQUIRE(*(++it) == advance(begin(v), 3)); + REQUIRE(*it == advance(begin(v), 3)); + //REQUIRE(*(it + 2) == advance(begin(v), 5)); + //REQUIRE(*(2 + it) == advance(begin(v), 5)); + //REQUIRE(*(it += 2) == advance(begin(v), 5)); + //REQUIRE(*it == advance(begin(v), 5)); + } + + //SECTION("decrement and subtract") { + // Iterator it(advance(begin(v), 5)); + // REQUIRE(*it == advance(begin(v), 5)); + // REQUIRE(*(it--) == advance(begin(v), 5)); + // REQUIRE(*it == advance(begin(v), 4)); + // REQUIRE(*(--it) == advance(begin(v), 3)); + // REQUIRE(*it == advance(begin(v), 3)); + // //REQUIRE(*(it - 2) == advance(begin(v), 1)); + // //REQUIRE(*(it -= 2) == advance(begin(v), 1)); + // //REQUIRE(*it == advance(begin(v), 1)); + //} + + SECTION("compare equality") { + Iterator it(advance(begin(v), 1)); + Iterator it1(advance(begin(v), 1)); + Iterator it2(advance(begin(v), 2)); + REQUIRE(it == it1); + REQUIRE(it != it2); + REQUIRE(it1 == it); + REQUIRE(it1 != it2); + REQUIRE(it2 != it); + REQUIRE(it2 != it1); + } + + //SECTION("compare relative") { + // Iterator it(advance(begin(v), 1)); + // Iterator it1(advance(begin(v), 1)); + // Iterator it2(advance(begin(v), 2)); + // REQUIRE(it == it1); + // REQUIRE(it != it2); + // REQUIRE(it < it2); + // REQUIRE(it <= it2); + // REQUIRE(it2 > it); + // REQUIRE(it2 >= it); + //} + + // operator[] is not tested because it will return a reference to a non-existing element for contiguous_iterator +} + +TEMPLATE_TEST_CASE("Identifier iterator for bidirectional container", + "[descriptor]", + (forward_list), + (const forward_list)) { + using Container = TestType; + using Iterator = _descriptor_iterator>; + using difference_type = typename iterator_traits::difference_type; + Container v = {5, 4, 3, 2, 1}; // reverse order b/c forward_list adds to the front + + SECTION("iterator traits") { + using value_type = typename iterator_traits::value_type; + + static_assert(is_same_v::difference_type, + typename iterator_traits>::difference_type>); + static_assert(is_same_v::value_type, iterator_t>); + static_assert(is_same_v::pointer, const value_type*>); + static_assert(is_same_v::reference, const value_type&>); + static_assert(is_same_v::iterator_category, + typename iterator_traits>::iterator_category>); + //static_assert(is_same_v::iterator_concept>); // not contiguous + } + + SECTION("forward iterator concept") { + //static_assert(sentinel_for); + //static_assert(is_same_v() - declval())>); + //static_assert(sized_sentinel_for); + static_assert(forward_iterator); + //static_assert(bidirectional_iterator); + //static_assert(random_access_iterator); + //static_assert(contiguous_iterator); + } + + SECTION("construction") { + Iterator it; + Iterator it0(advance(begin(v), 0)); + Iterator it1(advance(begin(v), 1)); + //REQUIRE(*it == 0); + REQUIRE(*it0 == advance(begin(v), 0)); + REQUIRE(*it1 == advance(begin(v), 1)); + } + SECTION("copy") { + Iterator it(advance(begin(v), 1)); + Iterator it1(it); + Iterator it2; + it2 = it1; + REQUIRE(*it1 == advance(begin(v), 1)); + REQUIRE(*it2 == advance(begin(v), 1)); + } + + SECTION("move") { + Iterator it(advance(begin(v), 1)); + Iterator it1(move(it)); + Iterator it2; + it2 = move(it1); + REQUIRE(*it1 == advance(begin(v), 1)); + REQUIRE(*it2 == advance(begin(v), 1)); + } + + SECTION("increment and add") { + Iterator it(advance(begin(v), 1)); + REQUIRE(*it == advance(begin(v), 1)); + REQUIRE(*(it++) == advance(begin(v), 1)); + REQUIRE(*it == advance(begin(v), 2)); + REQUIRE(*(++it) == advance(begin(v), 3)); + REQUIRE(*it == advance(begin(v), 3)); + //REQUIRE(*(it + 2) == advance(begin(v), 5)); + //REQUIRE(*(2 + it) == advance(begin(v), 5)); + //REQUIRE(*(it += 2) == advance(begin(v), 5)); + //REQUIRE(*it == advance(begin(v), 5)); + } + + //SECTION("decrement and subtract") { + // Iterator it(advance(begin(v), 5)); + // REQUIRE(*it == advance(begin(v), 5)); + // REQUIRE(*(it--) == advance(begin(v), 5)); + // REQUIRE(*it == advance(begin(v), 4)); + // REQUIRE(*(--it) == advance(begin(v), 3)); + // REQUIRE(*it == advance(begin(v), 3)); + // REQUIRE(*(it - 2) == advance(begin(v), 1)); + // REQUIRE(*(it -= 2) == advance(begin(v), 1)); + // REQUIRE(*it == advance(begin(v), 1)); + //} + + SECTION("compare equality") { + Iterator it(advance(begin(v), 1)); + Iterator it1(advance(begin(v), 1)); + Iterator it2(advance(begin(v), 2)); + REQUIRE(it == it1); + REQUIRE(it != it2); + REQUIRE(it1 == it); + REQUIRE(it1 != it2); + REQUIRE(it2 != it); + REQUIRE(it2 != it1); + } + + //SECTION("compare relative") { + // Iterator it(advance(begin(v), 1)); + // Iterator it1(advance(begin(v), 1)); + // Iterator it2(advance(begin(v), 2)); + // REQUIRE(it == it1); + // REQUIRE(it != it2); + // REQUIRE(it < it2); + // REQUIRE(it <= it2); + // REQUIRE(it2 > it); + // REQUIRE(it2 >= it); + //} + + // operator[] is not tested because it will return a reference to a non-existing element for contiguous_iterator +} + + +TEMPLATE_TEST_CASE("continuous descriptor range vector", "[descriptor]", (vector), (const vector)) { + using Container = TestType; + using Iterator = _descriptor_iterator>; + using difference_type = typename iterator_traits::difference_type; + Container v = {1, 2, 3, 4, 5}; + auto descriptors = descriptor_subrange_view(v); + difference_type i = 0; + + SECTION("descriptor std for") { + for (auto it = begin(descriptors); it != end(descriptors); ++it) { + difference_type descriptor = *it; + REQUIRE(descriptor == i); + //REQUIRE(descriptors[descriptor] == descriptor + 1); + REQUIRE(descriptors.id(descriptor) == i); + ++i; + } + } + + SECTION("descriptor range for") { + for (difference_type descriptor : descriptors) { + REQUIRE(descriptor == i); + //REQUIRE(descriptors[descriptor] == descriptor + 1); + ++i; + } + } +} + +TEMPLATE_TEST_CASE("bidirectional descriptor range list", "[descriptor]", (list), (const list)) { + using Container = TestType; + using Iterator = _descriptor_iterator>; + using difference_type = typename iterator_traits::difference_type; + Container v = {1, 2, 3, 4, 5}; + auto descriptors = descriptor_subrange_view(v); + difference_type i = 0; + + SECTION("descriptor std for") { + for (auto it = begin(descriptors); it != end(descriptors); ++it) { + auto descriptor = *it; + //const int& value = descriptors[descriptor]; + //REQUIRE(descriptors[descriptor] == i + 1); + ++i; + } + } + + SECTION("descriptor range for") { + for (auto descriptor : descriptors) { + //REQUIRE(descriptors[descriptor] == i + 1); + ++i; + } + } +} + +// REVIEW +TEMPLATE_TEST_CASE("All simple values", + "[descriptor]", + (vector), + (const vector), + (deque), + (const deque), + (list), + (const list)) { + using Container = TestType; + using IdentifierView = descriptor_subrange_view; + using Iterator = _descriptor_iterator>; + using descriptor_type = typename IdentifierView::descriptor_type; // integral or iterator + using difference_type = typename iterator_traits::difference_type; + Container v = {1, 2, 3, 4, 5}; + auto descriptors = descriptor_subrange_view(v); + difference_type i = 0; + + SECTION("descriptor std for") { + // for(auto it = begin(vertices(g)); it != end(vertices(g)); ++it) + for (auto it = begin(descriptors); it != end(descriptors); ++it) { + descriptor_type descriptor = *it; // descriptor is integral or iterator + //REQUIRE(descriptors[descriptor] == i + 1); + if constexpr (random_access_range || is_tuple_like_v>) { + REQUIRE(descriptors.id(descriptor) == i); // e.g. vertex_id(descriptor) + } + ++i; + } + } + + SECTION("descriptor range for") { + // for(auto descriptor : vertices(g)) // descriptor is integral or iterator + for (descriptor_type descriptor : descriptors) { + //REQUIRE(descriptors[descriptor] == i + 1); + if constexpr (random_access_range || is_tuple_like_v>) { + REQUIRE(descriptors.id(descriptor) == i); // e.g. vertex_id(descriptor) == i + } + ++i; + } + } +} + +TEMPLATE_TEST_CASE("All map-like containers", "[descriptor]", (map), (const map)) { + using Container = TestType; + using IdentifierView = descriptor_subrange_view; + using Iterator = _descriptor_iterator>; + using descriptor_type = typename IdentifierView::descriptor_type; // integral or iterator + using difference_type = typename iterator_traits::difference_type; + Container v = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 5}}; + auto descriptors = descriptor_subrange_view(v); + difference_type i = 0; + + SECTION("descriptor std for") { + for (auto it = begin(descriptors); it != end(descriptors); ++it) { + descriptor_type descriptor = *it; + //REQUIRE(descriptors[descriptor] == i + 1); + if constexpr (random_access_range || is_tuple_like_v>) { + REQUIRE(descriptors.id(descriptor) == i); + } + ++i; + } + } + + SECTION("descriptor range for") { + for (descriptor_type descriptor : descriptors) { + //REQUIRE(descriptors[descriptor] == i + 1); + if constexpr (random_access_range || is_tuple_like_v>) { + REQUIRE(descriptors.id(descriptor) == i); + } + ++i; + } + } +} + +//TEMPLATE_TEST_CASE("All simple values", "[descriptor]", (forward_list), (const forward_list)) { +// using Container = TestType; +// using IdentifierView = descriptor_subrange_view; +// using Iterator = _descriptor_iterator>; +// using descriptor_type = typename IdentifierView::descriptor_type; // integral or iterator +// using difference_type = typename iterator_traits::difference_type; +// Container v = {5, 4, 3, 2, 1}; +// auto descriptors = descriptor_subrange_view(v); +// difference_type i = 0; +// +// SECTION("descriptor std for") { +// for (auto it = begin(descriptors); it != end(descriptors); ++it) { +// descriptor_type descriptor = *it; +// REQUIRE(descriptors[descriptor] == i + 1); +// if constexpr (random_access_range || is_tuple_like_v>) { +// REQUIRE(descriptors.id(descriptor) == i); +// } +// ++i; +// } +// } +// +// SECTION("descriptor range for") { +// for (descriptor_type descriptor : descriptors) { +// REQUIRE(descriptors[descriptor] == i + 1); +// if constexpr (random_access_range || is_tuple_like_v>) { +// REQUIRE(descriptors.id(descriptor) == i); +// } +// ++i; +// } +// } +//} + + +# if 0 +TEST_CASE("example") { + using G = vector; + G g = {1, 2, 3, 4, 5}; + auto V = descriptor_subrange_view(g); + + for (auto&& uid : V) { + auto id = vertex_id(g, uid); + for (auto&& uv : edges(g,uid)) { + } + } +} +auto a = std::vector>; +auto b = std::map>; + +for (auto u = begin(a); u != end(a); ++u) { + // u is an vector>::iterator + // *u is a vector + for (auto v = begin(*u); v != end(*u); ++v) { + // v is a vector::iterator + // *v is an int + } +} + +for (auto&& u : vertices(a)) { + // u is a vector& + for (auto&& v : edges(g,u)) { + // v is an int& + } +} + +// for(auto&& u : descriptor_subrange_view(a)) +for (auto&& u : vertices(a)) { + // u is a vertex descriptor/descriptor = index/iterator = graph_traits::vertex_info + for (auto&& uv : edges(a,u)) { + // uv is an edge descriptor/descriptor = index/iterator = graph_traits::edge_info + auto&& uu = source(g, uv); + //uu is graph_traits::vertex_info + } +} + +template +auto vertices(const G& g) { + return descriptor_subrange_view(g); +} + + +# endif // 0 + +#endif // ENABLE_DESCRIPTOR_TESTS diff --git a/tests/dijkstra_shortest_paths_tests.cpp b/tests/dijkstra_shortest_paths_tests.cpp index 41e4eae..3bfa7d9 100644 --- a/tests/dijkstra_shortest_paths_tests.cpp +++ b/tests/dijkstra_shortest_paths_tests.cpp @@ -91,9 +91,9 @@ auto to_string(const Predecessors& predecessors) { } template -using visited_vertex_t = vertex_descriptor, vertex_reference_t, void>; +using visited_vertex_t = vertex_info, vertex_reference_t, void>; template -using visited_edge_t = edge_descriptor, true, edge_reference_t, void>; +using visited_edge_t = edge_info, true, edge_reference_t, void>; template class empty_dijkstra_visitor { diff --git a/tests/edgelist_tests.cpp b/tests/edgelist_tests.cpp index 30a09f1..72aa059 100644 --- a/tests/edgelist_tests.cpp +++ b/tests/edgelist_tests.cpp @@ -1,7 +1,7 @@ #include #include #include "graph/edgelist.hpp" -#include "graph/graph_descriptors.hpp" +#include "graph/graph_info.hpp" #include #include @@ -11,7 +11,7 @@ using std::tuple; using std::pair; using std::is_same_v; using std::same_as; -using graph::edge_descriptor; +using graph::edge_info; using graph::_el_tuple_edge; using graph::_el_basic_sourced_edge_desc; using graph::source_id; @@ -122,8 +122,8 @@ TEST_CASE("edgelist pair test", "[edgelist][tuple]") { static_assert(basic_sourced_edgelist); } -TEST_CASE("edgelist edge_descriptor test", "[edgelist][edge_descriptor]") { - using EL = vector>; +TEST_CASE("edgelist edge_info test", "[edgelist][edge_info]") { + using EL = vector>; using E = std::ranges::range_value_t; EL el{{1, 2}, {1, 4}, {2, 3}, {2, 4}}; @@ -135,7 +135,7 @@ TEST_CASE("edgelist edge_descriptor test", "[edgelist][edge_descriptor]") { graph::_Target_id::_Cpo cpo; E e; - static_assert(same_as>); + static_assert(same_as>); static_assert(!std::ranges::forward_range); //static_assert(_el_value); @@ -155,8 +155,8 @@ TEST_CASE("edgelist edge_descriptor test", "[edgelist][edge_descriptor]") { static_assert(basic_sourced_edgelist); } -TEST_CASE("edgelist edge_descriptor test with value", "[edgelist][edge_descriptor]") { - using EL = vector>; +TEST_CASE("edgelist edge_info test with value", "[edgelist][edge_info]") { + using EL = vector>; using E = std::ranges::range_value_t; EL el{{1, 2, 11.1}, {1, 4, 22.2}, {2, 3, 3.33}, {2, 4, 4.44}}; @@ -168,7 +168,7 @@ TEST_CASE("edgelist edge_descriptor test with value", "[edgelist][edge_descripto graph::_Target_id::_Cpo cpo; E e; - static_assert(same_as>); + static_assert(same_as>); static_assert(!std::ranges::forward_range); //static_assert(_el_value); diff --git a/tests/incidence_tests.cpp b/tests/incidence_tests.cpp index a22617f..687e4a7 100644 --- a/tests/incidence_tests.cpp +++ b/tests/incidence_tests.cpp @@ -205,7 +205,7 @@ TEST_CASE("incidence test", "[csr][incidence]") { static_assert(forward_range, "incidence(g) is not a forward_range"); size_t cnt = 0; for (auto&& [vid, uv] : - graph::views::incidence(g, uid)) { // edge_descriptor, false, edge_t, void> + graph::views::incidence(g, uid)) { // edge_info, false, edge_t, void> ++cnt; } REQUIRE(cnt == size(edges(g, u))); diff --git a/tests/mst_tests.cpp b/tests/mst_tests.cpp index 00323e5..4b52a22 100644 --- a/tests/mst_tests.cpp +++ b/tests/mst_tests.cpp @@ -44,7 +44,7 @@ TEST_CASE("Kruskal Min ST Algorithm", "[min st]") { size_t N(size(vertices(g))); auto evf = [&g](edge_reference_t uv) { return edge_value(g, uv); }; - std::vector, true, void, double>> e, t; + std::vector, true, void, double>> e, t; for (auto&& [uid, vid, uv] : graph::views::edgelist(g)) { e.push_back(std::ranges::range_value_t()); e.back().source_id = uid; @@ -66,7 +66,7 @@ TEST_CASE("Kruskal Min ST Algorithm", "[min st]") { } // Kruskal inplace, modifiy input edgelist - std::vector, true, void, double>> t2; + std::vector, true, void, double>> t2; graph::inplace_kruskal(e, t2); last = -1; for (auto&& [u, v, val] : t2) { @@ -76,7 +76,7 @@ TEST_CASE("Kruskal Min ST Algorithm", "[min st]") { } // Kruskal inplace from adjacency list - std::vector, true, void, double>> t3; + std::vector, true, void, double>> t3; graph::kruskal(graph::views::edgelist(g, evf), t3); last = -1; for (auto&& [u, v, val] : t3) { @@ -94,7 +94,7 @@ TEST_CASE("Kruskal Max ST Algorithm", "[max st]") { size_t N(size(vertices(g))); auto evf = [&g](edge_reference_t uv) { return edge_value(g, uv); }; - std::vector, true, void, double>> e, t; + std::vector, true, void, double>> e, t; for (auto&& [uid, vid, uv] : graph::views::edgelist(g)) { e.push_back(std::ranges::range_value_t()); e.back().source_id = uid; @@ -116,7 +116,7 @@ TEST_CASE("Kruskal Max ST Algorithm", "[max st]") { } // Kruskal inplace, modifiy input edgelist - std::vector, true, void, double>> t2; + std::vector, true, void, double>> t2; graph::inplace_kruskal(e, t2, [](auto&& i, auto&& j) { return i > j; }); last = std::numeric_limits::max(); for (auto&& [u, v, val] : t2) { @@ -126,7 +126,7 @@ TEST_CASE("Kruskal Max ST Algorithm", "[max st]") { } // Kruskal inplace from adjacency list - std::vector, true, void, double>> t3; + std::vector, true, void, double>> t3; graph::kruskal(graph::views::edgelist(g, evf), t3, [](auto&& i, auto&& j) { return i > j; }); last = std::numeric_limits::max(); for (auto&& [u, v, val] : t3) { diff --git a/tests/tests.cpp b/tests/tests.cpp index 43077c8..608351e 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -2,6 +2,7 @@ #include #include #include +#include using std::conditional_t; using std::ranges::contiguous_range; @@ -34,6 +35,10 @@ template struct identifier_value> { using type = U; }; +template +struct identifier_value> { + using type = U; +}; template using identifier_value_t = typename identifier_value::type;