Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-ranges.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
110#ifndef AH_RANGES_H
111#define AH_RANGES_H
112
113// Check for C++20 ranges support
114// We need both the header AND the actual implementation.
115// libc++ in Clang 14 has <ranges> header but incomplete implementation.
116//
117// Detection strategy:
118// - GCC 11+: __cpp_lib_ranges >= 202106L (basic ranges support)
119// - GCC 12+: __cpp_lib_ranges >= 202110L (complete ranges support)
120// - Clang with libc++: Often has <ranges> but incomplete std::views
121//
122// We accept __cpp_lib_ranges >= 202106L for GCC, but exclude Clang + libc++
123// which has the header but incomplete views implementation.
124// Manual override (portability escape hatch):
125// - Define ALEPH_NO_RANGES (e.g. -DALEPH_NO_RANGES) to force ranges support
126// OFF regardless of what the compiler reports.
127// - Or pre-define ALEPH_HAS_RANGES to 0/1 to skip auto-detection entirely.
128// This lets users on toolchains whose std::ranges is present but unreliable
129// opt out without editing the library.
130#if defined(ALEPH_NO_RANGES)
131#undef ALEPH_HAS_RANGES
132#define ALEPH_HAS_RANGES 0
133#endif
134
135// <version> defines the standard library feature-test macros (e.g.
136// __cpp_lib_ranges) without pulling in a heavy header. It must be included
137// before the detection below, otherwise __cpp_lib_ranges is undefined and the
138// check wrongly resolves to "no ranges".
139#if __has_include(<version>)
140#include <version>
141#endif
142
143#ifndef ALEPH_HAS_RANGES
144#if __cplusplus >= 202002L && __has_include(<ranges>) && \
145 defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 202106L
146// Exclude Clang with libc++ < 16 (incomplete std::views implementation)
147#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000
148#define ALEPH_HAS_RANGES 0
149#else
150#define ALEPH_HAS_RANGES 1
151#endif
152#else
153#define ALEPH_HAS_RANGES 0
154#endif
155#endif
156
157// Support headers required by the C++20 baseline (always available).
158#include <algorithm>
159#include <iterator>
160#include <concepts>
161
162// The <ranges> header is pulled in only when the feature is actually enabled.
163#if ALEPH_HAS_RANGES
164#include <ranges>
165#endif
166
167// Feature detection for C++23 views
168#ifdef __cpp_lib_ranges_stride
169#define ALEPH_HAS_STRIDE 1
170#else
171#define ALEPH_HAS_STRIDE 0
172#endif
173
174#ifdef __cpp_lib_ranges_repeat
175#define ALEPH_HAS_REPEAT 1
176#else
177#define ALEPH_HAS_REPEAT 0
178#endif
179
180#ifdef __cpp_lib_ranges_zip
181#define ALEPH_HAS_ZIP 1
182#else
183#define ALEPH_HAS_ZIP 0
184#endif
185
186#ifdef __cpp_lib_ranges_enumerate
187#define ALEPH_HAS_ENUMERATE 1
188#else
189#define ALEPH_HAS_ENUMERATE 0
190#endif
191
192// `std::views::join` is C++20 but the adaptor object (as opposed to
193// the `std::ranges::join_view` class) was incomplete in libc++ until
194// version 17. AppleClang 15 (shipped with Xcode 15 on macos-14) reports
195// `_LIBCPP_VERSION = 16xxxx` and triggers a compile error on the join
196// pipeline. Conservatively disable the wrapper when libc++ is older
197// than 17; libstdc++ exposes the adaptor since GCC 11.
198#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 170000
199#define ALEPH_HAS_JOIN 0
200#else
201#define ALEPH_HAS_JOIN 1
202#endif
203
204#include <type_traits>
205#include <utility>
206#include <tuple>
207#include <functional>
208
209namespace Aleph {
210
226template <typename Range, typename Cmp>
227inline void sort_range(Range &r, Cmp cmp)
228#if ALEPH_HAS_RANGES
229{
230 std::ranges::sort(r, std::move(cmp));
231}
232#else
233{
234 std::sort(std::begin(r), std::end(r), std::move(cmp));
235} // NOLINT(modernize-use-ranges)
236#endif
237
242template <typename Range>
243inline void sort_range(Range &r)
244#if ALEPH_HAS_RANGES
245{
246 std::ranges::sort(r, std::ranges::less{});
247}
248#else
249{
250 std::sort(std::begin(r), std::end(r));
251} // NOLINT(modernize-use-ranges)
252#endif
253
254// Forward declarations for major Aleph containers with simple template signatures.
255// Containers with complex template signatures (like DynSetTree, DynBinHeap)
256// should use the generic to<Container>() adaptor instead.
257template <typename T>
258class DynList;
259template <typename T>
260class DynArray;
261template <typename T>
262class DynDlist;
263template <typename T>
264class DynListStack;
265template <typename T>
266class DynListQueue;
267template <typename T>
268class ArrayStack;
269template <typename T>
270class ArrayQueue;
271template <typename T>
272class Random_Set;
273
274#if ALEPH_HAS_RANGES
275
276// ============================================================================
277// Concepts for Aleph containers
278// ============================================================================
279
288template <typename C>
289concept AlephContainer = requires(C c) {
290 typename C::Iterator;
291 typename C::Item_Type;
292 { c.begin() } -> std::input_or_output_iterator;
293 { c.end() } -> std::sentinel_for<decltype(c.begin())>;
294};
295
299template <typename C>
300concept AlephAppendable =
301 AlephContainer<C> && requires(C c, typename C::Item_Type v) { c.append(v); };
302
306template <typename R>
307concept RangeLike = std::ranges::range<R>;
308
309// ============================================================================
310// Range Adaptors - Convert ranges to Aleph containers
311// ============================================================================
312
330template <AlephAppendable Container, RangeLike R>
332{
333 Container result;
334 for (auto &&elem : r)
335 result.append(std::forward<decltype(elem)>(elem));
336 return result;
337}
338
339// ============================================================================
340// Lazy Range Generation (zero-allocation until materialized)
341// ============================================================================
342
367template <typename T = int>
368[[nodiscard]] constexpr auto lazy_range(T start, T end)
369{
370 return std::views::iota(start, end);
371}
372
379template <typename T = int>
380[[nodiscard]] constexpr auto lazy_range(T n)
381{
382 return std::views::iota(T{0}, n);
383}
384
400template <typename T = int>
401[[nodiscard]] constexpr auto lazy_iota(T start = T{0})
402{
403 return std::views::iota(start);
404}
405
406#if ALEPH_HAS_REPEAT
414template <typename T>
415[[nodiscard]] constexpr auto lazy_repeat(const T &value, size_t n)
416{
417 return std::views::repeat(value) | std::views::take(n);
418}
419#endif
420
421// ============================================================================
422// Internal Utilities using Ranges (for performance optimization)
423// ============================================================================
424
425namespace detail {
426
432template <RangeLike R, typename Pred>
433[[nodiscard]] constexpr bool ranges_all_of(R &&r, Pred &&pred)
434{
435 return std::ranges::all_of(std::forward<R>(r), std::forward<Pred>(pred));
436}
437
443template <RangeLike R, typename Pred>
444[[nodiscard]] constexpr bool ranges_any_of(R &&r, Pred &&pred)
445{
446 return std::ranges::any_of(std::forward<R>(r), std::forward<Pred>(pred));
447}
448
454template <RangeLike R, typename Pred>
455[[nodiscard]] constexpr bool ranges_none_of(R &&r, Pred &&pred)
456{
457 return std::ranges::none_of(std::forward<R>(r), std::forward<Pred>(pred));
458}
459
465template <RangeLike R, typename Pred>
466[[nodiscard]] constexpr auto ranges_find_if(R &&r, Pred &&pred)
467{
468 return std::ranges::find_if(std::forward<R>(r), std::forward<Pred>(pred));
469}
470
474template <RangeLike R, typename Pred>
475[[nodiscard]] constexpr auto ranges_count_if(R &&r, Pred &&pred)
476{
477 return std::ranges::count_if(std::forward<R>(r), std::forward<Pred>(pred));
478}
479
485template <RangeLike R, typename Func>
486[[nodiscard]] constexpr auto ranges_transform(R &&r, Func &&func)
487{
488 return std::forward<R>(r) | std::views::transform(std::forward<Func>(func));
489}
490
496template <RangeLike R, typename Pred>
497[[nodiscard]] constexpr auto ranges_filter(R &&r, Pred &&pred)
498{
499 return std::forward<R>(r) | std::views::filter(std::forward<Pred>(pred));
500}
501
505template <RangeLike R>
506[[nodiscard]] constexpr auto ranges_take(R &&r, size_t n)
507{
508 return std::forward<R>(r) | std::views::take(n);
509}
510
514template <RangeLike R>
515[[nodiscard]] constexpr auto ranges_drop(R &&r, size_t n)
516{
517 return std::forward<R>(r) | std::views::drop(n);
518}
519
525template <RangeLike R>
526 requires std::ranges::bidirectional_range<R>
527[[nodiscard]] constexpr auto ranges_reverse(R &&r)
528{
529 return std::forward<R>(r) | std::views::reverse;
530}
531
532#if ALEPH_HAS_JOIN
536template <RangeLike R>
537[[nodiscard]] constexpr auto ranges_flatten(R &&r)
538{
539 return std::forward<R>(r) | std::views::join;
540}
541#endif
542
543#if ALEPH_HAS_ZIP
547template <RangeLike... Rs>
548[[nodiscard]] constexpr auto ranges_zip(Rs &&...rs)
549{
550 return std::views::zip(std::forward<Rs>(rs)...);
551}
552#endif
553
554#if ALEPH_HAS_ENUMERATE
558template <RangeLike R>
559[[nodiscard]] constexpr auto ranges_enumerate(R &&r)
560{
561 return std::forward<R>(r) | std::views::enumerate;
562}
563#endif
564
570template <RangeLike R, typename T, typename BinaryOp>
571[[nodiscard]] constexpr T ranges_fold_left(R &&r, T init, BinaryOp &&op)
572{
573#ifdef __cpp_lib_ranges_fold
574 return std::ranges::fold_left(std::forward<R>(r), init, std::forward<BinaryOp>(op));
575#else
576 // Fallback for C++20 - use explicit variable to avoid rvalue issues
577 for (auto &&elem : r)
578 init = op(init, elem);
579 return init;
580#endif
581}
582
586template <RangeLike R>
587[[nodiscard]] constexpr auto ranges_sum(R &&r)
588{
589 using T = std::ranges::range_value_t<R>;
590 return ranges_fold_left(std::forward<R>(r), T{0}, std::plus<>{});
591}
592
596template <RangeLike R>
597[[nodiscard]] constexpr auto ranges_product(R &&r)
598{
599 using T = std::ranges::range_value_t<R>;
600 return ranges_fold_left(std::forward<R>(r), T{1}, std::multiplies<>{});
601}
602
606template <RangeLike R>
607[[nodiscard]] constexpr auto ranges_min(R &&r)
608{
609 return std::ranges::min_element(std::forward<R>(r));
610}
611
615template <RangeLike R>
616[[nodiscard]] constexpr auto ranges_max(R &&r)
617{
618 return std::ranges::max_element(std::forward<R>(r));
619}
620
624template <RangeLike R, typename Comp = std::less<>>
625constexpr void ranges_sort(R &&r, Comp &&comp = Comp{})
626{
627 std::ranges::sort(std::forward<R>(r), std::forward<Comp>(comp));
628}
629
630} // namespace detail
631
632// ============================================================================
633// Pipe Operator Support for Aleph Containers
634// ============================================================================
635
644{
645};
646
650template <typename T>
651concept AlephAdaptor = std::derived_from<std::remove_cvref_t<T>, aleph_adaptor_tag>;
652
662template <typename R, AlephAdaptor Adaptor>
663 requires std::ranges::range<std::remove_cvref_t<R>>
664[[nodiscard]] auto operator | (R &&r, const Adaptor &adaptor)
665{
666 return adaptor(std::forward<R>(r));
667}
668
674template <template <typename> class Container>
676{
677 template <typename R>
678 requires std::ranges::range<std::remove_cvref_t<R>>
679 [[nodiscard]] auto operator () (R &&r) const
680 {
681 using T = std::ranges::range_value_t<std::remove_cvref_t<R>>;
682 Container<T> result;
683 for (auto &&elem : r)
684 result.append(std::forward<decltype(elem)>(elem));
685 return result;
686 }
687};
688
699inline constexpr to_aleph_adaptor<DynList> to_dynlist_v{};
700
705
710
714template <template <typename> class Container>
716{
717 template <typename R>
718 requires std::ranges::range<std::remove_cvref_t<R>>
719 [[nodiscard]] auto operator () (R &&r) const
720 {
721 using T = std::ranges::range_value_t<std::remove_cvref_t<R>>;
722 Container<T> result;
723 for (auto &&elem : r)
724 result.push(std::forward<decltype(elem)>(elem));
725 return result;
726 }
727};
728
734
739
743template <template <typename> class Container>
745{
746 template <typename R>
747 requires std::ranges::range<std::remove_cvref_t<R>>
748 [[nodiscard]] auto operator () (R &&r) const
749 {
750 using T = std::ranges::range_value_t<std::remove_cvref_t<R>>;
751 Container<T> result;
752 for (auto &&elem : r)
753 result.put(std::forward<decltype(elem)>(elem));
754 return result;
755 }
756};
757
762
767
772
776template <template <typename, typename...> class Container, typename... ExtraArgs>
778{
779 template <typename R>
780 requires std::ranges::range<std::remove_cvref_t<R>>
781 [[nodiscard]] auto operator () (R &&r) const
782 {
783 using T = std::ranges::range_value_t<std::remove_cvref_t<R>>;
784 Container<T, ExtraArgs...> result;
785 for (auto &&elem : r)
786 result.insert(std::forward<decltype(elem)>(elem));
787 return result;
788 }
789};
790
810template <typename Container, RangeLike R>
812{
813 Container result;
814 for (auto &&elem : r)
815 {
816 if constexpr (requires { result.append(elem); })
817 result.append(std::forward<decltype(elem)>(elem));
818 else if constexpr (requires { result.insert(elem); })
819 result.insert(std::forward<decltype(elem)>(elem));
820 else if constexpr (requires { result.push(elem); })
821 result.push(std::forward<decltype(elem)>(elem));
822 else
823 static_assert(sizeof(Container) == 0,
824 "Container must have append(), insert(), or push() method");
825 }
826 return result;
827}
828
840template <typename Container>
842{
843 template <typename R>
844 requires std::ranges::range<std::remove_cvref_t<R>>
845 [[nodiscard]] Container operator () (R &&r) const
846 {
847 return collect<Container>(std::forward<R>(r));
848 }
849};
850
864template <typename Container>
865[[nodiscard]] constexpr to_adaptor<Container> to()
866{
867 return {};
868}
869
870#else // !ALEPH_HAS_RANGES
871
872// ============================================================================
873// Fallback for C++17 and earlier
874// ============================================================================
875
876// Define ALEPH_HAS_RANGES as 0 for feature detection
877// The public API in ahFunctional.H will be used instead
878
879namespace detail {
880
881// Fallback implementations that work without ranges
882template <typename Container, typename Pred>
884{
885 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
886 if (!pred(it.get_curr()))
887 return false;
888 return true;
889}
890
891template <typename Container, typename Pred>
893{
894 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
895 if (pred(it.get_curr()))
896 return true;
897 return false;
898}
899
900template <typename Container, typename Pred>
902{
903 return !fallback_any_of(c, std::forward<Pred>(pred));
904}
905
912template <typename Container, typename T, typename BinaryOp>
914{
915 for (auto &&elem : c)
916 init = op(std::move(init), elem);
917 return init;
918}
919
923template <typename Container, typename Pred>
925{
926 for (const auto &elem : c)
927 if (!pred(elem))
928 return false;
929 return true;
930}
931
935template <typename Container, typename Pred>
937{
938 for (const auto &elem : c)
939 if (pred(elem))
940 return true;
941 return false;
942}
943
947template <typename Container, typename Pred>
949{
950 return !ranges_any_of(c, std::forward<Pred>(pred));
951}
952
956template <typename Container, typename Pred>
958{
959 size_t count = 0;
960 for (const auto &elem : c)
961 if (pred(elem))
962 ++count;
963 return count;
964}
965
966} // namespace detail
967
968#endif // ALEPH_HAS_RANGES
969
970} // namespace Aleph
971
972#endif // AH_RANGES_H
size_t size_t int32_t value
Definition ca-c-api.h:116
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_binary_ior > > operator|(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4046
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4129
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Freq_Node * pred
Predecessor node in level-order traversal.
bool fallback_all_of(const Container &c, Pred &&pred)
Definition ah-ranges.H:883
auto ranges_count_if(const Container &c, Pred &&pred)
Fallback count_if using range-based for loop.
Definition ah-ranges.H:957
bool fallback_any_of(const Container &c, Pred &&pred)
Definition ah-ranges.H:892
constexpr T ranges_fold_left(Container &&c, T init, BinaryOp &&op)
Fallback fold_left using range-based for loop.
Definition ah-ranges.H:913
bool ranges_none_of(const Container &c, Pred &&pred)
Fallback none_of using range-based for loop.
Definition ah-ranges.H:948
bool fallback_none_of(const Container &c, Pred &&pred)
Definition ah-ranges.H:901
bool ranges_any_of(const Container &c, Pred &&pred)
Fallback any_of using range-based for loop.
Definition ah-ranges.H:936
bool ranges_all_of(const Container &c, Pred &&pred)
Fallback all_of using range-based for loop.
Definition ah-ranges.H:924
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
void sort_range(Range &r, Cmp cmp)
Sort a whole range in place, portably across the ranges divide.
Definition ah-ranges.H:227
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
static std::atomic< bool > init
Definition hash-fct.C:54
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
STL namespace.
gsl_rng * r