22// This file is part of the CPP-GL project (https://github.com/SpectraL519/cpp-gl).
33// Licensed under the MIT License. See the LICENSE file in the project root for full license information.
44
5+ // / @file gl/util/ranges.hpp
6+ // / @brief Defines utility functions and views for working with C++20 ranges.
7+
58#pragma once
69
710#include < algorithm>
811#include < ranges>
912
1013namespace gl ::util {
1114
15+ // / @ingroup GL GL-Util
16+ // / @brief Returns the size of a range.
17+ // /
18+ // / This function returns the size of a range if it is a sized range, otherwise it computes the
19+ // / distance between the beginning and end of the range. Note that computing the distance for
20+ // / non-sized ranges may be expensive.
21+ // /
22+ // / > [!WARNING] This function will consume input ranges that are not sized, as it needs to iterate through them to count the elements.
23+ // /
24+ // / @tparam R The type of the range.
25+ // / @param r The range to measure.
26+ // / @return The size of the range if it is a sized range, otherwise the distance between the beginning and end of the range.
27+ // /
28+ // / > [!INFO] Time complexity
29+ // / >
30+ // / > $O(1)$ if the range is a sized range, otherwise $O(N)$ where $N$ is the number of elements in the range.
1231template <std::ranges::range R>
1332constexpr auto range_size (R&& r) {
1433 if constexpr (std::ranges::sized_range<R>)
@@ -18,6 +37,15 @@ constexpr auto range_size(R&& r) {
1837 return std::ranges::distance (std::begin (r), std::end (r));
1938}
2039
40+ // / @ingroup GL GL-Util
41+ // / @brief Checks if all elements in a range are equal.
42+ // / @tparam R The type of the range.
43+ // / @param range The range to check.
44+ // / @return `true` if all elements in the range are equal or the range is empty, otherwise `false`.
45+ // /
46+ // / > [!INFO] Time complexity
47+ // / >
48+ // / > $O(N)$ where $N$ is the number of elements in the range.
2149template <std::ranges::forward_range R>
2250[[nodiscard]] constexpr bool is_constant (R&& range) noexcept {
2351 if (std::ranges::empty (range))
@@ -28,31 +56,55 @@ template <std::ranges::forward_range R>
2856 });
2957}
3058
59+ // / @ingroup GL GL-Util
60+ // / @brief Checks if all elements in a range are equal to a given value.
61+ // / @tparam R The type of the range.
62+ // / @param range The range to check.
63+ // / @param value The value to compare against.
64+ // / @return `true` if all elements in the range are equal to the given value or the range is empty, otherwise `false`.
65+ // /
66+ // / > [!INFO] Time complexity
67+ // / >
68+ // / > $O(N)$ where $N$ is the number of elements in the range.
3169template <std::ranges::forward_range R>
32- [[nodiscard]] constexpr bool all_equal (R&& range, const std::ranges::range_value_t <R>& k) noexcept {
70+ [[nodiscard]] constexpr bool all_equal (
71+ R&& range, const std::ranges::range_value_t <R>& value
72+ ) noexcept {
3373 if (std::ranges::empty (range))
3474 return true ;
3575
36- return std::ranges::all_of (range, [&k ](const auto & val) { return val == k ; });
76+ return std::ranges::all_of (range, [&value ](const auto & val) { return val == value ; });
3777}
3878
79+ // / @ingroup GL GL-Util
3980// / @brief A view concatenating two ranges sequentially (C++20 polyfill for C++26 `std::views::concat`).
4081// /
41- // / @warning **GCC 13/14 Bug:** Using branching views (like this or `std::ranges::filter_view`)
42- // / inside complex algorithms (e.g., `std::ranges::is_permutation`) may trigger false-positive
43- // / `-Wmaybe-uninitialized` warnings. To work around this, suppress the warning at the call site
44- // / or materialize the view into a contiguous container like `std::vector`.
82+ // / > [!WARNING] GCC 13/14 Bug
83+ // / >
84+ // / > Using branching views (like this or `std::ranges::filter_view`) inside complex algorithms
85+ // / > (e.g., `std::ranges::is_permutation`) may trigger false-positive `-Wmaybe-uninitialized`
86+ // / > warnings. To work around this, suppress the warning at the call site or materialize the
87+ // / > view into a contiguous container like `std::vector`.
4588// /
4689// / @tparam V1 First view type.
4790// / @tparam V2 Second view type.
4891// / @todo Replace with `std::views::concat` (C++26).
92+ // / ### See also
93+ // / - @ref gl::util::concat_fn "concat_fn": A helper compile-time constant function object for creating `concat_view` instances.
94+ // / - @ref gl::util::concat "concat": A compile-time constant instantiation of this function object for convenient use.
4995template <std::ranges::view V1, std::ranges::view V2>
5096class concat_view : public std ::ranges::view_interface<concat_view<V1, V2>> {
5197public:
98+ // / @brief Default constructor creates an empty concatenated view.
5299 concat_view () = default ;
53100
101+ // / @brief Constructs a `concat_view` from two viewable ranges.
102+ // / @param v1 The first range to concatenate.
103+ // / @param v2 The second range to concatenate.
54104 constexpr concat_view (V1 v1, V2 v2) : _v1(std::move(v1)), _v2(std::move(v2)) {}
55105
106+ // / @brief Returns an iterator to the beginning of the concatenated view.
107+ // / @return An iterator that traverses the first range followed by the second range.
56108 constexpr auto begin () {
57109 return iterator<false >(
58110 std::ranges::begin (this ->_v1 ),
@@ -61,8 +113,10 @@ class concat_view : public std::ranges::view_interface<concat_view<V1, V2>> {
61113 );
62114 }
63115
116+ // / @brief Returns a const iterator to the beginning of the concatenated view.
117+ // / @return A const iterator that traverses the first range followed by the second range.
64118 constexpr auto begin () const
65- requires std::ranges::range<const V1> and std::ranges::range<const V2>
119+ requires( std::ranges::range<const V1> and std::ranges::range<const V2>)
66120 {
67121 return iterator<true >(
68122 std::ranges::begin (this ->_v1 ),
@@ -71,12 +125,16 @@ class concat_view : public std::ranges::view_interface<concat_view<V1, V2>> {
71125 );
72126 }
73127
128+ // / @brief Returns a sentinel representing the end of the concatenated view.
129+ // / @return A sentinel that compares equal to an iterator when it reaches the end of the second range.
74130 constexpr auto end () {
75131 return sentinel<false >(std::ranges::end (this ->_v2 ));
76132 }
77133
134+ // / @brief Returns a const sentinel representing the end of the concatenated view.
135+ // / @return A const sentinel that compares equal to a const iterator when it reaches the end
78136 constexpr auto end () const
79- requires std::ranges::range<const V1> and std::ranges::range<const V2>
137+ requires( std::ranges::range<const V1> and std::ranges::range<const V2>)
80138 {
81139 return sentinel<true >(std::ranges::end (this ->_v2 ));
82140 }
@@ -172,9 +230,18 @@ class concat_view : public std::ranges::view_interface<concat_view<V1, V2>> {
172230 };
173231};
174232
175- namespace detail {
176-
233+ // / @ingroup GL GL-Util
234+ // / @brief A function object for concatenating two viewable ranges into a `concat_view`.
235+ // / ### See also
236+ // / - @ref gl::util::concat_view "concat_view": The view type that represents the concatenation of two ranges.
237+ // / - @ref gl::util::concat "concat": A compile-time constant instantiation of this function object for convenient use.
177238struct concat_fn {
239+ // / @brief Concatenates two viewable ranges into a `concat_view`.
240+ // / @tparam R1 The type of the first range.
241+ // / @tparam R2 The type of the second range.
242+ // / @param r1 The first range to concatenate.
243+ // / @param r2 The second range to concatenate.
244+ // / @return A `concat_view` that represents the concatenation of the two ranges.
178245 template <std::ranges::viewable_range R1, std::ranges::viewable_range R2>
179246 constexpr auto operator ()(R1&& r1, R2&& r2) const {
180247 return concat_view<std::views::all_t <R1>, std::views::all_t <R2>>(
@@ -183,12 +250,24 @@ struct concat_fn {
183250 }
184251};
185252
186- } // namespace detail
187-
253+ // / @ingroup GL GL-Util
188254// / @brief Concatenates two viewable ranges into a `concat_view`.
255+ // /
256+ // / ### Example usage
257+ // / ```cpp
258+ // / std::vector<int> v1 = {1, 2, 3};
259+ // / std::vector<int> v2 = {4, 5, 6};
260+ // / auto concatenated = gl::util::concat(v1, v2);
261+ // / for (int x : concatenated)
262+ // / std::cout << x << " "; // Output: 1 2 3 4 5 6
263+ // / ```
264+ // /
189265// / @param r1 First range to concatenate.
190266// / @param r2 Second range to concatenate.
191267// / @todo Replace with `std::views::concat` (C++26).
192- inline constexpr detail::concat_fn concat{};
268+ // / ### See also
269+ // / - @ref gl::util::concat_view "concat_view": The view type that represents the concatenation of two ranges.
270+ // / - @ref gl::util::concat_fn "concat_fn": A helper compile-time constant function object for creating `concat_view` instances.
271+ inline constexpr concat_fn concat{};
193272
194273} // namespace gl::util
0 commit comments