Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-uni-functional.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
32# ifndef AH_UNI_FUNCTIONAL_H
33# define AH_UNI_FUNCTIONAL_H
34
71# include <type_traits>
72# include <vector>
73# include <optional>
74# include <functional>
75# include <algorithm>
76# include <utility>
77# include <tuple>
78# include <iterator>
79# include <ah-concepts.H>
80
81namespace Aleph
82{
83 // ============================================================================
84 // Type Traits for Container Detection
85 // ============================================================================
86
87 namespace uni_functional_detail
88 {
89 // Detect if type has STL-style begin()/end()
90 template <typename T>
91 struct has_stl_iterator : std::bool_constant<StlIterableContainer<T>>
92 {};
93
94 // Detect if type has Aleph-style Iterator with has_curr()/get_curr()/next()
95 // Detect if type yields an Aleph iterator (shared with ah-zip-utils.H)
96 template <typename T>
97 struct has_aleph_iterator : std::bool_constant<AlephIterable<T>>
98 {};
99
100 // Build the Aleph iterator the way AlephIterable promises it can be
101 // built, so containers without get_it() (MemArray, raw hash tables) work.
102 template <typename C>
103 [[nodiscard]] auto aleph_iterator(const C & c)
104 {
105 return typename C::Iterator(c);
106 }
107
108 // Detect if type has reverse iterators (rbegin/rend)
109 template <typename T>
110 struct has_reverse_iterator : std::bool_constant<requires(const T & c)
111 {
112 c.rbegin();
113 c.rend();
114 }>
115 {};
116
117 // Get value type from container
118 template <typename T, typename = void>
120
121 template <typename T>
122 struct container_value_type<T, std::enable_if_t<has_stl_iterator<T>::value>>
123 {
124 using type = typename T::value_type;
125 };
126
127 template <typename T>
129 has_aleph_iterator<T>::value and not has_stl_iterator<T>::value>>
130 {
131 using type = std::decay_t<typename T::Item_Type>;
132 };
133
134 template <typename T>
136
137 // Check if container is STL-style
138 template <typename T>
140
141 // Check if container is Aleph-only
142 template <typename T>
143 constexpr bool is_aleph_only_v =
146 } // namespace uni_functional_detail
147
148 // ============================================================================
149 // Core Functional Operations
150 // ============================================================================
151
162 template <typename Op, typename Container>
163 void uni_for_each(Op && op, const Container & c)
164 {
165 auto & op_ref = op;
166 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
167 for (const auto & item: c)
168 op_ref(item);
169 else
170 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
171 op_ref(it.get_curr());
172 }
173
182 template <typename Op, typename Container>
183 void uni_for_each_indexed(Op && op, const Container & c)
184 {
185 auto & op_ref = op;
186 size_t i = 0;
187 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
188 for (const auto & item: c)
189 op_ref(i++, item);
190 else
191 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne(), ++i)
192 op_ref(i, it.get_curr());
193 }
194
204 template <typename Op, typename Container>
205 [[nodiscard]] auto uni_map(Op && op, const Container & c)
206 {
208 using R = std::decay_t<decltype(std::forward<Op>(op)(std::declval<T>()))>;
209
210 std::vector<R> result;
211 auto & op_ref = op;
212
213 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
214 {
215 result.reserve(c.size());
216 for (const auto & item: c)
217 result.push_back(op_ref(item));
218 }
219 else
220 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
221 result.push_back(op_ref(it.get_curr()));
222
223 return result;
224 }
225
235 template <typename Op, typename Container>
236 [[nodiscard]] auto uni_mapi(Op && op, const Container & c)
237 {
239 using R = std::decay_t<decltype(std::forward<Op>(op)(size_t{}, std::declval<T>()))>;
240
241 std::vector<R> result;
242 auto & op_ref = op;
243 size_t i = 0;
244
245 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
246 {
247 result.reserve(c.size());
248 for (const auto & item: c)
249 result.push_back(op_ref(i++, item));
250 }
251 else
252 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne(), ++i)
253 result.push_back(op_ref(i, it.get_curr()));
254
255 return result;
256 }
257
267 template <typename Pred, typename Container>
268 [[nodiscard]] auto uni_filter(Pred && pred, const Container & c)
269 {
271
272 std::vector<T> result;
273 auto & pred_ref = pred;
274
275 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
276 {
277 for (const auto & item: c)
278 if (pred_ref(item))
279 result.push_back(item);
280 }
281 else
282 {
283 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
284 if (const auto & item = it.get_curr(); pred_ref(item))
285 result.push_back(item);
286 }
287 return result;
288 }
289
299 template <typename Pred, typename Container>
300 [[nodiscard]] auto uni_filteri(Pred && pred, const Container & c)
301 {
303
304 std::vector<T> result;
305 auto & pred_ref = pred;
306 size_t i = 0;
307
308 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
309 for (const auto & item: c)
310 {
311 if (pred_ref(i, item))
312 result.push_back(item);
313 ++i;
314 }
315 else
316 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne(), ++i)
317 if (const auto & item = it.get_curr(); pred_ref(i, item))
318 result.push_back(item);
319
320 return result;
321 }
322
333 template <typename T, typename Op, typename Container>
334 [[nodiscard]] T uni_foldl(T init, Op && op, const Container & c)
335 {
336 T acc = std::move(init);
337 auto & op_ref = op;
338
339 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
340 for (const auto & item: c)
341 acc = op_ref(std::move(acc), item);
342 else
343 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
344 acc = op_ref(std::move(acc), it.get_curr());
345 return acc;
346 }
347
349 template <typename T, typename Op, typename Container>
350 [[nodiscard]] T uni_reduce(T init, Op && op, const Container & c)
351 {
352 return uni_foldl(std::move(init), std::forward<Op>(op), c);
353 }
354
365 template <typename T, typename Op, typename Container>
366 [[nodiscard]] std::vector<T> uni_scan_left(T init, Op && op, const Container & c)
367 {
368 std::vector<T> result;
369 result.push_back(init);
370
371 T acc = std::move(init);
372 auto & op_ref = op;
373
374 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
375 for (const auto & item: c)
376 {
377 acc = op_ref(std::move(acc), item);
378 result.push_back(acc);
379 }
380 else
381 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
382 {
383 acc = op_ref(std::move(acc), it.get_curr());
384 result.push_back(acc);
385 }
386 return result;
387 }
388
389 // ============================================================================
390 // Predicates
391 // ============================================================================
392
402 template <typename Pred, typename Container>
403 [[nodiscard]] bool uni_all(Pred && pred, const Container & c)
404 {
405 auto & pred_ref = pred;
406 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
407 {
408 for (const auto & item: c)
409 if (not pred_ref(item))
410 return false;
411 }
412 else
413 {
414 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
415 if (not pred_ref(it.get_curr()))
416 return false;
417 }
418 return true;
419 }
420
430 template <typename Pred, typename Container>
431 [[nodiscard]] bool uni_exists(Pred && pred, const Container & c)
432 {
433 auto & pred_ref = pred;
434 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
435 {
436 for (const auto & item: c)
437 if (pred_ref(item))
438 return true;
439 }
440 else
441 {
442 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
443 if (pred_ref(it.get_curr()))
444 return true;
445 }
446 return false;
447 }
448
450 template <typename Pred, typename Container>
451 [[nodiscard]] bool uni_any(Pred && pred, const Container & c)
452 {
453 return uni_exists(std::forward<Pred>(pred), c);
454 }
455
461 template <typename Pred, typename Container>
462 [[nodiscard]] bool uni_none(Pred && pred, const Container & c)
463 {
464 return not uni_exists(std::forward<Pred>(pred), c);
465 }
466
467 // ============================================================================
468 // Finding Elements
469 // ============================================================================
470
480 template <typename Pred, typename Container>
481 [[nodiscard]] auto uni_find(Pred && pred, const Container & c)
482 {
484
485 auto & pred_ref = pred;
486 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
487 {
488 for (const auto & item: c)
489 if (pred_ref(item))
490 return std::optional<T>(item);
491 }
492 else
493 {
494 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
495 if (const auto & item = it.get_curr(); pred_ref(item))
496 return std::optional<T>(item);
497 }
498 return std::optional<T>{};
499 }
500
510 template <typename Pred, typename Container>
511 [[nodiscard]] std::optional<size_t> uni_find_index(Pred && pred, const Container & c)
512 {
513 auto & pred_ref = pred;
514 size_t i = 0;
515
516 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
517 {
518 for (const auto & item: c)
519 {
520 if (pred_ref(item))
521 return i;
522 ++i;
523 }
524 }
525 else
526 {
527 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne(), ++i)
528 if (pred_ref(it.get_curr()))
529 return i;
530 }
531 return std::nullopt;
532 }
533
543 template <typename Op, typename Container>
544 [[nodiscard]] auto uni_find_mapi(Op && op, const Container & c)
545 {
547 using OptType = std::decay_t<decltype(std::forward<Op>(op)(size_t{}, std::declval<T>()))>;
548
549 auto & op_ref = op;
550 size_t i = 0;
551
552 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
553 {
554 for (const auto & item: c)
555 if (auto result = op_ref(i++, item))
556 return result;
557 }
558 else
559 {
560 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne(), ++i)
561 if (auto result = op_ref(i, it.get_curr()))
562 return result;
563 }
564 return OptType{};
565 }
566
576 template <typename T, typename Container>
577 [[nodiscard]] bool uni_mem(const T & target, const Container & c)
578 {
579 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
580 {
581 for (const auto & item: c)
582 if (item == target)
583 return true;
584 }
585 else
586 {
587 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
588 if (it.get_curr() == target)
589 return true;
590 }
591 return false;
592 }
593
594 // ============================================================================
595 // Counting
596 // ============================================================================
597
607 template <typename Pred, typename Container>
608 [[nodiscard]] size_t uni_count(Pred && pred, const Container & c)
609 {
610 auto & pred_ref = pred;
611 size_t count = 0;
612
613 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
614 {
615 for (const auto & item: c)
616 if (pred_ref(item))
617 ++count;
618 }
619 else
620 {
621 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
622 if (pred_ref(it.get_curr()))
623 ++count;
624 }
625 return count;
626 }
627
636 template <typename Container>
637 [[nodiscard]] size_t uni_length(const Container & c)
638 {
639 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
640 {
641 return c.size();
642 }
643 else
644 {
645 size_t count = 0;
646 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
647 ++count;
648 return count;
649 }
650 }
651
652 // ============================================================================
653 // Taking and Dropping
654 // ============================================================================
655
665 template <typename Container>
666 [[nodiscard]] auto uni_take(size_t n, const Container & c)
667 {
669
670 std::vector<T> result;
671 result.reserve(n);
672 size_t count = 0;
673
674 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
675 {
676 for (const auto & item: c)
677 {
678 if (count >= n) break;
679 result.push_back(item);
680 ++count;
681 }
682 }
683 else
684 {
685 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr() and count < n; it.next_ne(), ++count)
686 result.push_back(it.get_curr());
687 }
688 return result;
689 }
690
700 template <typename Container>
701 [[nodiscard]] auto uni_drop(size_t n, const Container & c)
702 {
704
705 std::vector<T> result;
706 size_t count = 0;
707
708 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
709 {
710 for (const auto & item: c)
711 {
712 if (count >= n)
713 result.push_back(item);
714 ++count;
715 }
716 }
717 else
718 {
719 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne(), ++count)
720 if (count >= n)
721 result.push_back(it.get_curr());
722 }
723 return result;
724 }
725
735 template <typename Pred, typename Container>
737 {
739
740 std::vector<T> result;
741 auto & pred_ref = pred;
742
743 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
744 {
745 for (const auto & item: c)
746 {
747 if (not pred_ref(item))
748 break;
749 result.push_back(item);
750 }
751 }
752 else
753 {
754 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
755 {
756 const auto & item = it.get_curr();
757 if (not pred_ref(item))
758 break;
759 result.push_back(item);
760 }
761 }
762 return result;
763 }
764
774 template <typename Pred, typename Container>
776 {
778
779 std::vector<T> result;
780 auto & pred_ref = pred;
781 bool dropping = true;
782
783 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
784 {
785 for (const auto & item: c)
786 {
787 if (dropping and pred_ref(item))
788 continue;
789 dropping = false;
790 result.push_back(item);
791 }
792 }
793 else
794 {
795 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
796 {
797 const auto & item = it.get_curr();
798 if (dropping and pred_ref(item))
799 continue;
800 dropping = false;
801 result.push_back(item);
802 }
803 }
804 return result;
805 }
806
807 // ============================================================================
808 // Accessing Elements
809 // ============================================================================
810
819 template <typename Container>
820 [[nodiscard]] auto uni_first(const Container & c)
821 {
823
824 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
825 {
826 auto it = c.begin();
827 if (it == c.end())
828 return std::optional<T>{};
829 return std::optional<T>(*it);
830 }
831 else
832 {
834 if (not it.has_curr())
835 return std::optional<T>{};
836 return std::optional<T>(it.get_curr());
837 }
838 }
839
848 template <typename Container>
849 [[nodiscard]] auto uni_last(const Container & c)
850 {
852
853 std::optional<T> result;
854
855 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
856 {
857 for (const auto & item: c)
858 result = item;
859 }
860 else
861 {
862 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
863 result = it.get_curr();
864 }
865 return result;
866 }
867
877 template <typename Container>
878 [[nodiscard]] auto uni_nth(size_t n, const Container & c)
879 {
881
882 size_t i = 0;
883
884 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
885 {
886 for (const auto & item: c)
887 {
888 if (i == n)
889 return std::optional<T>(item);
890 ++i;
891 }
892 }
893 else
894 {
895 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne(), ++i)
896 if (i == n)
897 return std::optional<T>(it.get_curr());
898 }
899 return std::optional<T>{};
900 }
901
902 // ============================================================================
903 // Min/Max
904 // ============================================================================
905
914 template <typename Container>
915 [[nodiscard]] auto uni_min(const Container & c)
916 {
918
919 std::optional<T> result;
920
921 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
922 {
923 auto it = c.begin();
924 if (it == c.end())
925 return result;
926
927 T min_val = *it;
928 ++it;
929 for (; it != c.end(); ++it)
930 if (*it < min_val)
931 min_val = *it;
932 return std::optional<T>(min_val);
933 }
934 else
935 {
937 if (not it.has_curr())
938 return result;
939
940 T min_val = it.get_curr();
941 it.next_ne();
942 for (; it.has_curr(); it.next_ne())
943 {
944 const auto & item = it.get_curr();
945 if (item < min_val)
946 min_val = item;
947 }
948 return std::optional<T>(min_val);
949 }
950 }
951
960 template <typename Container>
961 [[nodiscard]] auto uni_max(const Container & c)
962 {
964
965 std::optional<T> result;
966
967 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
968 {
969 auto it = c.begin();
970 if (it == c.end())
971 return result;
972
973 T max_val = *it;
974 ++it;
975 for (; it != c.end(); ++it)
976 if (*it > max_val)
977 max_val = *it;
978 return std::optional<T>(max_val);
979 }
980 else
981 {
983 if (not it.has_curr())
984 return result;
985
986 T max_val = it.get_curr();
987 it.next_ne();
988 for (; it.has_curr(); it.next_ne())
989 {
990 const auto & item = it.get_curr();
991 if (item > max_val)
992 max_val = item;
993 }
994 return std::optional<T>(max_val);
995 }
996 }
997
1006 template <typename Container>
1007 [[nodiscard]] auto uni_min_max(const Container & c)
1008 {
1010 using ResultType = std::optional<std::pair<T, T>>;
1011
1012 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
1013 {
1014 auto it = c.begin();
1015 if (it == c.end())
1016 return ResultType{};
1017
1018 T min_val = *it;
1019 T max_val = *it;
1020 ++it;
1021
1022 for (; it != c.end(); ++it)
1023 {
1024 if (*it < min_val) min_val = *it;
1025 if (*it > max_val) max_val = *it;
1026 }
1027 return ResultType(std::make_pair(min_val, max_val));
1028 }
1029 else
1030 {
1032 if (not it.has_curr())
1033 return ResultType{};
1034
1035 T min_val = it.get_curr();
1036 T max_val = min_val;
1037 it.next_ne();
1038
1039 for (; it.has_curr(); it.next_ne())
1040 {
1041 const auto & item = it.get_curr();
1042 if (item < min_val) min_val = item;
1043 if (item > max_val) max_val = item;
1044 }
1045 return ResultType(std::make_pair(min_val, max_val));
1046 }
1047 }
1048
1049 // ============================================================================
1050 // Sum and Product
1051 // ============================================================================
1052
1061 template <typename Container>
1062 [[nodiscard]] auto uni_sum(const Container & c)
1063 {
1065 T sum{};
1066
1067 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
1068 {
1069 for (const auto & item: c)
1070 sum = sum + item;
1071 }
1072 else
1073 {
1074 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
1075 sum = sum + it.get_curr();
1076 }
1077 return sum;
1078 }
1079
1088 template <typename Container>
1089 [[nodiscard]] auto uni_product(const Container & c)
1090 {
1092
1093 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
1094 {
1095 auto it = c.begin();
1096 if (it == c.end()) return T{};
1097
1098 T prod = *it;
1099 ++it;
1100 for (; it != c.end(); ++it)
1101 prod = prod * (*it);
1102 return prod;
1103 }
1104 else
1105 {
1107 if (not it.has_curr()) return T{};
1108
1109 T prod = it.get_curr();
1110 it.next_ne();
1111 for (; it.has_curr(); it.next_ne())
1112 prod = prod * it.get_curr();
1113 return prod;
1114 }
1115 }
1116
1117 // ============================================================================
1118 // Partitioning
1119 // ============================================================================
1120
1130 template <typename Pred, typename Container>
1132 {
1134
1135 std::vector<T> matching, non_matching;
1136 auto & pred_ref = pred;
1137
1138 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
1139 {
1140 for (const auto & item: c)
1141 {
1142 if (pred_ref(item))
1143 matching.push_back(item);
1144 else
1145 non_matching.push_back(item);
1146 }
1147 }
1148 else
1149 {
1150 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
1151 {
1152 const auto & item = it.get_curr();
1153 if (pred_ref(item))
1154 matching.push_back(item);
1155 else
1156 non_matching.push_back(item);
1157 }
1158 }
1159 return std::make_pair(std::move(matching), std::move(non_matching));
1160 }
1161
1162 // ============================================================================
1163 // Concatenation and Flattening
1164 // ============================================================================
1165
1175 template <typename Container1, typename Container2>
1176 [[nodiscard]] auto uni_concat(const Container1 & c1, const Container2 & c2)
1177 {
1179
1180 std::vector<T> result;
1181
1182 if constexpr (uni_functional_detail::is_stl_container_v<Container1>)
1183 for (const auto & item: c1)
1184 result.push_back(item);
1185 else
1186 for (auto it = uni_functional_detail::aleph_iterator(c1); it.has_curr(); it.next_ne())
1187 result.push_back(it.get_curr());
1188
1189 if constexpr (uni_functional_detail::is_stl_container_v<Container2>)
1190 for (const auto & item: c2)
1191 result.push_back(item);
1192 else
1193 for (auto it = uni_functional_detail::aleph_iterator(c2); it.has_curr(); it.next_ne())
1194 result.push_back(it.get_curr());
1195
1196 return result;
1197 }
1198
1207 template <typename Container>
1208 [[nodiscard]] auto uni_flatten(const Container & c)
1209 {
1212
1213 std::vector<T> result;
1214
1215 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
1216 {
1217 for (const auto & inner: c)
1218 {
1219 if constexpr (uni_functional_detail::is_stl_container_v<InnerContainer>)
1220 for (const auto & item: inner)
1221 result.push_back(item);
1222 else
1223 for (auto it = uni_functional_detail::aleph_iterator(inner); it.has_curr(); it.next_ne())
1224 result.push_back(it.get_curr());
1225 }
1226 }
1227 else
1228 {
1229 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
1230 {
1231 const auto & inner = it.get_curr();
1232 if constexpr (uni_functional_detail::is_stl_container_v<InnerContainer>)
1233 for (const auto & item: inner)
1234 result.push_back(item);
1235 else
1236 for (auto it2 = uni_functional_detail::aleph_iterator(inner); it2.has_curr(); it2.next_ne())
1237 result.push_back(it2.get_curr());
1238 }
1239 }
1240
1241 return result;
1242 }
1243
1253 template <typename Op, typename Container>
1254 [[nodiscard]] auto uni_flat_map(Op && op, const Container & c)
1255 {
1257 using InnerContainer = std::decay_t<decltype(std::forward<Op>(op)(std::declval<T>()))>;
1259
1260 std::vector<R> result;
1261 auto & op_ref = op;
1262
1263 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
1264 {
1265 for (const auto & item: c)
1266 {
1267 auto inner = op_ref(item);
1268 if constexpr (uni_functional_detail::is_stl_container_v<InnerContainer>)
1269 for (const auto & inner_item: inner)
1270 result.push_back(inner_item);
1271 else
1272 for (auto it = uni_functional_detail::aleph_iterator(inner); it.has_curr(); it.next_ne())
1273 result.push_back(it.get_curr());
1274 }
1275 }
1276 else
1277 {
1278 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
1279 {
1280 auto inner = op_ref(it.get_curr());
1281 if constexpr (uni_functional_detail::is_stl_container_v<InnerContainer>)
1282 for (const auto & inner_item: inner)
1283 result.push_back(inner_item);
1284 else
1285 for (auto it2 = uni_functional_detail::aleph_iterator(inner); it2.has_curr(); it2.next_ne())
1286 result.push_back(it2.get_curr());
1287 }
1288 }
1289
1290 return result;
1291 }
1292
1293 // ============================================================================
1294 // Uniqueness and Grouping
1295 // ============================================================================
1296
1308 template <typename Container>
1310 {
1312
1313 std::vector<T> result;
1314
1315 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
1316 {
1317 for (const auto & item: c)
1318 if (std::find(result.begin(), result.end(), item) == result.end())
1319 result.push_back(item);
1320 }
1321 else
1322 {
1323 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
1324 if (const auto & item = it.get_curr(); std::find(result.begin(), result.end(), item) == result.end())
1325 result.push_back(item);
1326 }
1327
1328 return result;
1329 }
1330
1340 template <typename Key, typename Container>
1341 [[nodiscard]] auto uni_group_by(Key && key, const Container & c)
1342 {
1344 using K = std::decay_t<decltype(std::forward<Key>(key)(std::declval<T>()))>;
1345
1346 std::vector<std::pair<K, std::vector<T>>> result;
1347 auto & key_ref = key;
1348
1349 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
1350 {
1351 for (const auto & item: c)
1352 {
1353 auto k = key_ref(item);
1354 auto it = std::find_if(result.begin(), result.end(),
1355 [&k](const auto & p) { return p.first == k; });
1356 if (it != result.end())
1357 it->second.push_back(item);
1358 else
1359 result.emplace_back(std::move(k), std::vector<T>{item});
1360 }
1361 }
1362 else
1363 {
1364 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
1365 {
1366 const auto & item = it.get_curr();
1367 auto k = key_ref(item);
1368 auto res_it = std::find_if(result.begin(), result.end(),
1369 [&k](const auto & p) { return p.first == k; });
1370 if (res_it != result.end())
1371 res_it->second.push_back(item);
1372 else
1373 result.emplace_back(std::move(k), std::vector<T>{item});
1374 }
1375 }
1376
1377 return result;
1378 }
1379
1388 template <typename Container>
1389 [[nodiscard]] auto uni_tally(const Container & c)
1390 {
1392
1393 std::vector<std::pair<T, size_t>> result;
1394
1395 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
1396 {
1397 for (const auto & item: c)
1398 {
1399 auto it = std::find_if(result.begin(), result.end(),
1400 [&item](const auto & p) { return p.first == item; });
1401 if (it != result.end())
1402 ++it->second;
1403 else
1404 result.emplace_back(item, 1);
1405 }
1406 }
1407 else
1408 {
1409 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
1410 {
1411 const auto & item = it.get_curr();
1412 auto res_it = std::find_if(result.begin(), result.end(),
1413 [&item](const auto & p) { return p.first == item; });
1414 if (res_it != result.end())
1415 ++res_it->second;
1416 else
1417 result.emplace_back(item, 1);
1418 }
1419 }
1420
1421 return result;
1422 }
1423
1424 // ============================================================================
1425 // Conversion
1426 // ============================================================================
1427
1436 template <typename Container>
1438 {
1440
1441 std::vector<T> result;
1442
1443 if constexpr (uni_functional_detail::is_stl_container_v<Container>)
1444 {
1445 result.reserve(c.size());
1446 for (const auto & item: c)
1447 result.push_back(item);
1448 }
1449 else
1450 {
1451 for (auto it = uni_functional_detail::aleph_iterator(c); it.has_curr(); it.next_ne())
1452 result.push_back(it.get_curr());
1453 }
1454 return result;
1455 }
1456
1457 // ============================================================================
1458 // Comparison
1459 // ============================================================================
1460
1473 template <typename Container1, typename Container2>
1474 [[nodiscard]] bool uni_equal(const Container1 & c1, const Container2 & c2)
1475 {
1476 constexpr bool c1_is_stl = uni_functional_detail::is_stl_container_v<Container1>;
1477 constexpr bool c2_is_stl = uni_functional_detail::is_stl_container_v<Container2>;
1478
1479 if constexpr (c1_is_stl and c2_is_stl)
1480 {
1481 // Both STL: use standard iterators
1482 auto it1 = c1.begin();
1483 auto it2 = c2.begin();
1484 for (; it1 != c1.end() and it2 != c2.end(); ++it1, ++it2)
1485 if (not (*it1 == *it2))
1486 return false;
1487 return it1 == c1.end() and it2 == c2.end();
1488 }
1489 else if constexpr (c1_is_stl and not c2_is_stl)
1490 {
1491 // c1 STL, c2 Aleph
1492 auto it1 = c1.begin();
1494 for (; it1 != c1.end() and it2.has_curr(); ++it1, it2.next_ne())
1495 if (not (*it1 == it2.get_curr()))
1496 return false;
1497 return it1 == c1.end() and not it2.has_curr();
1498 }
1499 else if constexpr (not c1_is_stl and c2_is_stl)
1500 {
1501 // c1 Aleph, c2 STL
1503 auto it2 = c2.begin();
1504 for (; it1.has_curr() and it2 != c2.end(); it1.next_ne(), ++it2)
1505 if (not (it1.get_curr() == *it2))
1506 return false;
1507 return not it1.has_curr() and it2 == c2.end();
1508 }
1509 else
1510 {
1511 // Both Aleph
1514 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
1515 if (not (it1.get_curr() == it2.get_curr()))
1516 return false;
1517 return not it1.has_curr() and not it2.has_curr();
1518 }
1519 }
1520
1533 template <typename Container1, typename Container2>
1535 {
1536 constexpr bool c1_is_stl = uni_functional_detail::is_stl_container_v<Container1>;
1537 constexpr bool c2_is_stl = uni_functional_detail::is_stl_container_v<Container2>;
1538
1539 if constexpr (c1_is_stl and c2_is_stl)
1540 {
1541 // Both STL: use standard iterators
1542 auto it1 = c1.begin();
1543 auto it2 = c2.begin();
1544 for (; it1 != c1.end() and it2 != c2.end(); ++it1, ++it2)
1545 {
1546 if (*it1 < *it2) return -1;
1547 if (*it2 < *it1) return 1;
1548 }
1549 if (it1 == c1.end() and it2 == c2.end()) return 0;
1550 return (it1 == c1.end()) ? -1 : 1;
1551 }
1552 else if constexpr (c1_is_stl and not c2_is_stl)
1553 {
1554 // c1 STL, c2 Aleph
1555 auto it1 = c1.begin();
1557 for (; it1 != c1.end() and it2.has_curr(); ++it1, it2.next_ne())
1558 {
1559 if (*it1 < it2.get_curr()) return -1;
1560 if (it2.get_curr() < *it1) return 1;
1561 }
1562 if (it1 == c1.end() and not it2.has_curr()) return 0;
1563 return (it1 == c1.end()) ? -1 : 1;
1564 }
1565 else if constexpr (not c1_is_stl and c2_is_stl)
1566 {
1567 // c1 Aleph, c2 STL
1569 auto it2 = c2.begin();
1570 for (; it1.has_curr() and it2 != c2.end(); it1.next_ne(), ++it2)
1571 {
1572 if (it1.get_curr() < *it2) return -1;
1573 if (*it2 < it1.get_curr()) return 1;
1574 }
1575 if (not it1.has_curr() and it2 == c2.end()) return 0;
1576 return (not it1.has_curr()) ? -1 : 1;
1577 }
1578 else
1579 {
1580 // Both Aleph
1583 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
1584 {
1585 if (it1.get_curr() < it2.get_curr()) return -1;
1586 if (it2.get_curr() < it1.get_curr()) return 1;
1587 }
1588 if (not it1.has_curr() and not it2.has_curr()) return 0;
1589 return (not it1.has_curr()) ? -1 : 1;
1590 }
1591 }
1592} // end namespace Aleph
1593
1594# endif // AH_UNI_FUNCTIONAL_H
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
size_t size_t int32_t value
Definition ca-c-api.h:116
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.
typename container_value_type< std::decay_t< T > >::type value_t
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
T uni_reduce(T init, Op &&op, const Container &c)
Alias for uni_foldl.
auto uni_distinct(const Container &c)
Remove all duplicates (keeps first occurrence).
bool uni_none(Pred &&pred, const Container &c)
Check if no element satisfies predicate.
auto uni_filter(Pred &&pred, const Container &c)
Filter elements satisfying predicate.
auto uni_nth(size_t n, const Container &c)
Get n-th element.
int uni_compare(const Container1 &c1, const Container2 &c2)
Compare two containers lexicographically.
bool uni_equal(const Container1 &c1, const Container2 &c2)
Check equality of two containers.
std::vector< T > uni_scan_left(T init, Op &&op, const Container &c)
Scan left - fold with all intermediate results.
size_t uni_length(const Container &c)
Get container length.
auto uni_tally(const Container &c)
Count occurrences of each element (frequency count).
auto uni_flatten(const Container &c)
Flatten a container of containers.
auto uni_flat_map(Op &&op, const Container &c)
Flat map - map then flatten.
auto uni_drop_while(Pred &&pred, const Container &c)
Drop elements while predicate is true, return the rest.
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
auto uni_product(const Container &c)
Product of all elements.
auto uni_find(Pred &&pred, const Container &c)
Find first element satisfying predicate.
bool uni_mem(const T &target, const Container &c)
Check if element exists in container (mem in ML).
auto uni_group_by(Key &&key, const Container &c)
Group elements by key function.
auto uni_filteri(Pred &&pred, const Container &c)
Filter with index (filteri in ML).
auto uni_map(Op &&op, const Container &c)
Map operation - transform each element.
auto uni_concat(const Container1 &c1, const Container2 &c2)
Concatenate two containers.
auto uni_last(const Container &c)
Get last element.
auto uni_min_max(const Container &c)
Get both min and max in a single pass.
auto uni_min(const Container &c)
Get minimum element.
size_t uni_count(Pred &&pred, const Container &c)
Count elements satisfying predicate.
void uni_for_each_indexed(Op &&op, const Container &c)
Apply operation to each element with index.
T uni_foldl(T init, Op &&op, const Container &c)
Left fold (foldl) - reduce from left to right.
auto uni_drop(size_t n, const Container &c)
Drop first n elements, return the rest.
auto uni_max(const Container &c)
Get maximum element.
void uni_for_each(Op &&op, const Container &c)
Apply operation to each element (for_each).
auto uni_find_mapi(Op &&op, const Container &c)
Find and map with index (find_mapi in ML).
auto uni_take_while(Pred &&pred, const Container &c)
Take elements while predicate is true.
bool uni_all(Pred &&pred, const Container &c)
Check if all elements satisfy predicate.
auto uni_first(const Container &c)
Get first element.
auto uni_partition(Pred &&pred, const Container &c)
Partition elements by predicate.
static std::atomic< bool > init
Definition hash-fct.C:54
auto uni_to_vector(const Container &c)
Convert container to std::vector.
auto uni_mapi(Op &&op, const Container &c)
Map with index (mapi in ML).
bool uni_any(Pred &&pred, const Container &c)
Alias for uni_exists.
auto uni_take(size_t n, const Container &c)
Take first n elements.
auto uni_sum(const Container &c)
Sum all elements.
bool uni_exists(Pred &&pred, const Container &c)
Check if any element satisfies predicate.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
std::optional< size_t > uni_find_index(Pred &&pred, const Container &c)
Find index of first element satisfying predicate.
STL namespace.
static int * k