Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-stl-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_STL_FUNCTIONAL_H
33# define AH_STL_FUNCTIONAL_H
34
74# include <type_traits>
75# include <vector>
76# include <optional>
77# include <functional>
78# include <algorithm>
79# include <numeric>
80# include <utility>
81# include <tuple>
82# include <iterator>
83# include <stdexcept>
84# include <unordered_set>
85# include <unordered_map>
86# include <ah-concepts.H>
87# include <ah-ranges.H>
88
89namespace Aleph
90{
91 // ============================================================================
92 // Type Traits and Concepts
93 // ============================================================================
94
95 namespace stl_detail
96 {
98 inline constexpr size_t ADAPTIVE_THRESHOLD = 64;
99
101 template <typename T>
102 struct has_size : std::bool_constant<requires { std::declval<T>().size(); }> {};
103
104 template <typename T>
105 inline constexpr bool has_size_v = has_size<T>::value;
106
108 template <typename T>
109 struct is_std_hashable : std::bool_constant<requires { std::hash<T>{}(std::declval<T>()); }> {};
110
111 template <typename T>
113
115 template <typename T>
116 struct has_reverse_iterators : std::bool_constant<requires
117 {
118 std::declval<T>().rbegin();
119 std::declval<T>().rend();
120 }> {};
121
122 template <typename T>
124
126 template <typename Container>
127 [[nodiscard]] size_t safe_size(const Container & c)
128 {
129 if constexpr (has_size_v<Container>)
130 return c.size();
131 else
132 return 0; // Cannot determine size efficiently
133 }
134
136 template <typename Result, typename Container>
137 void try_reserve(Result & result, const Container & c)
138 {
139 if constexpr (has_size_v<Container>)
140 result.reserve(c.size());
141 }
142
144 template <typename Result>
145 void try_reserve_n(Result & result, size_t n)
146 {
147 if constexpr (requires { result.reserve(n); })
148 result.reserve(n);
149 }
150 } // namespace stl_detail
151
152 // ============================================================================
153 // Range Generation
154 // ============================================================================
155
174 template <typename T = int>
175 [[nodiscard]] std::vector<T> stl_range(T start, T end, T step = 1)
176 {
177 std::vector<T> result;
178 if (step > 0 and start <= end)
179 {
180 result.reserve(static_cast<size_t>((end - start) / step + 1));
181 for (T i = start; i <= end; i += step)
182 result.push_back(i);
183 }
184 else if (step < 0 and start >= end)
185 {
186 result.reserve(static_cast<size_t>((start - end) / (-step) + 1));
187 for (T i = start; i >= end; i += step)
188 result.push_back(i);
189 }
190 return result;
191 }
192
202 template <typename T = int>
203 [[nodiscard]] std::vector<T> stl_range(T n)
204 {
205 std::vector<T> result;
206 result.reserve(static_cast<size_t>(n));
207 for (T i = 0; i < n; ++i)
208 result.push_back(i);
209 return result;
210 }
211
223 template <typename T = double>
224 [[nodiscard]] std::vector<T> stl_linspace(T start, T end, size_t n)
225 {
226 std::vector<T> result;
227 if (n == 0) return result;
228 result.reserve(n);
229 if (n == 1)
230 {
231 result.push_back(start);
232 return result;
233 }
234
235 result.reserve(n);
236 const auto step = (end - start) / static_cast<T>(n - 1);
237 for (size_t i = 0; i < n; ++i)
238 result.push_back(start + static_cast<T>(i) * step);
239 return result;
240 }
241
252 template <typename T>
253 [[nodiscard]] std::vector<T> stl_rep(size_t n, const T & value)
254 {
255 return std::vector<T>(n, value);
256 }
257
268 template <typename Gen>
269 [[nodiscard]] auto stl_generate(size_t n, Gen && gen)
270 {
271 using T = std::decay_t<decltype(gen(size_t{}))>;
272 std::vector<T> result;
273 result.reserve(n);
274 auto & gen_ref = gen; // Preserve as lvalue to avoid moving in loop
275 for (size_t i = 0; i < n; ++i)
276 result.push_back(gen_ref(i));
277 return result;
278 }
279
280 // ============================================================================
281 // Core Functional Operations
282 // ============================================================================
283
293 template <typename Op, typename Container>
294 void stl_for_each(Op && op, const Container & c)
295 {
296 auto & op_ref = op; // Preserve as lvalue to avoid moving in loop
297 for (const auto & item: c)
298 op_ref(item);
299 }
300
310 template <typename Op, typename Container>
311 void stl_for_each_indexed(Op && op, const Container & c)
312 {
313 auto & op_ref = op; // Preserve as lvalue to avoid moving in loop
314 size_t i = 0;
315 for (const auto & item: c)
316 op_ref(i++, item);
317 }
318
334 template <typename Op, typename Container>
335 [[nodiscard]] auto stl_map(Op && op, const Container & c)
336 {
337 using T = typename Container::value_type;
338 using R = std::decay_t<decltype(op(std::declval<T>()))>;
339
340 std::vector<R> result;
341 stl_detail::try_reserve(result, c);
342 auto & op_ref = op; // Preserve as lvalue to avoid moving in loop
343 for (const auto & item: c)
344 result.push_back(op_ref(item));
345 return result;
346 }
347
358 template <typename Op, typename Container>
359 [[nodiscard]] auto stl_mapi(Op && op, const Container & c)
360 {
361 using T = typename Container::value_type;
362 using R = std::decay_t<decltype(op(size_t{}, std::declval<T>()))>;
363
364 std::vector<R> result;
365 stl_detail::try_reserve(result, c);
366 auto & op_ref = op; // Preserve as lvalue to avoid moving in loop
367 size_t i = 0;
368 for (const auto & item: c)
369 result.push_back(op_ref(i++, item));
370 return result;
371 }
372
383 template <typename Pred, typename Container>
384 [[nodiscard]] auto stl_filter(Pred && pred, const Container & c)
385 {
386 using T = typename Container::value_type;
387
388 std::vector<T> result;
389 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
390 for (const auto & item: c)
391 if (pred_ref(item))
392 result.push_back(item);
393 return result;
394 }
395
406 template <typename Pred, typename Container>
407 [[nodiscard]] auto stl_filteri(Pred && pred, const Container & c)
408 {
409 using T = typename Container::value_type;
410
411 std::vector<T> result;
412 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
413 size_t i = 0;
414 for (const auto & item: c)
415 {
416 if (pred_ref(i, item))
417 result.push_back(item);
418 ++i;
419 }
420 return result;
421 }
422
441 template <typename T, typename Op, typename Container>
442 [[nodiscard]] T stl_foldl(T init, Op && op, const Container & c)
443 {
444#if ALEPH_HAS_RANGES
445 if constexpr (std::ranges::range<Container>)
446 return detail::ranges_fold_left(c, std::move(init), std::forward<Op>(op));
447 else
448#endif
449 {
450 T acc = std::move(init);
451 auto & op_ref = op; // Preserve as lvalue to avoid moving in loop
452 for (const auto & item: c)
453 acc = op_ref(std::move(acc), item);
454 return acc;
455 }
456 }
457
479 template <typename T, typename Op, typename Container>
480 [[nodiscard]] T stl_foldr(T init, Op && op, const Container & c)
481 {
482 static_assert(stl_detail::has_reverse_iterators_v<Container>,
483 "stl_foldr requires a container with reverse iterators (rbegin/rend)");
484 T acc = std::move(init);
485 auto & op_ref = op; // Preserve as lvalue to avoid moving in loop
486 for (auto it = c.rbegin(); it != c.rend(); ++it)
487 acc = op_ref(*it, std::move(acc));
488 return acc;
489 }
490
508 template <typename T, typename Op, typename Container>
509 [[nodiscard]] std::vector<T> stl_scan_left(T init, Op && op, const Container & c)
510 {
511 std::vector<T> result;
512 if constexpr (stl_detail::has_size_v<Container>)
513 result.reserve(c.size() + 1);
514 result.push_back(init);
515
516 T acc = std::move(init);
517 auto & op_ref = op; // Preserve as lvalue to avoid moving in loop
518 for (const auto & item: c)
519 {
520 acc = op_ref(std::move(acc), item);
521 result.push_back(acc);
522 }
523 return result;
524 }
525
537 template <typename T, typename Op, typename Container>
538 [[nodiscard]] std::vector<T> stl_scan_right(T init, Op && op, const Container & c)
539 {
540 static_assert(stl_detail::has_reverse_iterators_v<Container>,
541 "stl_scan_right requires a container with reverse iterators (rbegin/rend)");
542 std::vector<T> result;
543 if constexpr (stl_detail::has_size_v<Container>)
544 result.reserve(c.size() + 1);
545
546 T acc = std::move(init);
547 result.push_back(acc);
548
549 auto & op_ref = op; // Preserve as lvalue to avoid moving in loop
550 for (auto it = c.rbegin(); it != c.rend(); ++it)
551 {
552 acc = op_ref(*it, std::move(acc));
553 result.push_back(acc);
554 }
555
556 std::reverse(result.begin(), result.end());
557 return result;
558 }
559
561 template <typename T, typename Op, typename Container>
562 [[nodiscard]] T stl_reduce(T init, Op && op, const Container & c)
563 {
564 return stl_foldl(std::move(init), std::forward<Op>(op), c);
565 }
566
567 // ============================================================================
568 // Predicates
569 // ============================================================================
570
581 template <typename Pred, typename Container>
582 [[nodiscard]] bool stl_all(Pred && pred, const Container & c)
583 {
584#if ALEPH_HAS_RANGES
585 if constexpr (std::ranges::range<Container>)
586 return detail::ranges_all_of(c, std::forward<Pred>(pred));
587 else
588#endif
589 {
590 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
591 for (const auto & item: c)
592 if (not pred_ref(item))
593 return false;
594 return true;
595 }
596 }
597
608 template <typename Pred, typename Container>
609 [[nodiscard]] bool stl_exists(Pred && pred, const Container & c)
610 {
611#if ALEPH_HAS_RANGES
612 if constexpr (std::ranges::range<Container>)
613 return detail::ranges_any_of(c, std::forward<Pred>(pred));
614 else
615#endif
616 {
617 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
618 for (const auto & item: c)
619 if (pred_ref(item))
620 return true;
621 return false;
622 }
623 }
624
626 template <typename Pred, typename Container>
627 [[nodiscard]] bool stl_any(Pred && pred, const Container & c)
628 {
629 return stl_exists(std::forward<Pred>(pred), c);
630 }
631
638 template <typename Pred, typename Container>
639 [[nodiscard]] bool stl_none(Pred && pred, const Container & c)
640 {
641 return not stl_exists(std::forward<Pred>(pred), c);
642 }
643
644 // ============================================================================
645 // Finding Elements
646 // ============================================================================
647
658 template <typename Pred, typename Container>
659 [[nodiscard]] auto stl_find(Pred && pred, const Container & c)
660 {
661 using T = typename Container::value_type;
662
663 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
664 for (const auto & item: c)
665 if (pred_ref(item))
666 return std::optional<T>(item);
667 return std::optional<T>{};
668 }
669
680 template <typename Pred, typename Container>
681 [[nodiscard]] auto stl_find_last(Pred && pred, const Container & c)
682 {
683 using T = typename Container::value_type;
684
685 std::optional<T> result;
686 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
687 for (const auto & item: c)
688 if (pred_ref(item))
689 result = item;
690 return result;
691 }
692
703 template <typename Pred, typename Container>
704 [[nodiscard]] std::optional<size_t> stl_find_index(Pred && pred, const Container & c)
705 {
706 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
707 size_t i = 0;
708 for (const auto & item: c)
709 {
710 if (pred_ref(item))
711 return i;
712 ++i;
713 }
714 return std::nullopt;
715 }
716
727 template <typename Op, typename Container>
728 [[nodiscard]] auto stl_find_mapi(Op && op, const Container & c)
729 {
730 using T = typename Container::value_type;
731 using OptType = std::decay_t<decltype(op(size_t{}, std::declval<T>()))>;
732 static_assert(std::is_default_constructible_v<OptType>,
733 "stl_find_mapi requires the return type to be default-constructible (like std::optional)");
734
735 auto & op_ref = op; // Preserve as lvalue to avoid moving in loop
736 size_t i = 0;
737 for (const auto & item: c)
738 if (auto result = op_ref(i++, item))
739 return result;
740 return OptType{};
741 }
742
753 template <typename T, typename Container>
754 [[nodiscard]] bool stl_mem(const T & target, const Container & c)
755 {
756 for (const auto & item: c)
757 if (item == target)
758 return true;
759 return false;
760 }
761
762 // ============================================================================
763 // Counting
764 // ============================================================================
765
776 template <typename Pred, typename Container>
777 [[nodiscard]] size_t stl_count(Pred && pred, const Container & c)
778 {
779 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
780 size_t count = 0;
781 for (const auto & item: c)
782 if (pred_ref(item))
783 ++count;
784 return count;
785 }
786
797 template <typename T, typename Container>
798 [[nodiscard]] size_t stl_count_value(const T & target, const Container & c)
799 {
800 size_t count = 0;
801 for (const auto & item: c)
802 if (item == target)
803 ++count;
804 return count;
805 }
806
807 // ============================================================================
808 // Taking and Dropping
809 // ============================================================================
810
821 template <typename Container>
822 [[nodiscard]] auto stl_take(size_t n, const Container & c)
823 {
824 using T = typename Container::value_type;
825
826 std::vector<T> result;
827 result.reserve(n);
828 size_t count = 0;
829 for (const auto & item: c)
830 {
831 if (count >= n) break;
832 result.push_back(item);
833 ++count;
834 }
835 return result;
836 }
837
848 template <typename Container>
849 [[nodiscard]] auto stl_drop(size_t n, const Container & c)
850 {
851 using T = typename Container::value_type;
852
853 std::vector<T> result;
854 if constexpr (stl_detail::has_size_v<Container>)
855 {
856 if (const size_t size = c.size(); size > n)
857 result.reserve(size - n);
858 }
859 size_t count = 0;
860 for (const auto & item: c)
861 {
862 if (count >= n)
863 result.push_back(item);
864 ++count;
865 }
866 return result;
867 }
868
879 template <typename Container>
880 [[nodiscard]] auto stl_take_last(size_t n, const Container & c)
881 {
882 using T = typename Container::value_type;
883
884 std::vector<T> result;
885 size_t size = stl_detail::safe_size(c);
886
887 // If container doesn't have size(), we need to iterate twice or use a different approach
888 if constexpr (!stl_detail::has_size_v<Container>)
889 {
890 // For containers without size(), collect all then take last n
891 std::vector<T> all(c.begin(), c.end());
892 size = all.size();
893 const size_t skip = size > n ? (size - n) : 0;
894 result.reserve(size > n ? n : size);
895 for (size_t i = skip; i < size; ++i)
896 result.push_back(std::move(all[i]));
897 return result;
898 }
899 else
900 {
901 size_t actual_n = size > n ? n : size;
902 result.reserve(actual_n);
903 const size_t skip = size > n ? (size - n) : 0;
904
905 size_t count = 0;
906 for (const auto & item: c)
907 {
908 if (count >= skip)
909 result.push_back(item);
910 ++count;
911 }
912 return result;
913 }
914 }
915
926 template <typename Pred, typename Container>
928 {
929 using T = typename Container::value_type;
930
931 std::vector<T> result;
932 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
933 for (const auto & item: c)
934 {
935 if (not pred_ref(item))
936 break;
937 result.push_back(item);
938 }
939 return result;
940 }
941
952 template <typename Pred, typename Container>
954 {
955 using T = typename Container::value_type;
956
957 std::vector<T> result;
958 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
959 bool dropping = true;
960 for (const auto & item: c)
961 {
962 if (dropping and pred_ref(item))
963 continue;
964 dropping = false;
965 result.push_back(item);
966 }
967 return result;
968 }
969
970 // ============================================================================
971 // Accessing Elements
972 // ============================================================================
973
983 template <typename Container>
984 [[nodiscard]] auto stl_first(const Container & c)
985 {
986 using T = typename Container::value_type;
987
988 auto it = c.begin();
989 if (it == c.end())
990 return std::optional<T>{};
991 return std::optional<T>(*it);
992 }
993
1003 template <typename Container>
1004 [[nodiscard]] auto stl_last(const Container & c)
1005 {
1006 using T = typename Container::value_type;
1007
1008 auto it = c.begin();
1009 if (it == c.end())
1010 return std::optional<T>{};
1011
1012 // Use reverse iterators if available (more efficient)
1013 if constexpr (stl_detail::has_reverse_iterators_v<Container>)
1014 {
1015 return std::optional<T>(*c.rbegin());
1016 }
1017 else
1018 {
1019 // Fallback: iterate through entire container (for forward_list, etc.)
1020 T last = *it;
1021 ++it;
1022 for (; it != c.end(); ++it)
1023 last = *it;
1024 return std::optional<T>(last);
1025 }
1026 }
1027
1038 template <typename Container>
1039 [[nodiscard]] auto stl_nth(const size_t n, const Container & c)
1040 {
1041 using T = typename Container::value_type;
1042
1043 size_t i = 0;
1044 for (const auto & item: c)
1045 {
1046 if (i == n)
1047 return std::optional<T>(item);
1048 ++i;
1049 }
1050 return std::optional<T>{};
1051 }
1052
1053 // ============================================================================
1054 // Min/Max
1055 // ============================================================================
1056
1066 template <typename Container>
1067 [[nodiscard]] auto stl_min(const Container & c)
1068 {
1069 using T = typename Container::value_type;
1070
1071 auto it = c.begin();
1072 if (it == c.end())
1073 return std::optional<T>{};
1074
1075 T min_val = *it;
1076 ++it;
1077 for (; it != c.end(); ++it)
1078 if (*it < min_val)
1079 min_val = *it;
1080 return std::optional<T>(min_val);
1081 }
1082
1092 template <typename Container>
1093 [[nodiscard]] auto stl_max(const Container & c)
1094 {
1095 using T = typename Container::value_type;
1096
1097 auto it = c.begin();
1098 if (it == c.end())
1099 return std::optional<T>{};
1100
1101 T max_val = *it;
1102 ++it;
1103 for (; it != c.end(); ++it)
1104 if (*it > max_val)
1105 max_val = *it;
1106 return std::optional<T>(max_val);
1107 }
1108
1118 template <typename Container>
1119 [[nodiscard]] auto stl_min_max(const Container & c)
1120 {
1121 using T = typename Container::value_type;
1122 using ResultType = std::optional<std::pair<T, T>>;
1123
1124 auto it = c.begin();
1125 if (it == c.end())
1126 return ResultType{};
1127
1128 T min_val = *it;
1129 T max_val = *it;
1130 ++it;
1131
1132 for (; it != c.end(); ++it)
1133 {
1134 if (*it < min_val) min_val = *it;
1135 if (*it > max_val) max_val = *it;
1136 }
1137 return ResultType(std::make_pair(min_val, max_val));
1138 }
1139
1150 template <typename Key, typename Container>
1151 [[nodiscard]] auto stl_min_by(Key && key, const Container & c)
1152 {
1153 using T = typename Container::value_type;
1154
1155 auto it = c.begin();
1156 if (it == c.end())
1157 return std::optional<T>{};
1158
1159 auto & key_ref = key; // Preserve as lvalue to avoid moving in loop
1160 T min_elem = *it;
1161 auto min_key = key_ref(min_elem);
1162 ++it;
1163
1164 for (; it != c.end(); ++it)
1165 {
1166 auto k = key_ref(*it);
1167 if (k < min_key)
1168 {
1169 min_key = k;
1170 min_elem = *it;
1171 }
1172 }
1173 return std::optional<T>(min_elem);
1174 }
1175
1186 template <typename Key, typename Container>
1187 [[nodiscard]] auto stl_max_by(Key && key, const Container & c)
1188 {
1189 using T = typename Container::value_type;
1190
1191 auto it = c.begin();
1192 if (it == c.end())
1193 return std::optional<T>{};
1194
1195 auto & key_ref = key; // Preserve as lvalue to avoid moving in loop
1196 T max_elem = *it;
1197 auto max_key = key_ref(max_elem);
1198 ++it;
1199
1200 for (; it != c.end(); ++it)
1201 {
1202 auto k = key_ref(*it);
1203 if (k > max_key)
1204 {
1205 max_key = k;
1206 max_elem = *it;
1207 }
1208 }
1209 return std::optional<T>(max_elem);
1210 }
1211
1212 // ============================================================================
1213 // Sum and Product
1214 // ============================================================================
1215
1225 template <typename Container>
1226 [[nodiscard]] auto stl_sum(const Container & c)
1227 {
1228 using T = typename Container::value_type;
1229 T sum{};
1230 for (const auto & item: c)
1231 sum = sum + item;
1232 return sum;
1233 }
1234
1244 template <typename Container>
1245 [[nodiscard]] auto stl_product(const Container & c)
1246 {
1247 using T = typename Container::value_type;
1248 if (c.empty()) return T{};
1249
1250 auto it = c.begin();
1251 T prod = *it;
1252 ++it;
1253 for (; it != c.end(); ++it)
1254 prod = prod * (*it);
1255 return prod;
1256 }
1257
1258 // ============================================================================
1259 // Partitioning
1260 // ============================================================================
1261
1272 template <typename Pred, typename Container>
1274 {
1275 using T = typename Container::value_type;
1276
1277 std::vector<T> matching, non_matching;
1278 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
1279 for (const auto & item: c)
1280 if (pred_ref(item))
1281 matching.push_back(item);
1282 else
1283 non_matching.push_back(item);
1284 return std::make_pair(std::move(matching), std::move(non_matching));
1285 }
1286
1287 // ============================================================================
1288 // Zipping and Pairing
1289 // ============================================================================
1290
1301 template <typename Container1, typename Container2>
1303 {
1304 using T1 = typename Container1::value_type;
1305 using T2 = typename Container2::value_type;
1306
1307 std::vector<std::pair<T1, T2>> result;
1308 if constexpr (stl_detail::has_size_v<Container1> && stl_detail::has_size_v<Container2>)
1309 result.reserve(std::min(c1.size(), c2.size()));
1310 auto it1 = c1.begin();
1311 auto it2 = c2.begin();
1312 for (; it1 != c1.end() and it2 != c2.end(); ++it1, ++it2)
1313 result.emplace_back(*it1, *it2);
1314 return result;
1315 }
1316
1326 template <typename Container>
1328 {
1329 using PairType = typename Container::value_type;
1330 using T1 = std::decay_t<decltype(std::declval<PairType>().first)>;
1331 using T2 = std::decay_t<decltype(std::declval<PairType>().second)>;
1332
1333 std::vector<T1> v1;
1334 std::vector<T2> v2;
1337
1338 for (const auto & p: c)
1339 {
1340 v1.push_back(p.first);
1341 v2.push_back(p.second);
1342 }
1343 return std::make_pair(std::move(v1), std::move(v2));
1344 }
1345
1355 template <typename Container>
1357 {
1358 using T = typename Container::value_type;
1359
1360 std::vector<std::pair<size_t, T>> result;
1361 stl_detail::try_reserve(result, c);
1362 size_t i = 0;
1363 for (const auto & item: c)
1364 result.emplace_back(i++, item);
1365 return result;
1366 }
1367
1368 // ============================================================================
1369 // Comparison
1370 // ============================================================================
1371
1382 template <typename Container1, typename Container2>
1383 [[nodiscard]] bool stl_equal(const Container1 & c1, const Container2 & c2)
1384 {
1385 auto it1 = c1.begin();
1386 auto it2 = c2.begin();
1387 for (; it1 != c1.end() and it2 != c2.end(); ++it1, ++it2)
1388 if (not (*it1 == *it2))
1389 return false;
1390 return it1 == c1.end() and it2 == c2.end();
1391 }
1392
1403 template <typename Container1, typename Container2>
1405 {
1406 auto it1 = c1.begin();
1407 auto it2 = c2.begin();
1408
1409 for (; it1 != c1.end() and it2 != c2.end(); ++it1, ++it2)
1410 {
1411 if (*it1 < *it2) return -1;
1412 if (*it2 < *it1) return 1;
1413 }
1414
1415 if (it1 == c1.end() and it2 == c2.end()) return 0;
1416 return (it1 == c1.end()) ? -1 : 1;
1417 }
1418
1419 // ============================================================================
1420 // Reversing and Sorting
1421 // ============================================================================
1422
1432 template <typename Container>
1433 [[nodiscard]] auto stl_reverse(const Container & c)
1434 {
1435 using T = typename Container::value_type;
1436
1437 std::vector<T> result(c.begin(), c.end());
1438 std::reverse(result.begin(), result.end());
1439 return result;
1440 }
1441
1451 template <typename Container>
1452 [[nodiscard]] auto stl_sort(const Container & c)
1453 {
1454 using T = typename Container::value_type;
1455
1456 std::vector<T> result(c.begin(), c.end());
1457 sort_range(result);
1458 return result;
1459 }
1460
1471 template <typename Cmp, typename Container>
1472 [[nodiscard]] auto stl_sort_by(Cmp && cmp, const Container & c)
1473 {
1474 using T = typename Container::value_type;
1475
1476 std::vector<T> result(c.begin(), c.end());
1477 sort_range(result, std::forward<Cmp>(cmp));
1478 return result;
1479 }
1480
1481 // ============================================================================
1482 // Uniqueness
1483 // ============================================================================
1484
1494 template <typename Container>
1495 [[nodiscard]] auto stl_unique(const Container & c)
1496 {
1497 using T = typename Container::value_type;
1498
1499 std::vector<T> result;
1500 for (const auto & item: c)
1501 if (result.empty() or not (result.back() == item))
1502 result.push_back(item);
1503 return result;
1504 }
1505
1532 template <typename Container>
1534 {
1535 using T = typename Container::value_type;
1536
1537 std::vector<T> result;
1538 const size_t size = stl_detail::safe_size(c);
1539
1540 // Use linear search for small containers or if type is not hashable
1541 if constexpr (!stl_detail::is_std_hashable_v<T>)
1542 {
1543 // Linear search only (type not hashable)
1544 for (const auto & item : c)
1545 if (std::find(result.begin(), result.end(), item) == result.end())
1546 result.push_back(item);
1547 }
1549 {
1550 // Linear search for small containers (better cache, no hash overhead)
1551 for (const auto & item : c)
1552 if (std::find(result.begin(), result.end(), item) == result.end())
1553 result.push_back(item);
1554 }
1555 else
1556 {
1557 // Hash-based for large containers
1558 std::unordered_set<T> seen;
1559 seen.reserve(size);
1560 for (const auto & item : c)
1561 if (seen.insert(item).second)
1562 result.push_back(item);
1563 }
1564
1565 return result;
1566 }
1567
1568 // ============================================================================
1569 // Concatenation and Flattening
1570 // ============================================================================
1571
1582 template <typename Container1, typename Container2>
1583 [[nodiscard]] auto stl_concat(const Container1 & c1, const Container2 & c2)
1584 {
1585 using T = typename Container1::value_type;
1586
1587 std::vector<T> result;
1588 if constexpr (stl_detail::has_size_v<Container1> && stl_detail::has_size_v<Container2>)
1589 result.reserve(c1.size() + c2.size());
1590 for (const auto & item: c1)
1591 result.push_back(item);
1592 for (const auto & item: c2)
1593 result.push_back(item);
1594 return result;
1595 }
1596
1606 template <typename Container>
1607 [[nodiscard]] auto stl_flatten(const Container & c)
1608 {
1609 using InnerContainer = typename Container::value_type;
1610 using T = typename InnerContainer::value_type;
1611
1612 std::vector<T> result;
1613 for (const auto & inner: c)
1614 for (const auto & item: inner)
1615 result.push_back(item);
1616 return result;
1617 }
1618
1629 template <typename Op, typename Container>
1630 [[nodiscard]] auto stl_flat_map(Op && op, const Container & c)
1631 {
1632 using T = typename Container::value_type;
1633 using InnerContainer = std::decay_t<decltype(op(std::declval<T>()))>;
1634 using R = typename InnerContainer::value_type;
1635
1636 std::vector<R> result;
1637 auto & op_ref = op; // Preserve as lvalue to avoid moving in loop
1638 for (const auto & item: c)
1639 for (const auto & inner_item: op_ref(item))
1640 result.push_back(inner_item);
1641 return result;
1642 }
1643
1644 // ============================================================================
1645 // Grouping
1646 // ============================================================================
1647
1657 template <typename Container>
1658 [[nodiscard]] auto stl_group(const Container & c)
1659 {
1660 using T = typename Container::value_type;
1661
1662 std::vector<std::vector<T>> result;
1663 if (c.empty()) return result;
1664
1665 auto it = c.begin();
1666 result.emplace_back();
1667 result.back().push_back(*it);
1668 T current = *it;
1669 ++it;
1670
1671 for (; it != c.end(); ++it)
1672 {
1673 if (not (*it == current))
1674 {
1675 result.emplace_back();
1676 current = *it;
1677 }
1678 result.back().push_back(*it);
1679 }
1680 return result;
1681 }
1682
1712 template <typename Key, typename Container>
1713 [[nodiscard]] auto stl_group_by(Key && key, const Container & c)
1714 {
1715 using T = typename Container::value_type;
1716 using K = std::decay_t<decltype(key(std::declval<T>()))>;
1717
1718 std::vector<std::pair<K, std::vector<T>>> result;
1719 auto & key_ref = key; // Preserve as lvalue to avoid moving in loop
1720 const size_t size = stl_detail::safe_size(c);
1721
1722 // Use linear search for small containers or if key type is not hashable
1723 if constexpr (!stl_detail::is_std_hashable_v<K>)
1724 {
1725 // Linear search only (key type not hashable)
1726 for (const auto & item : c)
1727 {
1728 auto k = key_ref(item);
1729 auto it = std::find_if(result.begin(), result.end(),
1730 [&k](const auto & p) { return p.first == k; });
1731 if (it != result.end())
1732 it->second.push_back(item);
1733 else
1734 result.emplace_back(std::move(k), std::vector<T>{item});
1735 }
1736 }
1738 {
1739 // Linear search for small containers
1740 for (const auto & item : c)
1741 {
1742 auto k = key_ref(item);
1743 auto it = std::find_if(result.begin(), result.end(),
1744 [&k](const auto & p) { return p.first == k; });
1745 if (it != result.end())
1746 it->second.push_back(item);
1747 else
1748 result.emplace_back(std::move(k), std::vector<T>{item});
1749 }
1750 }
1751 else
1752 {
1753 // Hash-based for large containers
1754 std::unordered_map<K, size_t> key_to_index;
1755 key_to_index.reserve(size);
1756
1757 for (const auto & item : c)
1758 {
1759 auto k = key_ref(item);
1760 auto [it, inserted] = key_to_index.try_emplace(k, result.size());
1761 if (inserted)
1762 result.emplace_back(std::move(k), std::vector<T>{item});
1763 else
1764 result[it->second].second.push_back(item);
1765 }
1766 }
1767
1768 return result;
1769 }
1770
1771 // ============================================================================
1772 // Combinatorics: Permutations, Combinations, Arrangements
1773 // ============================================================================
1774
1775 namespace stl_comb_detail
1776 {
1777 template <typename T, typename Op>
1778 bool permutations_impl(std::vector<T> & arr, size_t start, Op & op_ref)
1779 {
1780 if (start >= arr.size())
1781 return op_ref(arr);
1782
1783 for (size_t i = start; i < arr.size(); ++i)
1784 {
1785 std::swap(arr[start], arr[i]);
1786 if (not permutations_impl(arr, start + 1, op_ref))
1787 {
1788 std::swap(arr[start], arr[i]);
1789 return false;
1790 }
1791 std::swap(arr[start], arr[i]);
1792 }
1793 return true;
1794 }
1795
1796 template <typename T, typename Op>
1797 bool combinations_impl(const std::vector<T> & arr, size_t k, size_t start,
1798 std::vector<T> & current, Op & op_ref)
1799 {
1800 if (current.size() == k)
1801 return op_ref(current);
1802
1803 for (size_t i = start; i <= arr.size() - (k - current.size()); ++i)
1804 {
1805 current.push_back(arr[i]);
1806 if (not combinations_impl(arr, k, i + 1, current, op_ref))
1807 {
1808 current.pop_back();
1809 return false;
1810 }
1811 current.pop_back();
1812 }
1813 return true;
1814 }
1815
1816 template <typename T, typename Op>
1817 bool arrangements_impl(const std::vector<T> & arr, size_t k,
1818 std::vector<T> & current, std::vector<bool> & used, Op & op_ref)
1819 {
1820 if (current.size() == k)
1821 return op_ref(current);
1822
1823 for (size_t i = 0; i < arr.size(); ++i)
1824 {
1825 if (used[i]) continue;
1826 used[i] = true;
1827 current.push_back(arr[i]);
1828 if (not arrangements_impl(arr, k, current, used, op_ref))
1829 {
1830 current.pop_back();
1831 used[i] = false;
1832 return false;
1833 }
1834 current.pop_back();
1835 used[i] = false;
1836 }
1837 return true;
1838 }
1839 } // namespace stl_comb_detail
1840
1864 template <typename Op, typename Container>
1865 bool stl_traverse_permutations(Op && op, const Container & c)
1866 {
1867 using T = typename Container::value_type;
1868 std::vector<T> arr(c.begin(), c.end());
1869 auto & op_ref = op; // Preserve as lvalue for recursive calls
1871 }
1872
1884 template <typename Container>
1886 {
1887 using T = typename Container::value_type;
1888 std::vector<std::vector<T>> result;
1889
1890 stl_traverse_permutations([&result](const std::vector<T> & p)
1891 {
1892 result.push_back(p);
1893 return true;
1894 }, c);
1895
1896 return result;
1897 }
1898
1923 template <typename Op, typename Container>
1924 bool stl_traverse_combinations(size_t k, Op && op, const Container & c)
1925 {
1926 using T = typename Container::value_type;
1927 std::vector<T> arr(c.begin(), c.end());
1928
1929 if (k > arr.size())
1930 return true;
1931
1932 std::vector<T> current;
1933 current.reserve(k);
1934 auto & op_ref = op; // Preserve as lvalue for recursive calls
1935 return stl_comb_detail::combinations_impl(arr, k, 0, current, op_ref);
1936 }
1937
1948 template <typename Container>
1949 [[nodiscard]] auto stl_combinations(size_t k, const Container & c)
1950 {
1951 using T = typename Container::value_type;
1952 std::vector<std::vector<T>> result;
1953
1954 stl_traverse_combinations(k, [&result](const std::vector<T> & combo)
1955 {
1956 result.push_back(combo);
1957 return true;
1958 }, c);
1959
1960 return result;
1961 }
1962
1987 template <typename Op, typename Container>
1988 bool stl_traverse_arrangements(size_t k, Op && op, const Container & c)
1989 {
1990 using T = typename Container::value_type;
1991 std::vector<T> arr(c.begin(), c.end());
1992
1993 if (k > arr.size())
1994 return true;
1995
1996 std::vector<T> current;
1997 current.reserve(k);
1998 std::vector<bool> used(arr.size(), false);
1999 auto & op_ref = op; // Preserve as lvalue for recursive calls
2000 return stl_comb_detail::arrangements_impl(arr, k, current, used, op_ref);
2001 }
2002
2013 template <typename Container>
2014 [[nodiscard]] auto stl_arrangements(size_t k, const Container & c)
2015 {
2016 using T = typename Container::value_type;
2017 std::vector<std::vector<T>> result;
2018
2019 stl_traverse_arrangements(k, [&result](const std::vector<T> & arr)
2020 {
2021 result.push_back(arr);
2022 return true;
2023 }, c);
2024
2025 return result;
2026 }
2027
2044 template <typename T>
2045 [[nodiscard]] auto stl_cartesian_product(const std::vector<std::vector<T>> & containers)
2046 {
2047 std::vector<std::vector<T>> result;
2048
2049 if (containers.empty())
2050 return result;
2051
2052 // Start with first container
2053 for (const auto & elem: containers[0])
2054 result.push_back({elem});
2055
2056 // Extend with each subsequent container
2057 for (size_t i = 1; i < containers.size(); ++i)
2058 {
2059 std::vector<std::vector<T>> new_result;
2060 for (const auto & partial: result)
2061 for (const auto & elem: containers[i])
2062 {
2063 auto extended = partial;
2064 extended.push_back(elem);
2065 new_result.push_back(std::move(extended));
2066 }
2067 result = std::move(new_result);
2068 }
2069
2070 return result;
2071 }
2072
2082 template <typename Container>
2083 [[nodiscard]] auto stl_power_set(const Container & c)
2084 {
2085 using T = typename Container::value_type;
2086 std::vector<T> arr(c.begin(), c.end());
2087 std::vector<std::vector<T>> result;
2088
2089 const size_t n = arr.size();
2090
2091 // Protect against overflow: 2^n overflows for n >= 64
2092 if (n >= 63)
2093 throw std::overflow_error("stl_power_set: container too large (n >= 63 would overflow)");
2094
2095 const size_t total = 1ULL << n; // 2^n
2096 result.reserve(total);
2097
2098 for (size_t mask = 0; mask < total; ++mask)
2099 {
2100 std::vector<T> subset;
2101 for (size_t i = 0; i < n; ++i)
2102 if (mask & (1ULL << i))
2103 subset.push_back(arr[i]);
2104 result.push_back(std::move(subset));
2105 }
2106
2107 return result;
2108 }
2109
2110 // ============================================================================
2111 // Additional Ruby/ML-style Operations
2112 // ============================================================================
2113
2130 template <typename Container>
2131 [[nodiscard]] auto stl_sliding_window(size_t n, const Container & c)
2132 {
2133 using T = typename Container::value_type;
2134 std::vector<std::vector<T>> result;
2135
2136 if (n == 0) return result;
2137
2138 std::vector<T> arr(c.begin(), c.end());
2139 if (arr.size() < n) return result;
2140
2141 for (size_t i = 0; i <= arr.size() - n; ++i)
2142 result.emplace_back(arr.begin() + i, arr.begin() + i + n);
2143
2144 return result;
2145 }
2146
2163 template <typename Container>
2164 [[nodiscard]] auto stl_chunks(size_t n, const Container & c)
2165 {
2166 using T = typename Container::value_type;
2167 std::vector<std::vector<T>> result;
2168
2169 if (n == 0) return result;
2170
2171 std::vector<T> arr(c.begin(), c.end());
2172
2173 for (size_t i = 0; i < arr.size(); i += n)
2174 {
2175 size_t end = std::min(i + n, arr.size());
2176 result.emplace_back(arr.begin() + i, arr.begin() + end);
2177 }
2178
2179 return result;
2180 }
2181
2198 template <typename T, typename Container>
2199 [[nodiscard]] auto stl_intersperse(const T & sep, const Container & c)
2200 {
2201 std::vector<T> result;
2202
2203 bool first = true;
2204 for (const auto & item: c)
2205 {
2206 if (not first)
2207 result.push_back(sep);
2208 result.push_back(item);
2209 first = false;
2210 }
2211
2212 return result;
2213 }
2214
2225 template <typename Container>
2226 [[nodiscard]] auto stl_split_at(size_t n, const Container & c)
2227 {
2228 using T = typename Container::value_type;
2229
2230 std::vector<T> first, second;
2231 size_t i = 0;
2232 for (const auto & item: c)
2233 {
2234 if (i < n)
2235 first.push_back(item);
2236 else
2237 second.push_back(item);
2238 ++i;
2239 }
2240
2241 return std::make_pair(std::move(first), std::move(second));
2242 }
2243
2256 template <typename Pred, typename Container>
2257 [[nodiscard]] auto stl_span(Pred && pred, const Container & c)
2258 {
2259 using T = typename Container::value_type;
2260
2261 std::vector<T> first, second;
2262 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
2263 bool taking = true;
2264
2265 for (const auto & item: c)
2266 if (taking and pred_ref(item))
2267 first.push_back(item);
2268 else
2269 {
2270 taking = false;
2271 second.push_back(item);
2272 }
2273
2274 return std::make_pair(std::move(first), std::move(second));
2275 }
2276
2286 template <typename Container>
2287 [[nodiscard]] auto stl_init(const Container & c)
2288 {
2289 using T = typename Container::value_type;
2290 std::vector<T> arr(c.begin(), c.end());
2291
2292 if (not arr.empty())
2293 arr.pop_back();
2294
2295 return arr;
2296 }
2297
2307 template <typename Container>
2308 [[nodiscard]] auto stl_tail(const Container & c)
2309 {
2310 using T = typename Container::value_type;
2311 std::vector<T> result;
2312
2313 bool first = true;
2314 for (const auto & item: c)
2315 {
2316 if (first)
2317 first = false;
2318 else
2319 result.push_back(item);
2320 }
2321
2322 return result;
2323 }
2324
2349 template <typename Container>
2350 [[nodiscard]] auto stl_tally(const Container & c)
2351 {
2352 using T = typename Container::value_type;
2353
2354 std::vector<std::pair<T, size_t>> result;
2355 const size_t size = stl_detail::safe_size(c);
2356
2357 // Use linear search for small containers or if type is not hashable
2358 if constexpr (!stl_detail::is_std_hashable_v<T>)
2359 {
2360 // Linear search only (type not hashable)
2361 for (const auto & item : c)
2362 {
2363 auto it = std::find_if(result.begin(), result.end(),
2364 [&item](const auto & p) { return p.first == item; });
2365 if (it != result.end())
2366 ++it->second;
2367 else
2368 result.emplace_back(item, 1);
2369 }
2370 }
2371 else if (size <= stl_detail::ADAPTIVE_THRESHOLD)
2372 {
2373 // Linear search for small containers
2374 for (const auto & item : c)
2375 {
2376 auto it = std::find_if(result.begin(), result.end(),
2377 [&item](const auto & p) { return p.first == item; });
2378 if (it != result.end())
2379 ++it->second;
2380 else
2381 result.emplace_back(item, 1);
2382 }
2383 }
2384 else
2385 {
2386 // Hash-based for large containers
2387 std::unordered_map<T, size_t> counts;
2388 counts.reserve(size);
2389 std::vector<T> order; // Track insertion order
2390 order.reserve(size);
2391
2392 for (const auto & item : c)
2393 {
2394 auto [it, inserted] = counts.try_emplace(item, 0);
2395 ++it->second;
2396 if (inserted)
2397 order.push_back(item);
2398 }
2399
2400 result.reserve(order.size());
2401 for (const auto & item : order)
2402 result.emplace_back(item, counts[item]);
2403 }
2404
2405 return result;
2406 }
2407
2418 template <typename Pred, typename Container>
2419 [[nodiscard]] auto stl_reject(Pred && pred, const Container & c)
2420 {
2421 using T = typename Container::value_type;
2422
2423 std::vector<T> result;
2424 auto & pred_ref = pred; // Preserve as lvalue to avoid moving in loop
2425 for (const auto & item: c)
2426 if (not pred_ref(item))
2427 result.push_back(item);
2428 return result;
2429 }
2430} // end namespace Aleph
2431
2432# endif // AH_STL_FUNCTIONAL_H
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
C++20 Ranges support and adaptors for Aleph-w containers.
size_t size_t int32_t value
Definition ca-c-api.h:116
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.
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_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
bool arrangements_impl(const std::vector< T > &arr, size_t k, std::vector< T > &current, std::vector< bool > &used, Op &op_ref)
bool permutations_impl(std::vector< T > &arr, size_t start, Op &op_ref)
bool combinations_impl(const std::vector< T > &arr, size_t k, size_t start, std::vector< T > &current, Op &op_ref)
constexpr size_t ADAPTIVE_THRESHOLD
Threshold for switching from linear to hash-based algorithms.
constexpr bool is_std_hashable_v
void try_reserve_n(Result &result, size_t n)
Helper to reserve with a specific size if the result supports it.
size_t safe_size(const Container &c)
Helper to get container size safely (returns 0 for containers without size())
void try_reserve(Result &result, const Container &c)
Helper to reserve if possible.
constexpr bool has_reverse_iterators_v
constexpr bool has_size_v
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
auto stl_first(const Container &c)
Get first element.
T stl_reduce(T init, Op &&op, const Container &c)
Alias for stl_foldl.
std::vector< T > stl_scan_left(T init, Op &&op, const Container &c)
Scan left - fold with all intermediate results.
bool stl_any(Pred &&pred, const Container &c)
Alias for stl_exists.
auto stl_span(Pred &&pred, const Container &c)
Split at predicate boundary (span in Haskell).
auto stl_take_last(size_t n, const Container &c)
Take last n elements.
auto stl_chunks(size_t n, const Container &c)
Split container into chunks of size n (each_slice in Ruby).
int stl_compare(const Container1 &c1, const Container2 &c2)
Compare two containers lexicographically.
auto stl_min_max(const Container &c)
Get both min and max in a single pass.
auto stl_last(const Container &c)
Get last element.
bool stl_traverse_arrangements(size_t k, Op &&op, const Container &c)
Traverse all k-arrangements (k-permutations) of a container.
auto stl_distinct(const Container &c)
Remove all duplicates (keeps first occurrence).
auto stl_max(const Container &c)
Get maximum element.
size_t size(Node *root) noexcept
void sort_range(Range &r, Cmp cmp)
Sort a whole range in place, portably across the ranges divide.
Definition ah-ranges.H:227
auto stl_flatten(const Container &c)
Flatten a container of containers.
auto stl_reject(Pred &&pred, const Container &c)
Filter out elements (reject in Ruby, opposite of filter).
auto stl_filter(Pred &&pred, const Container &c)
Filter elements satisfying predicate.
auto stl_arrangements(size_t k, const Container &c)
Generate all k-arrangements (k-permutations) of a container.
auto stl_drop(size_t n, const Container &c)
Drop first n elements, return the rest.
auto stl_enumerate_to_pairs(const Container &c)
Enumerate container (return pairs of index and element).
bool stl_equal(const Container1 &c1, const Container2 &c2)
Check equality of two containers.
auto stl_concat(const Container1 &c1, const Container2 &c2)
Concatenate two containers.
auto stl_combinations(size_t k, const Container &c)
Generate all k-combinations of a container.
auto stl_take_while(Pred &&pred, const Container &c)
Take elements while predicate is true.
auto stl_find_mapi(Op &&op, const Container &c)
Find and map with index (find_mapi in ML).
auto stl_nth(const size_t n, const Container &c)
Get n-th element.
auto stl_map(Op &&op, const Container &c)
Map operation - transform each element.
bool stl_mem(const T &target, const Container &c)
Check if element exists in container (mem in ML).
std::optional< size_t > stl_find_index(Pred &&pred, const Container &c)
Find index of first element satisfying predicate.
T stl_foldl(T init, Op &&op, const Container &c)
Left fold (foldl) - reduce from left to right.
bool all(Container &container, Operation &operation)
Return true if all elements satisfy a predicate.
auto stl_min_by(Key &&key, const Container &c)
Get minimum element by key function.
std::vector< T > stl_linspace(T start, T end, size_t n)
Generate n evenly spaced values between start and end.
and
Check uniqueness with explicit hash + equality functors.
bool stl_exists(Pred &&pred, const Container &c)
Check if any element satisfies predicate.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
auto stl_take(size_t n, const Container &c)
Take first n elements.
auto stl_generate(size_t n, Gen &&gen)
Generate a vector using a generator function.
std::vector< T > stl_range(T start, T end, T step=1)
Generate a range of values [start, end] with given step.
auto stl_init(const Container &c)
Get all elements except the last (init in Haskell).
bool stl_traverse_permutations(Op &&op, const Container &c)
Traverse all permutations of a container.
size_t stl_count_value(const T &target, const Container &c)
Count occurrences of a value.
auto stl_sort(const Container &c)
Return sorted copy of container.
auto stl_permutations(const Container &c)
Generate all permutations of a container.
auto stl_tally(const Container &c)
Count occurrences of each element (tally in Ruby, frequencies).
bool stl_all(Pred &&pred, const Container &c)
Check if all elements satisfy predicate.
auto stl_partition(Pred &&pred, const Container &c)
Partition elements by predicate.
auto stl_unique(const Container &c)
Remove consecutive duplicates.
auto stl_mapi(Op &&op, const Container &c)
Map with index (mapi in ML).
size_t stl_count(Pred &&pred, const Container &c)
Count elements satisfying predicate.
void stl_for_each_indexed(Op &&op, const Container &c)
Apply operation to each element with index.
auto stl_sum(const Container &c)
Sum all elements.
auto stl_sliding_window(size_t n, const Container &c)
Sliding window of size n over container (each_cons in Ruby).
auto stl_max_by(Key &&key, const Container &c)
Get maximum element by key function.
auto stl_group_by(Key &&key, const Container &c)
Group elements by key function.
auto stl_min(const Container &c)
Get minimum element.
bool stl_none(Pred &&pred, const Container &c)
Check if no element satisfies predicate.
auto stl_reverse(const Container &c)
Return reversed copy of container.
auto stl_flat_map(Op &&op, const Container &c)
Flat map - map then flatten.
std::vector< T > stl_rep(size_t n, const T &value)
Generate a vector of n repeated values.
bool stl_traverse_combinations(size_t k, Op &&op, const Container &c)
Traverse all k-combinations of a container.
T stl_foldr(T init, Op &&op, const Container &c)
Right fold (foldr) - reduce from right to left.
std::vector< T > stl_scan_right(T init, Op &&op, const Container &c)
Scan right - right fold with all intermediate results.
auto stl_unzip_pairs(const Container &c)
Unzip pairs into two vectors.
auto stl_drop_while(Pred &&pred, const Container &c)
Drop elements while predicate is true, return the rest.
auto stl_intersperse(const T &sep, const Container &c)
Insert element between each pair (intersperse in Haskell).
auto stl_cartesian_product(const std::vector< std::vector< T > > &containers)
Generate cartesian product of multiple containers.
auto stl_product(const Container &c)
Product of all elements.
auto stl_tail(const Container &c)
Get all elements except the first (tail in Haskell).
auto stl_filteri(Pred &&pred, const Container &c)
Filter with index (filteri in ML).
auto stl_find(Pred &&pred, const Container &c)
Find first element satisfying predicate.
void stl_for_each(Op &&op, const Container &c)
Apply operation to each element (for_each).
static std::atomic< bool > init
Definition hash-fct.C:54
auto stl_split_at(size_t n, const Container &c)
Split at position n, returning (take n, drop n) in one pass.
auto stl_sort_by(Cmp &&cmp, const Container &c)
Return sorted copy using custom comparator.
auto stl_power_set(const Container &c)
Generate power set (all subsets) of a container.
auto stl_group(const Container &c)
Group consecutive equal elements.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
auto stl_zip_to_pairs(const Container1 &c1, const Container2 &c2)
Zip two containers into pairs.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
auto stl_find_last(Pred &&pred, const Container &c)
Find last element satisfying predicate.
Detect if a container has reverse iterators.
Detect if a type has a size() method.
Detect if a type is hashable via std::hash.
static int * k