88#include < unordered_set>
99
1010// all_of, any_of, none_of terminal algorithm
11- #define DTL_DEFINE_PIPEABLE_RANGE_ALGO (ALGO_NAME ) \
11+ #define DTL_DEFINE_PIPEABLE_RANGE_ALGO (algo_name ) \
1212 namespace ranges_algo_detail { \
1313 template <typename Pred> \
14- struct ALGO_NAME ##_fn { \
14+ struct algo_name ##_fn { \
15+ private: \
1516 Pred pred; \
1617 \
18+ public: \
1719 template <typename P> \
18- constexpr explicit ALGO_NAME ##_fn(P &&p) : pred(std::forward<P>(p)) {} \
20+ constexpr explicit algo_name ##_fn(P &&p) : pred(std::forward<P>(p)) {} \
1921 \
2022 /* input_range causes no dangling risk since this adaptor is terminal */ \
2123 template <std::ranges::input_range R> \
2224 constexpr bool \
2325 operator ()(R &&r) const { \
24- return std::ranges::ALGO_NAME (r, pred); \
26+ return std::ranges::algo_name (r, pred); \
2527 } \
2628 \
2729 template <typename R> \
28- friend auto operator |(R &&r, const ALGO_NAME ##_fn &self) \
30+ friend auto operator |(R &&r, algo_name ##_fn const &self) \
2931 -> decltype (self(std::forward<R>(r))) { \
3032 return self (std::forward<R>(r)); \
3133 } \
3234 }; \
3335 } \
3436 \
3537 template <typename Pred> \
36- constexpr auto ALGO_NAME (Pred &&pred) { \
37- return ranges_algo_detail::ALGO_NAME ##_fn<std::decay_t <Pred>>( \
38+ constexpr auto algo_name (Pred &&pred) { \
39+ return ranges_algo_detail::algo_name ##_fn<std::remove_cvref_t <Pred>>( \
3840 std::forward<Pred>(pred)); \
3941 }
4042
@@ -48,19 +50,15 @@ namespace dice::template_library {
4850namespace dice ::template_library {
4951 namespace ranges_algo_detail {
5052 struct empty_fn {
53+
5154 template <std::ranges::input_range R>
5255 constexpr bool operator ()(R &&range) const {
53- // Use std::ranges::empty if the expression is valid for the range type.
54- if constexpr (requires { std::ranges::empty (range); }) {
55- return std::ranges::empty (range);
56- } else {
57- // std::ranges::begin/end work for const and non-const ranges.
58- return std::ranges::begin (range) == std::ranges::end (range);
59- }
56+ static_assert (requires { std::ranges::empty (range); }, " std::ranges::empty requires an input range as it might otherwise be expensive to materialize the first element." );
57+ return std::ranges::empty (range);
6058 }
6159
6260 template <std::ranges::input_range R>
63- friend constexpr auto operator |(R &&range, const empty_fn &self)
61+ friend constexpr auto operator |(R &&range, empty_fn const &self)
6462 -> decltype (self(std::forward<R>(range))) {
6563 return self (std::forward<R>(range));
6664 }
@@ -69,12 +67,11 @@ namespace dice::template_library {
6967 struct non_empty_fn {
7068 template <std::ranges::input_range R>
7169 constexpr bool operator ()(R &&range) const {
72- // Implemented as the negation of empty_fn for code reuse.
7370 return !empty_fn{}(std::forward<R>(range));
7471 }
7572
7673 template <std::ranges::input_range R>
77- friend constexpr auto operator |(R &&range, const non_empty_fn &self)
74+ friend constexpr auto operator |(R &&range, non_empty_fn const &self)
7875 -> decltype (self(std::forward<R>(range))) {
7976 return self (std::forward<R>(range));
8077 }
@@ -107,22 +104,24 @@ namespace dice::template_library {
107104 namespace ranges_algo_detail {
108105 template <typename T, typename Pred>
109106 struct remove_element_fn {
107+ private:
110108 T value_;
111109 Pred pred_;
112110
111+ public:
113112 template <typename V, typename P>
114113 constexpr remove_element_fn (V &&value, P &&pred)
115114 : value_(std::forward<V>(value)), pred_(std::forward<P>(pred)) {}
116115
117116 template <std::ranges::viewable_range R>// viewable_range ensures there are no views into dangling stuff
118117 constexpr auto operator ()(R &&range) const {
119- return std::forward<R>(range) | std::views::filter ([value = value_, pred = pred_](const auto &element) {
118+ return std::forward<R>(range) | std::views::filter ([value = value_, pred = pred_](auto const &element) {
120119 return !std::invoke (pred, element, value);
121120 });
122121 }
123122
124123 template <std::ranges::viewable_range R>// viewable_range ensures there are no views into dangling stuff
125- friend constexpr auto operator |(R &&range, const remove_element_fn &self)
124+ friend constexpr auto operator |(R &&range, remove_element_fn const &self)
126125 -> decltype (self(std::forward<R>(range))) {
127126 return self (std::forward<R>(range));
128127 }
@@ -138,7 +137,7 @@ namespace dice::template_library {
138137 */
139138 template <typename T, typename Pred = std::ranges::equal_to>
140139 constexpr auto remove_element (T &&value, Pred &&pred = Pred{}) {
141- return ranges_algo_detail::remove_element_fn<std::decay_t <T>, std::decay_t <Pred>>(
140+ return ranges_algo_detail::remove_element_fn<std::remove_cvref_t <T>, std::remove_cvref_t <Pred>>(
142141 std::forward<T>(value), std::forward<Pred>(pred));
143142 }
144143}// namespace dice::template_library
@@ -157,23 +156,23 @@ namespace dice::template_library {
157156 template <std::ranges::input_range R>
158157 requires std::copyable<std::ranges::range_value_t <R>>
159158 constexpr bool operator ()(R &&range) const {
160- if (dice::template_library::empty (range)) {
159+ auto it = std::ranges::begin (range);
160+ if (it == std::ranges::end (range)) {
161161 return true ;
162162 }
163-
164- auto it = std::ranges::begin (range);
165- const auto first_element = *(it++);
163+ const auto first_element = *it;
164+ ++it;
166165
167166 // Check if all subsequent elements in the range match the first one.
168167 return std::ranges::subrange (it, std::ranges::end (range)) |
169- dice::template_library::all_of ([this , first_element](const auto ¤t_element) {
168+ dice::template_library::all_of ([this , first_element](auto const ¤t_element) {
170169 return std::invoke (pred_, current_element, first_element);
171170 });
172171 }
173172
174173 template <std::ranges::input_range R>
175174 requires std::copyable<std::ranges::range_value_t <R>>
176- friend constexpr auto operator |(R &&range, const all_equal_fn &self)
175+ friend constexpr auto operator |(R &&range, all_equal_fn const &self)
177176 -> decltype (self(std::forward<R>(range))) {
178177 return self (std::forward<R>(range));
179178 }
@@ -190,7 +189,7 @@ namespace dice::template_library {
190189 */
191190 template <typename Pred = std::ranges::equal_to>
192191 constexpr auto all_equal (Pred &&pred = Pred{}) {
193- return ranges_algo_detail::all_equal_fn<std::decay_t <Pred>>(
192+ return ranges_algo_detail::all_equal_fn<std::remove_cvref_t <Pred>>(
194193 std::forward<Pred>(pred));
195194 }
196195}// namespace dice::template_library
@@ -205,12 +204,15 @@ namespace dice::template_library {
205204 private:
206205 struct iterator ;
207206
208- using ValueType = std::decay_t <std::ranges::range_value_t <V>>;
207+ using ValueType = std::remove_cvref_t <std::ranges::range_value_t <V>>;
209208 static_assert (std::copy_constructible<ValueType>, " The value type for unique must be copy-constructible." );
209+ static_assert ((requires (const ValueType &v) { { std::hash<ValueType>{}(v) } -> std::convertible_to<std::size_t >; } && std::equality_comparable<V>) ||
210+ std::strict_weak_order<std::less<V>, V, V>,
211+ " The value type must be either hashable and equality comparable, or support less than.." );
210212
211213 using SetType = std::conditional_t <
212214 // Check if std::hash is a valid expression for the value type.
213- requires (const ValueType &v) { { std::hash<ValueType>{}(v) } -> std::convertible_to<std::size_t >; },
215+ requires (ValueType const &v) { { std::hash<ValueType>{}(v) } -> std::convertible_to<std::size_t >; },
214216 std::unordered_set<ValueType>,
215217 std::set<ValueType>>;
216218
@@ -284,7 +286,7 @@ namespace dice::template_library {
284286 }
285287
286288 template <std::ranges::viewable_range R>
287- friend constexpr auto operator |(R &&r, const unique_fn &self)
289+ friend constexpr auto operator |(R &&r, unique_fn const &self)
288290 -> decltype (self(std::forward<R>(r))) {
289291 return self (std::forward<R>(r));
290292 }
@@ -310,9 +312,9 @@ namespace dice::template_library {
310312
311313 // The view that represents the generated sequence.
312314 template <std::integral T>
313- struct range_generator_view : public std ::ranges::view_interface<range_generator_view<T>> {
315+ struct range_generator_view : std::ranges::view_interface<range_generator_view<T>> {
314316 private:
315- class iterator ;// Forward-declare
317+ struct iterator ;// Forward-declare
316318
317319 T start_{};
318320 T stop_{};
@@ -331,9 +333,9 @@ namespace dice::template_library {
331333
332334 // The iterator that generates the numbers on the fly.
333335 template <std::integral T>
334- class range_generator_view <T>::iterator {
336+ struct range_generator_view <T>::iterator {
335337 private:
336- const range_generator_view *parent_ = nullptr ;
338+ range_generator_view const *parent_ = nullptr ;
337339 T value_{};
338340
339341 public:
@@ -343,7 +345,7 @@ namespace dice::template_library {
343345 using difference_type = std::ptrdiff_t ;
344346
345347 iterator () = default ;
346- constexpr explicit iterator (const range_generator_view *parent, T value)
348+ constexpr explicit iterator (range_generator_view const *parent, T value)
347349 : parent_(parent),
348350 value_(value) {}
349351
@@ -375,9 +377,9 @@ namespace dice::template_library {
375377 * - `range<T>(start, stop, step)`: Generates numbers from start, incrementing by step, until stop is met or passed.
376378 */
377379 template <std::integral T, typename S = T>
378- constexpr auto range (T arg1 , T arg2 , S step) {
380+ constexpr auto range (T start , T stop , S step) {
379381 static_assert (std::is_integral_v<S>, " Step must be an integral type." );
380- return ranges_algo_detail::range_generator_view<T>(arg1, arg2 , static_cast <std::make_signed_t <T>>(step));
382+ return ranges_algo_detail::range_generator_view<T>(start, stop , static_cast <std::make_signed_t <T>>(step));
381383 }
382384
383385 template <std::integral T>
@@ -397,25 +399,24 @@ namespace dice::template_library {
397399 namespace ranges_algo_detail {
398400 template <typename Pred>
399401 struct all_distinct_fn {
402+ private:
400403 Pred pred_;
401404
405+ public:
402406 template <typename P>
403407 constexpr explicit all_distinct_fn (P &&pred)
404408 : pred_(std::forward<P>(pred)) {}
405409
406410 template <std::ranges::input_range R>
407411 constexpr bool operator ()(R &&range) const {
408- using ValueType = std::decay_t <std::ranges::range_value_t <R>>;
412+ using ValueType = std::remove_cvref_t <std::ranges::range_value_t <R>>;
409413
410- if (dice::template_library::empty (range)) {
411- return true ;
412- }
413414
414415 // backend_selection
415416 constexpr bool is_default_pred = std::is_same_v<Pred, std::ranges::equal_to>;
416417
417418 constexpr bool hash_set_usable = std::copy_constructible<ValueType> &&
418- requires (const ValueType &v) {
419+ requires (ValueType const &v) {
419420 { std::hash<ValueType>{}(v) } -> std::convertible_to<std::size_t >;
420421 };
421422
@@ -424,21 +425,26 @@ namespace dice::template_library {
424425 is_default_pred;// non-default predicates cannot be used with the ordered set
425426 static_assert (hash_set_usable || ordered_set_usable, " The elements of the consumed range are neither compatible with std::unordered_set nor with std::set." );
426427
428+ auto it = std::ranges::begin (range);
429+ if (it == std::ranges::end (range)) {
430+ return true ;
431+ }
432+
427433 auto seen = [&] {
428434 if constexpr (hash_set_usable) {
429435 return std::unordered_set<ValueType, std::hash<ValueType>, Pred>{1 , {}, pred_};
430436 } else {
431437 return std::set<ValueType>{};
432438 }
433439 }();
434- for (const auto &element : range) {
440+ for (const auto &element : std::ranges::subrange{it, std::ranges::end ( range)} ) {
435441 if (!seen.insert (element).second ) { return false ; }
436442 }
437443 return true ;
438444 }
439445
440446 template <std::ranges::input_range R>
441- friend constexpr auto operator |(R &&range, const all_distinct_fn &self)
447+ friend constexpr auto operator |(R &&range, all_distinct_fn const &self)
442448 -> decltype (self(std::forward<R>(range))) {
443449 return self (std::forward<R>(range));
444450 }
@@ -458,7 +464,7 @@ namespace dice::template_library {
458464 */
459465 template <typename Pred = std::ranges::equal_to>
460466 constexpr auto all_distinct (Pred &&pred = Pred{}) {
461- return ranges_algo_detail::all_distinct_fn<std::decay_t <Pred>>(
467+ return ranges_algo_detail::all_distinct_fn<std::remove_cvref_t <Pred>>(
462468 std::forward<Pred>(pred));
463469 }
464470
0 commit comments