Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ahFunctional.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
32#ifndef AH_FUNCTIONAL_H
33#define AH_FUNCTIONAL_H
34
59# include <stdexcept>
60# include <utility>
61# include <tuple>
62# include <functional>
63# include <algorithm>
64# include <optional>
65# include <ah-errors.H>
66# include <ah-ranges.H>
67
68namespace Aleph
69{
73 template <typename T> struct Found_Item
74 {
75 virtual T & get_item() = 0;
76 virtual const T & get_item() const = 0;
77 virtual bool is_found() const noexcept = 0;
79 };
80
83 {
84 [[noreturn]] virtual T & get_item() override
85 {
86 ah_invalid_argument() << "Access from None type";
87 __builtin_unreachable(); // Satisfies compiler after throw
88 }
89
90 [[noreturn]] virtual const T & get_item() const override
91 {
92 ah_invalid_argument() << "Access from None type";
94 }
95
96 virtual bool is_found() const noexcept override { return false; }
97 };
98
100 template <typename T> struct Some : public Found_Item<T>
101 {
103
104 Some(T & i) : item(i) {}
105
106 virtual T & get_item() override { return item; }
107 virtual const T & get_item() const override { return item; }
108 virtual bool is_found() const noexcept override { return true; }
109 };
110
112 template <typename tgtT, typename srcT>
114 {
115 tgtT operator () (const srcT & item) const noexcept { return static_cast<tgtT>(item); }
116 };
117
119 template <typename TR, typename TD>
121 {
122 TR operator () (const TR & /*acc */, const TD & /* val */)
123 const noexcept { return TR(); }
124 };
125
126
127 template <typename T> class DynList;
128
138 template <typename T = int, template <typename> class Container = DynList>
139 [[nodiscard]] inline Container<T> range(const T start, const T end, const T step = 1)
140 {
142 for (T i = start; i <= end; i += step)
143 ret_val.append(i);
144 return ret_val;
145 }
146
157 template <typename T = int, template <typename> class Container = DynList>
158 [[nodiscard]] inline Container<T> nrange(const T start, const T end, const size_t n)
159 {
160 ah_domain_error_if(n == 0) << "nrange: n must be greater than 0";
161
163 if (n == 1)
164 {
165 ret_val.append(start);
166 return ret_val;
167 }
168
169 const auto step = static_cast<double>(end - start) / (n - 1);
170 for (size_t i = 0; i < n; ++i)
171 ret_val.append(static_cast<T>(start + i * step));
172
173 return ret_val;
174 }
175
187 template <typename T = int, template <typename> class Container = DynList,
188 class Op>
189 [[nodiscard]] inline auto set_range(const T start, const T end, const T step, Op & op)
190 -> Container<std::decay_t<decltype(op(start))>>
191 {
192 Container<std::decay_t<decltype(op(start))>> ret_val;
193 for (T i = start; i <= end; i += step)
194 ret_val.append(op(i));
195 return ret_val;
196 }
197
199 template <typename T = int, template <typename> class Container = DynList,
200 class Op>
201 [[nodiscard]] inline auto set_range(const T start, const T end,
202 const T step = 1, Op && op = Op())
203 -> Container<std::decay_t<decltype(op(start))>>
204 {
205 return set_range<T, Container, Op>(start, end, step, op);
206 }
207
227 template <typename T = int, template <typename> class Container = DynList>
228 [[nodiscard]] inline Container<T> contiguous_range(T start, const size_t n)
229 {
231 for (size_t i = 0; i < n; ++i)
232 ret_val.append(start++);
233 return ret_val;
234 }
235
236
244 template <typename T = int, template <typename> class Container = DynList>
245 [[nodiscard]] inline Container<T> range(const T n)
246 {
248 for (T i = 0; i < n; ++i)
249 ret_val.append(i);
250 return ret_val;
251 }
252
253
262 template <typename T = int> [[nodiscard]] inline
263 DynList<T> rep(size_t n, const T & item)
264 {
266 for (size_t i = 0; i < n; ++i)
267 ret_val.append(item);
268 return ret_val;
269 }
270
272 template <typename T = int> [[nodiscard]] inline
273 DynList<T> rep(size_t n, T && item = T())
274 {
275 return rep<T>(n, item);
276 }
277
300 template <class Container> [[nodiscard]]
302 {
304 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
305 ret.append(&it.get_curr());
306 return ret;
307 }
308
313 template <class Container> [[nodiscard]]
316 {
317 using T = const typename Container::Item_Type *;
319 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
320 ret.append(&it.get_curr());
321 return ret;
322 }
323
342 template <class Op>
343 void each(size_t start, size_t end, Op & op)
344 {
345 for (size_t i = start; i <= end; ++i)
346 op();
347 }
348
350 template <class Op>
351 void each(size_t start, size_t end, Op && op)
352 {
353 each(start, end, op);
354 }
355
357 template <class Op>
358 void each(size_t n, Op & op)
359 {
360 if (n == 0) return;
361 each(0, n - 1, op);
362 }
363
365 template <class Op>
366 void each(size_t n, Op && op)
367 {
368 each(n, op);
369 }
370
378 template <class Container> [[nodiscard]]
380 sublist(const Container & c, size_t pos, size_t stride)
381 {
383 try
384 {
385 for (auto it = c.get_it(pos); it.has_curr();
386 each(0, stride - 1, [&it] () { it.next(); }))
387 ret.append(it.get_curr());
388 }
389 catch (const std::overflow_error &) { /* end of container reached */ }
390
391 return ret;
392 }
393
395 template <class Container> [[nodiscard]]
397 sublist(const Container & c, size_t stride)
398 {
399 return sublist(c, 0, stride);
400 }
401
424 template <class Container, class Operation> inline
426 {
427 container.traverse([&operation] (const auto & item)
428 {
429 operation(item);
430 return true;
431 });
432 return container;
433 }
434
436 template <class Container, class Operation> inline
437 const Container & for_each(const Container & container, Operation & operation)
438 {
439 container.traverse([&operation] (const auto & item)
440 {
441 operation(item);
442 return true;
443 });
444 return container;
445 }
446
448 template <class Container, class Operation> inline
451 {
452 return for_each<Container, Operation>(container, operation);
453 }
454
456 template <class Container, class Operation> inline const Container &
457 for_each(const Container & container, Operation && operation = Operation())
458 {
459 return for_each<Container, Operation>(container, operation);
460 }
461
489 template <class Container, class Operation> inline
490 void enum_for_each(const Container & container, Operation & operation)
491 {
492 size_t i = 0;
493 for (auto it = container.get_it(); it.has_curr(); it.next_ne(), ++i)
494 operation(it.get_curr(), i);
495 }
496
498 template <class Container, class Operation> inline
499 void enum_for_each(const Container & container, Operation && operation)
500 {
501 enum_for_each(container, operation);
502 }
503
527 template <class Container, class Operation> inline
528 bool all(Container & container, Operation & operation)
529 {
530 return container.traverse(operation);
531 }
532
534 template <class Container, class Operation> inline
535 bool all(const Container & container, Operation & operation)
536 {
537 return container.template traverse<Operation>(operation);
538 }
539
541 template <class Container, class Operation> inline
542 bool all(Container & container, Operation && operation = Operation())
543 {
544 return all<Container, Operation>(container, operation);
545 }
546
548 template <class Container, class Operation> inline
549 bool all(const Container & container, Operation && operation = Operation())
550 {
551 return all<Container, Operation>(container, operation);
552 }
553
554
578 template <class Container, class Operation> inline
579 bool exists(Container & container, Operation & operation)
580 {
581 return not
582 container.traverse([&operation] (const auto & item)
583 {
584 return not operation(item);
585 });
586 }
587
589 template <class Container, class Operation> inline
590 bool exists(const Container & container, Operation & operation)
591 {
592 return not
593 container.traverse([&operation] (const auto & item)
594 {
595 return not operation(item);
596 });
597 }
598
600 template <class Container, class Operation> inline
601 bool exists(Container & container, Operation && operation = Operation())
602 {
603 return exists<Container, Operation>(container, operation);
604 }
605
607 template <class Container, class Operation> inline
608 bool exists(const Container & container, Operation && operation = Operation())
609 {
610 return exists<Container, Operation>(container, operation);
611 }
612
614 template <typename T>
616 {
617 bool operator () (const T &) const noexcept { return true; }
618 };
619
620
630 template <class Container1,
631 template <typename> class Container2 = Aleph::DynList,
635 {
637 container.
638 for_each([&ret_val, &operation] (const auto & item)
639 {
640 if (operation(item))
641 ret_val.append(item);
642 });
643 return ret_val;
644 }
645
647 template <class Container1,
648 template <typename> class Container2 = Aleph::DynList,
651 filter(const Container1 & container, Operation & operation)
652 {
654 container.for_each
655 ([&ret_val, &operation] (const auto & item)
656 {
657 if (operation(item))
658 ret_val.append(item);
659 });
660 return ret_val;
661 }
662
664 template <class Container1,
665 template <typename> class Container2 = Aleph::DynList,
669 {
671 }
672
673
675 template <class Container1,
676 template <typename> class Container2 = Aleph::DynList,
679 filter(const Container1 & container, Operation && operation)
680 {
682 }
683
692 template <typename T, class C, class Op>
693 [[nodiscard]] DynList<T> maps(const C & c, Op op)
694 {
696 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
697 ret.append(op(it.get_curr()));
698 return ret;
699 }
700
707 template < typename T, class Container, class Operation> [[nodiscard]] inline
708 T foldl(const Container & container, const T & init, Operation operation)
709 {
710#if ALEPH_HAS_RANGES
711 if constexpr (std::ranges::range<Container>)
712 return detail::ranges_fold_left(container, init, std::move(operation));
713 else
714#endif
715 {
716 T ret_val = init;
717 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
718 ret_val = operation(ret_val, it.get_curr());
719 return ret_val;
720 }
721 }
722
723
748 template <class Container1, class Container2> [[nodiscard]] inline
749 DynList<std::pair<typename Container1::Item_Type,
750 typename Container2::Item_Type>>
751 zip(const Container1 & a, const Container2 & b)
752 {
753 typedef typename Container1::Item_Type T1;
754 typedef typename Container2::Item_Type T2;
756
757 typename Container1::Iterator it1(a);
758 typename Container2::Iterator it2(b);
759 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
760 ret_val.append(std::pair<T1, T2>(it1.get_curr(), it2.get_curr()));
761
762 return ret_val;
763 }
764
791 template <class Container1, class Container2> [[nodiscard]] inline
792 DynList<std::tuple<typename Container1::Item_Type,
793 typename Container2::Item_Type>>
794 tzip(const Container1 & a, const Container2 & b)
795 {
796 typedef typename Container1::Item_Type T1;
797 typedef typename Container2::Item_Type T2;
798 using Tuple = std::tuple<T1, T2>;
800
801 typename Container1::Iterator it1(a);
802 typename Container2::Iterator it2(b);
803 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
804 ret_val.append(Tuple(it1.get_curr(), it2.get_curr()));
805
806 return ret_val;
807 }
808
835 template <class Container1, class Container2> [[nodiscard]] inline
836 DynList<std::pair<typename Container1::Item_Type,
837 typename Container2::Item_Type>>
838 zipEq(const Container1 & a, const Container2 & b)
839 {
840
841 typedef typename Container1::Item_Type T1;
842 typedef typename Container2::Item_Type T2;
844
845 auto it1 = a.get_it();
846 auto it2 = b.get_it();
847 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
848 ret_val.append(std::pair<T1, T2>(it1.get_curr(), it2.get_curr()));
849
850 if (it1.has_curr() or it2.has_curr())
851 ah_length_error() << "Container sizes mismatch";
852
853 return ret_val;
854 }
855
872 template <class Container1, class Container2> [[nodiscard]] inline
873 DynList<std::tuple<typename Container1::Item_Type,
874 typename Container2::Item_Type>>
875 tzipEq(const Container1 & a, const Container2 & b)
876 {
877 typedef typename Container1::Item_Type T1;
878 typedef typename Container2::Item_Type T2;
879 using Tuple = std::tuple<T1, T2>;
881
882 typename Container1::Iterator it1(a);
883 typename Container2::Iterator it2(b);
884 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
885 ret_val.append(Tuple(it1.get_curr(), it2.get_curr()));
886
887 if (it1.has_curr() or it2.has_curr())
888 ah_length_error() << "Container sizes mismatch";
889
890 return ret_val;
891 }
892
918 template <class Container> [[nodiscard]]
919 auto inline enumerate(const Container & c)
920 {
921 using Item = typename Container::Item_Type;
922 using Pair = std::pair<Item, size_t>;
924 size_t i = 0;
925 c.for_each([&i, &ret] (const Item & item) { ret.append(Pair(item, i++)); });
926 return ret;
927 }
928
929
958 template <class C1, class C2,
959 class Eq = std::equal_to<typename C1::Item_Type>> [[nodiscard]] inline
960 bool eq(const C1 & c1, const C2 & c2, Eq e = Eq())
961 {
962 auto it1 = c1.get_it();
963 auto it2 = c2.get_it();
964 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
965 if (not (e(it1.get_curr(), it2.get_curr())))
966 return false;
967
968 return not (it1.has_curr() or it2.has_curr());
969 }
970
972 template <typename T> [[nodiscard]] inline
973 bool operator == (const DynList<T> & l1, const DynList<T> & l2)
974 {
975 return eq(l1, l2);
976 }
977
979 template <class C1, class C2, class Eq> [[nodiscard]] inline
980 bool containers_eq(const C1 & c1, const C2 & c2, Eq e)
981 {
982 return eq(c1, c2, e);
983 }
984
1011 template <class C1, class C2,
1012 class Eq = std::equal_to<typename C1::Item_Type>> [[nodiscard]] inline
1013 std::tuple<bool, size_t, typename C1::Item_Type, typename C2::Item_Type>
1014 are_eq(const C1 & c1, const C2 & c2, Eq e = Eq())
1015 {
1016 using T = typename C1::Item_Type;
1017 auto it1 = c1.get_it();
1018 auto it2 = c2.get_it();
1019 size_t n = 0;
1020 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne(), n++)
1021 {
1022 auto & i1 = it1.get_curr();
1023 auto & i2 = it2.get_curr();
1024 if (not (e(i1, i2)))
1025 return std::make_tuple(false, n, i1, i2);
1026 }
1027
1028 return std::make_tuple(not (it1.has_curr() or it2.has_curr()), n, T(), T());
1029 }
1030
1057 template <class C1, class C2,
1058 class Cmp = std::less<typename C1::Item_Type>> [[nodiscard]] inline
1059 bool lesser(const C1 & c1, const C2 & c2, Cmp cmp = Cmp())
1060 {
1061 auto it1 = c1.get_it();
1062 auto it2 = c2.get_it();
1063 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
1064 {
1065 auto & curr1 = it1.get_curr();
1066 auto & curr2 = it2.get_curr();
1067 if (cmp(curr1, curr2))
1068 return true;
1069 else if (cmp(curr2, curr1))
1070 return false;
1071 }
1072
1073 if (not it1.has_curr() and not it2.has_curr())
1074 return false;
1075
1076 return it2.has_curr();
1077 }
1078
1095 template <class C1, class C2,
1096 class Eq = std::equal_to<typename C1::Item_Type>> [[nodiscard]] inline
1097 bool diff(const C1 & c1, const C2 & c2, Eq e = Eq())
1098 {
1099 return not eq(c1, c2, e);
1100 }
1101
1126 template <class Container> [[nodiscard]] inline
1127 auto unzip(const Container & l)
1128 {
1129 using T1 = std::decay_t<decltype(l.get_first().first)>;
1130 using T2 = std::decay_t<decltype(l.get_first().second)>;
1131 DynList<T1> l1;
1132 DynList<T2> l2;
1133 for (auto it = l.get_it(); it.has_curr(); it.next_ne())
1134 {
1135 auto & curr = it.get_curr();
1136 l1.append(curr.first);
1137 l2.append(curr.second);
1138 }
1139
1140 return std::make_pair(std::move(l1), std::move(l2));
1141 }
1142
1169 template <template <typename> class Container, typename T1, typename T2>
1170 [[nodiscard]] inline std::tuple<Container<T1>, Container<T2>>
1171 tunzip(const Container<std::tuple<T1, T2>> & l)
1172 {
1173 Container<T1> l1;
1174 Container<T2> l2;
1175 for (auto it = l.get_it(); it.has_curr(); it.next_ne())
1176 {
1177 auto & curr = it.get_curr();
1178 l1.append(std::get<0>(curr));
1179 l2.append(std::get<1>(curr));
1180 }
1181
1182 return std::make_tuple(std::move(l1), std::move(l2));
1183 }
1184
1185
1192 template <class SrcContainer,
1193 template <typename> class TgtContainer = Aleph::DynList>
1194 [[nodiscard]] inline std::pair<TgtContainer<typename SrcContainer::Item_Type>,
1196 (const SrcContainer & c,
1197 std::function<bool(const typename SrcContainer::Item_Type &)> operation)
1198 {
1199 typedef typename SrcContainer::Item_Type Type;
1200 typedef std::pair<TgtContainer<Type>, TgtContainer<Type>> Pair;
1201
1202 Pair ret_val;
1203 for_each(c, [&ret_val, &operation] (const Type & item)
1204 {
1205 if (operation(item))
1206 ret_val.first.append(item);
1207 else
1208 ret_val.second.append(item);
1209 });
1210 return ret_val;
1211 }
1212
1214 template <class Container> [[nodiscard]] inline
1217 {
1218 using T = typename Container::Key_Type;
1219 using Pair = std::pair<size_t, T>;
1220 size_t i = 0;
1221
1222 return c.Container:: template maps<Pair>([&i] (const T & d)
1223 { return Pair(i++, d); });
1224 }
1225
1226
1228 template <class Container> [[nodiscard]] inline
1231 {
1232 using T = typename Container::Key_Type;
1233 using Tuple = std::tuple<size_t, typename Container::Key_Type>;
1234 size_t i = 0;
1235 return c.Container::template maps<std::tuple<size_t, T>>([&i] (const T & d)
1236 {
1237 return Tuple(i++, d);
1238 });
1239 }
1240
1241
1262 template <typename T, template <typename> class Container>
1264 {
1266 l.for_each([&ret_val] (const T & item)
1267 {
1268 ret_val.insert(item);
1269 });
1270 return ret_val;
1271 }
1272
1294 template <class Container> [[nodiscard]]
1295 auto gen_seq_list_tuples(const Container & c, size_t n)
1296 {
1297 using T = typename Container::Item_Type;
1298 typename Container::Iterator it(c);
1299 DynList<T> l;
1300 for (size_t i = 0; i < n; ++i, it.next())
1301 l.append(it.get_curr());
1302
1304 ret.append(l);
1305 for (; it.has_curr(); it.next_ne())
1306 {
1307 l.remove_first();
1308 l.append(it.get_curr());
1309 ret.append(l);
1310 }
1311
1312 return ret;
1313 }
1314
1340 template <typename T, template <typename> class Container, class Equal>
1341 [[nodiscard]] std::pair<DynList<DynList<T>>, size_t>
1343 {
1344 using P = std::pair<DynList<DynList<T>>, size_t>;
1345 if (c.is_empty())
1346 return P(DynList<DynList<T> >(), 0);
1347
1348 DynList<DynList<T>> ret; // this will be the result
1349
1350 DynList<T> * group = &ret.append(DynList<T>()); // creates a first group
1351
1352 auto it = c.get_it(); // put the firstitem into the group
1353 auto curr_item = it.get_curr();
1355
1356 size_t count = 1; // count the number of groups
1357
1358 for (it.next(); it.has_curr(); it.next_ne())
1359 {
1360 auto & curr = it.get_curr();
1361 if (not eq(curr, curr_item)) // group change?
1362 {
1363 curr_item = curr;
1364 group = &ret.append(DynList<T>()); // create new group and insert it
1365 ++count; // increase the number of groups
1366 }
1367
1368 group->append(curr);
1369 }
1370
1371 return P(ret, count);
1372 }
1373
1375 template <typename T, template <typename> class Container,
1376 class Equal = std::equal_to<T>>
1377 [[nodiscard]] std::pair<DynList<DynList<T>>, size_t>
1378 sequential_groups(const Container<T> & c, Equal && eq = Equal())
1379 {
1380 return sequential_groups(c, eq);
1381 }
1382
1410 template <typename T, template <typename> class Container, class Equal>
1411 [[nodiscard]] std::pair<DynList<T>, size_t>
1413 {
1414 using P = std::pair<DynList<T>, size_t>;
1415 if (c.is_empty())
1416 return P(DynList<T>(), 0);
1417
1419
1420 auto it = c.get_it(); // put the first item
1421 auto curr_item = it.get_curr();
1423
1424 size_t count = 1; // count the number of groups
1425
1426 for (it.next(); it.has_curr(); it.next_ne())
1427 {
1428 auto & curr = it.get_curr();
1429 if (not eq(curr, curr_item)) // group change?
1430 {
1431 curr_item = curr;
1433 ++count; // increase the number of groups
1434 }
1435 }
1436
1437 return P(ret, count);
1438 }
1439
1441 template <typename T, template <typename> class Container,
1442 class Equal = std::equal_to<T>>
1443 [[nodiscard]] std::pair<DynList<T>, size_t>
1444 unique_sequential(const Container<T> & c, Equal && eq = Equal())
1445 {
1446 return unique_sequential(c, eq);
1447 }
1448
1473 template <class Itor1, class Itor2 = Itor1>
1475 {
1476 Itor1 it1;
1477 Itor2 it2;
1478
1479 public:
1480
1482 Pair_Iterator(Itor1 i1, Itor2 i2) : it1(i1), it2(i2) {}
1483
1488 template <class C1, class C2>
1489 Pair_Iterator(const C1 & c1, const C2 & c2)
1490 : Pair_Iterator(c1.get_it(), c2.get_it()) {}
1491
1495 bool has_curr() const noexcept { return it1.has_curr() and it2.has_curr(); }
1496
1498 bool has_curr1() const noexcept { return it1.has_curr(); }
1499
1501 bool has_curr2() const noexcept { return it2.has_curr(); }
1502
1507 auto get_curr() const
1508 {
1509 return std::make_pair(it1.get_curr(), it2.get_curr());
1510 }
1511
1516 auto get_curr_ne() const noexcept
1517 {
1518 return std::make_pair(it1.get_curr_ne(), it2.get_curr_ne());
1519 }
1520
1524 void next()
1525 {
1526 it1.next();
1527 it2.next();
1528 }
1529
1533 void next_ne() noexcept
1534 {
1535 it1.next_ne();
1536 it2.next_ne();
1537 }
1538
1543 bool was_traversed() const noexcept
1544 {
1545 return not (it1.has_curr() or it2.has_curr());
1546 }
1547 };
1548
1563 template <class C1, class C2>
1565 get_pair_it(const C1 & c1, const C2 & c2)
1566 {
1567 using I1 = typename C1::Iterator;
1568 using I2 = typename C2::Iterator;
1569 I1 i1(c1);
1570 I2 i2(c2);
1571 return Pair_Iterator<I1, I2>(i1, i2);
1572 }
1573
1575 template <class C1, class C2>
1577 get_pair_it(const C1 & c1, const C2 & c2, size_t pos)
1578 {
1579 using I1 = typename C1::Iterator;
1580 using I2 = typename C2::Iterator;
1581 I1 i1(c1);
1582 I2 i2(c2);
1583 for (size_t i = 0; i < pos; ++i)
1584 {
1585 i1.next();
1586 i2.next();
1587 }
1588 return Pair_Iterator<I1, I2>(i1, i2);
1589 }
1590
1592 template <class C> inline void insert_in_container(C &, size_t&) {}
1593
1594 template <class C, typename T, typename ... Args> inline
1595 void insert_in_container(C & c, size_t & n, const T & item, Args & ... args)
1596 {
1597 c.insert(item);
1598 ++n;
1599 insert_in_container(c, n, args...);
1600 }
1602
1606 template <class C, typename ... Args> inline
1607 size_t insert_in_container(C & c, Args ... args)
1608 {
1609 size_t n = 0;
1610 insert_in_container(c, n, args...);
1611 return n;
1612 }
1613
1615 template <class C> inline void append_in_container(C &, size_t&) {}
1616
1617 template <class C, typename T, typename ... Args> inline
1618 void append_in_container(C & c, size_t & n, const T & item, Args & ... args)
1619 {
1620 c.append(item);
1621 ++n;
1622 append_in_container(c, n, args...);
1623 }
1625
1629 template <class C, typename ... Args> inline
1630 size_t append_in_container(C & c, Args ... args)
1631 {
1632 size_t n = 0;
1633 append_in_container(c, n, args...);
1634 return n;
1635 }
1636
1638 template <class C, typename ... Args>
1640 {
1641 C c;
1643 return c;
1644 }
1645
1647 template <class SrcC, class TgtC>
1649 {
1650 TgtC ret;
1651 for (auto it = srcc.get_it(); it.has_curr(); it.next_ne())
1652 ret.append(it.get_curr());
1653
1654 return ret;
1655 }
1656
1658 template <typename T, typename ... Args>
1663
1665 template <class C> inline void remove_from_container(C &, size_t&) {}
1666
1667 template <class C, typename T, typename ... Args> inline
1668 void remove_from_container(C & c, size_t & n, const T & item, Args & ... args)
1669 {
1670 c.remove(item);
1671 ++n;
1672 remove_from_container(c, n, args...);
1673 }
1675
1679 template <class C, typename ... Args> inline
1681 {
1682 size_t n = 0;
1683 remove_from_container(c, n, args...);
1684 return n;
1685 }
1686
1687 // These function are defined in tpl_dynSetHash.H
1688
1689 // union
1690 template <typename T, template <typename> class Container> [[nodiscard]] inline
1691 DynList<T> join(const Container<T> & c1, const Container<T> & c2);
1692
1693 template <typename T, template <typename> class Container> [[nodiscard]] inline
1694 DynList<T> intercept(const Container<T> & c1, const Container<T> & c2);
1695
1696 template <typename T, template <typename> class Container> [[nodiscard]] inline
1697 DynList<T> unique(const Container<T> & c);
1698
1699 template <typename T, template <typename> class Container> [[nodiscard]] inline
1700 DynList<T> repeated(const Container<T> & c);
1701
1702 template <typename T, template <typename> class Container> [[nodiscard]] inline
1704
1725 template <typename T,
1726 template <typename> class C1,
1727 template <typename> class C2>
1729 {
1731 for (auto it_c = c.get_it(); it_c.has_curr(); it_c.next_ne())
1732 {
1733 const auto & curr_c = it_c.get_curr();
1734 for (auto it = curr_c.get_it(); it.has_curr(); it.next_ne())
1735 ret.append(it.get_curr());
1736 }
1737 return ret;
1738 }
1739
1751 template <typename T,
1752 template <typename> class C1,
1753 template <typename> class C2,
1754 template <typename> class C3>
1756 {
1758 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
1759 ret.append(flatten(it.get_curr()));
1760 return ret;
1761 }
1762
1774 template <typename T,
1775 template <typename> class C1,
1776 template <typename> class C2,
1777 template <typename> class C3,
1778 template <typename> class C4>
1780 {
1782 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
1783 ret.append(flatten(it.get_curr()));
1784 return ret;
1785 }
1786
1798 template <typename T,
1799 template <typename> class C1,
1800 template <typename> class C2,
1801 template <typename> class C3,
1802 template <typename> class C4,
1803 template <typename> class C5>
1805 {
1807 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
1808 ret.append(flatten(it.get_curr()));
1809 return ret;
1810 }
1811
1831 template <typename T> [[nodiscard]] inline
1832 bool is_inside(const T & val, const DynList<T> & values)
1833 {
1834 for (const auto & v : values)
1835 if (val == v)
1836 return true;
1837 return false;
1838 }
1839
1857 template <typename T> [[nodiscard]] inline
1858 bool is_equal(const T & val)
1859 {
1860 (void) val;
1861 return false;
1862 }
1863
1870 template <typename T, typename U, typename ... Args> [[nodiscard]] inline
1871 bool is_equal(const T & val, const U & rhs, const Args & ... args)
1872 {
1873 return (val == rhs) or is_equal(val, args...);
1874 }
1875
1882 template <class Container, class Operation> [[nodiscard]] inline
1883 bool none(const Container & container, Operation & operation)
1884 {
1885 return not exists(container, operation);
1886 }
1887
1889 template <class Container, class Operation> [[nodiscard]] inline
1890 bool none(const Container & container, Operation && operation = Operation())
1891 {
1892 return none<Container, Operation>(container, operation);
1893 }
1894
1922 template <class Container, class Pred> [[nodiscard]] inline
1923 typename Container::Item_Type *
1924 find_ptr(Container & container, Pred & pred)
1925 {
1926 typename Container::Item_Type * result = nullptr;
1927 container.traverse([&result, &pred] (auto & item)
1928 {
1929 if (pred(item))
1930 {
1931 result = &item;
1932 return false;
1933 }
1934 return true;
1935 });
1936 return result;
1937 }
1938
1940 template <class Container, class Pred> [[nodiscard]] inline
1941 const typename Container::Item_Type *
1942 find_ptr(const Container & container, Pred & pred)
1943 {
1944 const typename Container::Item_Type * result = nullptr;
1945 container.traverse([&result, &pred] (const auto & item)
1946 {
1947 if (pred(item))
1948 {
1949 result = &item;
1950 return false;
1951 }
1952 return true;
1953 });
1954 return result;
1955 }
1956
1958 template <class Container, class Pred> [[nodiscard]] inline
1959 typename Container::Item_Type *
1960 find_ptr(Container & container, Pred && pred)
1961 {
1962 return find_ptr<Container, Pred>(container, pred);
1963 }
1964
1966 template <class Container, class Pred> [[nodiscard]] inline
1967 const typename Container::Item_Type *
1968 find_ptr(const Container & container, Pred && pred)
1969 {
1970 return find_ptr<Container, Pred>(container, pred);
1971 }
1972
1995 template <class Container, class Pred> [[nodiscard]] inline
1996 std::optional<typename Container::Item_Type>
1997 find_opt(const Container & container, Pred & pred)
1998 {
1999 std::optional<typename Container::Item_Type> result;
2000 container.traverse([&result, &pred] (const auto & item)
2001 {
2002 if (pred(item))
2003 {
2004 result = item;
2005 return false;
2006 }
2007 return true;
2008 });
2009 return result;
2010 }
2011
2013 template <class Container, class Pred> [[nodiscard]] inline
2014 std::optional<typename Container::Item_Type>
2015 find_opt(const Container & container, Pred && pred)
2016 {
2017 return find_opt<Container, Pred>(container, pred);
2018 }
2019
2029 template <typename T, class Container, class Operation> [[nodiscard]] inline
2030 T foldr(const Container & container, const T & init, Operation operation)
2031 {
2033 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2034 reversed.insert(it.get_curr());
2035
2036 T ret_val = init;
2037 for (auto it = reversed.get_it(); it.has_curr(); it.next_ne())
2038 ret_val = operation(it.get_curr(), ret_val);
2039 return ret_val;
2040 }
2041
2049 template <class Container, typename T = typename Container::Item_Type>
2050 [[nodiscard]] inline T sum(const Container & container, const T & init = T{})
2051 {
2052#if ALEPH_HAS_RANGES
2053 if constexpr (std::ranges::range<Container>)
2054 return detail::ranges_fold_left(container, init, std::plus<>{});
2055 else
2056#endif
2057 {
2058 T result = init;
2059 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2060 result = result + it.get_curr();
2061 return result;
2062 }
2063 }
2064
2072 template <class Container, typename T = typename Container::Item_Type>
2073 [[nodiscard]] inline T product(const Container & container, const T & init = T{1})
2074 {
2075#if ALEPH_HAS_RANGES
2076 if constexpr (std::ranges::range<Container>)
2077 return detail::ranges_fold_left(container, init, std::multiplies<>{});
2078 else
2079#endif
2080 {
2081 T result = init;
2082 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2083 result = result * it.get_curr();
2084 return result;
2085 }
2086 }
2087
2095 template <class C1, class C2> [[nodiscard]] inline
2097 concat(const C1 & c1, const C2 & c2)
2098 {
2100 for (auto it = c1.get_it(); it.has_curr(); it.next_ne())
2101 result.append(it.get_curr());
2102 for (auto it = c2.get_it(); it.has_curr(); it.next_ne())
2103 result.append(it.get_curr());
2104 return result;
2105 }
2106
2114 template <class Container, class Pred> [[nodiscard]] inline
2117 {
2119 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
2120 {
2121 const auto & item = it.get_curr();
2122 if (not pred(item))
2123 break;
2124 result.append(item);
2125 }
2126 return result;
2127 }
2128
2136 template <class Container, class Pred> [[nodiscard]] inline
2139 {
2141 bool dropping = true;
2142 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
2143 {
2144 const auto & item = it.get_curr();
2145 if (dropping and pred(item))
2146 continue;
2147 dropping = false;
2148 result.append(item);
2149 }
2150 return result;
2151 }
2152
2162 template <class Container, class Op> [[nodiscard]] inline
2163 auto flat_map(const Container & container, Op op)
2165 {
2166 using ResultItemType = typename std::decay_t<decltype(op(std::declval<typename Container::Item_Type>()))>::Item_Type;
2168 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2169 {
2170 auto sub = op(it.get_curr());
2171 for (auto sit = sub.get_it(); sit.has_curr(); sit.next_ne())
2172 result.append(sit.get_curr());
2173 }
2174 return result;
2175 }
2176
2186 template <typename T, class Container> [[nodiscard]] inline
2187 DynList<T> scanl_sum(const Container & container, const T & init)
2188 {
2189 DynList<T> result;
2190 T acc = init;
2191 result.append(acc);
2192 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2193 {
2194 acc = acc + it.get_curr();
2195 result.append(acc);
2196 }
2197 return result;
2198 }
2199
2210 template <typename T, class Container, class Op> [[nodiscard]] inline
2211 DynList<T> scanl(const Container & container, const T & init, Op op)
2212 {
2213 DynList<T> result;
2214 T acc = init;
2215 result.append(acc);
2216 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2217 {
2218 acc = op(acc, it.get_curr());
2219 result.append(acc);
2220 }
2221 return result;
2222 }
2223
2231 template <class Container,
2232 class Cmp = std::less<typename Container::Item_Type>>
2233 [[nodiscard]] inline const typename Container::Item_Type *
2234 min_ptr(const Container & container, Cmp cmp = Cmp())
2235 {
2236 auto it = container.get_it();
2237 if (not it.has_curr())
2238 return nullptr;
2239
2240 const typename Container::Item_Type * min_elem = &it.get_curr();
2241 for (it.next_ne(); it.has_curr(); it.next_ne())
2242 {
2243 const auto & curr = it.get_curr();
2244 if (cmp(curr, *min_elem))
2245 min_elem = &curr;
2246 }
2247 return min_elem;
2248 }
2249
2257 template <class Container,
2258 class Cmp = std::less<typename Container::Item_Type>>
2259 [[nodiscard]] inline const typename Container::Item_Type *
2260 max_ptr(const Container & container, Cmp cmp = Cmp())
2261 {
2262 auto it = container.get_it();
2263 if (not it.has_curr())
2264 return nullptr;
2265
2266 const typename Container::Item_Type * max_elem = &it.get_curr();
2267 for (it.next_ne(); it.has_curr(); it.next_ne())
2268 {
2269 const auto & curr = it.get_curr();
2270 if (cmp(*max_elem, curr))
2271 max_elem = &curr;
2272 }
2273 return max_elem;
2274 }
2275
2283 template <class Container,
2284 class Cmp = std::less<typename Container::Item_Type>>
2285 [[nodiscard]] inline std::pair<const typename Container::Item_Type *,
2286 const typename Container::Item_Type *>
2287 minmax_ptr(const Container & container, Cmp cmp = Cmp())
2288 {
2289 using T = typename Container::Item_Type;
2290 auto it = container.get_it();
2291 if (not it.has_curr())
2292 return {nullptr, nullptr};
2293
2294 const T * min_elem = &it.get_curr();
2295 const T * max_elem = min_elem;
2296 for (it.next_ne(); it.has_curr(); it.next_ne())
2297 {
2298 const auto & curr = it.get_curr();
2299 if (cmp(curr, *min_elem))
2300 min_elem = &curr;
2301 if (cmp(*max_elem, curr))
2302 max_elem = &curr;
2303 }
2304 return {min_elem, max_elem};
2305 }
2306
2314 template <class Container, class Pred> [[nodiscard]] inline
2315 size_t count_if(const Container & container, Pred pred)
2316 {
2317 size_t count = 0;
2318 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2319 if (pred(it.get_curr()))
2320 ++count;
2321 return count;
2322 }
2323
2331 template <class Container> [[nodiscard]] inline
2332 bool contains(const Container & container,
2333 const typename Container::Item_Type & value)
2334 {
2335 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2336 if (it.get_curr() == value)
2337 return true;
2338 return false;
2339 }
2340
2349 template <class Container> [[nodiscard]] inline
2351 enumerate_tuple(const Container & container)
2352 {
2353 using T = typename Container::Item_Type;
2354 using Tuple = std::tuple<size_t, T>;
2355 DynList<Tuple> result;
2356 size_t i = 0;
2357 for (auto it = container.get_it(); it.has_curr(); it.next_ne(), ++i)
2358 result.append(Tuple(i, it.get_curr()));
2359 return result;
2360 }
2361
2362
2397 template <class Container1, class Container2> [[nodiscard]] inline
2398 DynList<std::pair<typename Container1::Item_Type,
2399 typename Container2::Item_Type>>
2400 zip_longest(const Container1 & a, const Container2 & b,
2401 const typename Container1::Item_Type & fill_a = typename Container1::Item_Type(),
2402 const typename Container2::Item_Type & fill_b = typename Container2::Item_Type())
2403 {
2404 using T1 = typename Container1::Item_Type;
2405 using T2 = typename Container2::Item_Type;
2407
2408 auto it1 = a.get_it();
2409 auto it2 = b.get_it();
2410
2411 // Process while both have elements
2412 while (it1.has_curr() and it2.has_curr())
2413 {
2414 ret_val.append(std::pair<T1, T2>(it1.get_curr(), it2.get_curr()));
2415 it1.next_ne();
2416 it2.next_ne();
2417 }
2418
2419 // Process remaining elements from first container
2420 while (it1.has_curr())
2421 {
2422 ret_val.append(std::pair<T1, T2>(it1.get_curr(), fill_b));
2423 it1.next_ne();
2424 }
2425
2426 // Process remaining elements from second container
2427 while (it2.has_curr())
2428 {
2429 ret_val.append(std::pair<T1, T2>(fill_a, it2.get_curr()));
2430 it2.next_ne();
2431 }
2432
2433 return ret_val;
2434 }
2435
2436
2468 template <class Container1, class Container2> [[nodiscard]] inline
2469 DynList<std::tuple<typename Container1::Item_Type,
2470 typename Container2::Item_Type>>
2471 tzip_longest(const Container1 & a, const Container2 & b,
2472 const typename Container1::Item_Type & fill_a = typename Container1::Item_Type(),
2473 const typename Container2::Item_Type & fill_b = typename Container2::Item_Type())
2474 {
2475 using T1 = typename Container1::Item_Type;
2476 using T2 = typename Container2::Item_Type;
2477 using Tuple = std::tuple<T1, T2>;
2479
2480 auto it1 = a.get_it();
2481 auto it2 = b.get_it();
2482
2483 while (it1.has_curr() and it2.has_curr())
2484 {
2485 ret_val.append(Tuple(it1.get_curr(), it2.get_curr()));
2486 it1.next_ne();
2487 it2.next_ne();
2488 }
2489
2490 while (it1.has_curr())
2491 {
2492 ret_val.append(Tuple(it1.get_curr(), fill_b));
2493 it1.next_ne();
2494 }
2495
2496 while (it2.has_curr())
2497 {
2498 ret_val.append(Tuple(fill_a, it2.get_curr()));
2499 it2.next_ne();
2500 }
2501
2502 return ret_val;
2503 }
2504
2505
2541 template <class Container1, class Container2> [[nodiscard]] inline
2543 std::optional<typename Container2::Item_Type>>>
2545 {
2546 using T1 = typename Container1::Item_Type;
2547 using T2 = typename Container2::Item_Type;
2548 using Opt1 = std::optional<T1>;
2549 using Opt2 = std::optional<T2>;
2551
2552 auto it1 = a.get_it();
2553 auto it2 = b.get_it();
2554
2555 while (it1.has_curr() and it2.has_curr())
2556 {
2557 ret_val.append(std::make_pair(Opt1(it1.get_curr()), Opt2(it2.get_curr())));
2558 it1.next_ne();
2559 it2.next_ne();
2560 }
2561
2562 while (it1.has_curr())
2563 {
2564 ret_val.append(std::make_pair(Opt1(it1.get_curr()), std::nullopt));
2565 it1.next_ne();
2566 }
2567
2568 while (it2.has_curr())
2569 {
2570 ret_val.append(std::make_pair(std::nullopt, Opt2(it2.get_curr())));
2571 it2.next_ne();
2572 }
2573
2574 return ret_val;
2575 }
2576
2577
2626 template <typename T, template <typename> class Container, class KeyFunc>
2627 [[nodiscard]]
2630 {
2631 using Key = std::invoke_result_t<KeyFunc, const T&>;
2632 using Group = DynList<T>;
2633 using Result = DynList<std::pair<Key, Group>>;
2634
2635 Result ret;
2636 if (c.is_empty())
2637 return ret;
2638
2639 auto it = c.get_it();
2640 Key curr_key = key_func(it.get_curr());
2641 Group * curr_group = &ret.append(std::make_pair(curr_key, Group())).second;
2642 curr_group->append(it.get_curr());
2643
2644 for (it.next_ne(); it.has_curr(); it.next_ne())
2645 {
2646 const auto & item = it.get_curr();
2647 Key new_key = key_func(item);
2648
2649 if (new_key != curr_key)
2650 {
2651 curr_key = new_key;
2652 curr_group = &ret.append(std::make_pair(curr_key, Group())).second;
2653 }
2654
2655 curr_group->append(item);
2656 }
2657
2658 return ret;
2659 }
2660
2661
2693 template <typename T, template <typename> class Container,
2694 class KeyFunc, class KeyEqual>
2695 [[nodiscard]]
2698 {
2699 using Key = std::invoke_result_t<KeyFunc, const T&>;
2700 using Group = DynList<T>;
2701 using Result = DynList<std::pair<Key, Group>>;
2702
2703 Result ret;
2704 if (c.is_empty())
2705 return ret;
2706
2707 auto it = c.get_it();
2708 Key curr_key = key_func(it.get_curr());
2709 Group * curr_group = &ret.append(std::make_pair(curr_key, Group())).second;
2710 curr_group->append(it.get_curr());
2711
2712 for (it.next_ne(); it.has_curr(); it.next_ne())
2713 {
2714 const auto & item = it.get_curr();
2715 Key new_key = key_func(item);
2716
2718 {
2719 curr_key = new_key;
2720 curr_group = &ret.append(std::make_pair(curr_key, Group())).second;
2721 }
2722
2723 curr_group->append(item);
2724 }
2725
2726 return ret;
2727 }
2728
2729
2767 template <typename T, template <typename> class Container,
2768 class KeyFunc, class Reducer>
2769 [[nodiscard]]
2772 std::invoke_result_t<Reducer, const DynList<T>&>>>
2773 {
2774 using Key = std::invoke_result_t<KeyFunc, const T&>;
2775 using ReducedType = std::invoke_result_t<Reducer, const DynList<T>&>;
2777
2778 auto groups = group_by(c, key_func);
2779 Result ret;
2780
2781 for (auto it = groups.get_it(); it.has_curr(); it.next_ne())
2782 {
2783 auto & [key, group] = it.get_curr();
2784 ret.append(std::make_pair(key, reducer(group)));
2785 }
2786
2787 return ret;
2788 }
2789
2790
2791} // end namespace Aleph
2792
2793#endif // AH_FUNCTIONAL_H
Exception handling system with formatted messages for Aleph-w.
#define ah_length_error()
Throws std::length_error unconditionally.
Definition ah-errors.H:730
#define ah_invalid_argument()
Throws std::invalid_argument unconditionally.
Definition ah-errors.H:671
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
C++20 Ranges support and adaptors for Aleph-w containers.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
T & get_first() const
Return the first item of the list.
Definition htlist.H:1675
T remove()
Remove the first item of the list.
Definition htlist.H:1611
Iterator that zips two other iterators.
auto get_curr_ne() const noexcept
Get current pair (no bounds check).
bool has_curr1() const noexcept
Check if first iterator has current element.
Pair_Iterator(const C1 &c1, const C2 &c2)
Construct from two containers.
Pair_Iterator(Itor1 i1, Itor2 i2)
Construct from two iterators.
bool has_curr() const noexcept
Check if both iterators have current elements.
bool was_traversed() const noexcept
Check if both iterators were completely traversed.
bool has_curr2() const noexcept
Check if second iterator has current element.
void next()
Advance both iterators (bounds-checked).
auto get_curr() const
Get current pair (bounds-checked).
void next_ne() noexcept
Advance both iterators (no bounds check).
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Definition ah-dry.H:685
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:190
pair< size_t, string > P
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4118
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:824
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::pair< DynList< T >, size_t > unique_sequential(const Container< T > &c, Equal &eq)
Extract unique consecutive items.
std::tuple< bool, size_t, typename C1::Item_Type, typename C2::Item_Type > are_eq(const C1 &c1, const C2 &c2, Eq e=Eq())
Detailed equality check returning mismatch position and values.
DynList< T > flatten(const C2< C1< T > > &c)
Flatten a nested container of one level.
Container< T > nrange(const T start, const T end, const size_t n)
Generate exactly n values evenly spaced between [start, end].
auto group_by_reduce(const Container< T > &c, KeyFunc key_func, Reducer reducer) -> DynList< std::pair< std::invoke_result_t< KeyFunc, const T & >, std::invoke_result_t< Reducer, const DynList< T > & > > >
Group consecutive elements and apply a reducer to each group.
std::pair< const typename Container::Item_Type *, const typename Container::Item_Type * > minmax_ptr(const Container &container, Cmp cmp=Cmp())
Find both min and max elements in a single pass.
const Container::Item_Type * min_ptr(const Container &container, Cmp cmp=Cmp())
Find the minimum element in a container.
DynList< std::pair< std::optional< typename Container1::Item_Type >, std::optional< typename Container2::Item_Type > > > zip_longest_opt(const Container1 &a, const Container2 &b)
Zip two containers using optionals for missing values.
auto unzip(const Container &l)
Separate a list of pairs into two lists.
bool all(Container &container, Operation &operation)
Return true if all elements satisfy a predicate.
void reverse(Itor beg, Itor end)
Reverse elements in a range.
Definition ahAlgo.H:1094
bool eq(const C1 &c1, const C2 &c2, Eq e=Eq())
Check equality of two containers using a predicate.
DynList< T > scanl(const Container &container, const T &init, Op op)
Prefix scan with custom operation.
Itor unique(Itor __first, Itor __last, BinaryPredicate __binary_pred=BinaryPredicate())
Remove consecutive duplicates in place.
Definition ahAlgo.H:1058
T Item_Type
Type of elements from the first container.
Definition ah-zip.H:117
bool operator==(const DynList< T > &l1, const DynList< T > &l2)
Equality operator for DynList.
DynList< typename Container::Item_Type > drop_while(const Container &c, Pred pred)
Skip elements while predicate is true (drop_while).
auto set_range(const T start, const T end, const T step, Op &op) -> Container< std::decay_t< decltype(op(start))> >
Generate a range [start, end] and apply an operation to each value.
DynList< std::pair< typename Container1::Item_Type, typename Container2::Item_Type > > zipEq(const Container1 &a, const Container2 &b)
Zip two containers; throw if lengths differ.
DynList< T > intercept(const Container< T > &c1, const Container< T > &c2)
std::pair< TgtContainer< typename SrcContainer::Item_Type >, TgtContainer< typename SrcContainer::Item_Type > > partition(const SrcContainer &c, std::function< bool(const typename SrcContainer::Item_Type &)> operation)
Partition a container into two based on a predicate.
bool containers_eq(const C1 &c1, const C2 &c2, Eq e)
DynList< std::pair< T, size_t > > repeated_with_index(const Container< T > &c)
Container2< typename Container1::Item_Type > filter(Container1 &container, Operation &operation)
Filter elements that satisfy operation.
bool is_inside(const T &val, const DynList< T > &values)
Check if a value is present in a list.
DynList< T > repeated(const Container< T > &c)
DynList< typename Container::Item_Type > take_while(const Container &c, Pred pred)
Return elements while predicate is true (take_while).
DynList< std::pair< typename Container1::Item_Type, typename Container2::Item_Type > > zip(const Container1 &a, const Container2 &b)
Zip two containers into a list of pairs.
Pair_Iterator< typename C1::Iterator, typename C2::Iterator > get_pair_it(const C1 &c1, const C2 &c2)
Create a Pair_Iterator for two containers.
T foldr(const Container &container, const T &init, Operation operation)
Right fold (reduce).
auto enumerate(const Container &c)
Return pairs of (element, index).
size_t append_in_container(C &c, Args ... args)
Append multiple items into a container.
bool is_equal(const T &val)
Variadic check for equality against multiple values.
T foldl(const Container &container, const T &init, Operation operation)
Classic left fold (reduce).
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:107
bool exists(Container &container, Operation &operation)
Return true if at least one element satisfies a predicate.
auto gen_seq_list_tuples(const Container &c, size_t n)
Generate all sequential tuples (sliding windows) of size n.
bool contains(const std::string_view &str, const std::string_view &substr)
Check if substr appears inside str.
DynList< T > build_dynlist(Args ... args)
Build a DynList with the given items.
std::optional< typename Container::Item_Type > find_opt(const Container &container, Pred &pred)
Find the first element satisfying pred (safe version).
auto flat_map(const Container &container, Op op) -> DynList< typename std::decay_t< decltype(op(std::declval< typename Container::Item_Type >()))>::Item_Type >
Apply operation and flatten results (flatMap/concatMap).
DynList< std::tuple< typename Container1::Item_Type, typename Container2::Item_Type > > tzip(const Container1 &a, const Container2 &b)
Zip two containers into a list of tuples.
T product(const Container &container, const T &init=T{1})
Compute product of all elements.
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
DynList< typename Container::Item_Type * > pointers_list(Container &c)
Create a list of pointers to items in a container.
DynList< std::pair< size_t, typename Container::Key_Type > > indexes(const Container &c)
Return pairs of (index, key).
DynList< typename Container::Item_Type > sublist(const Container &c, size_t pos, size_t stride)
Extract a sublist using a stride.
bool lesser(const C1 &c1, const C2 &c2, Cmp cmp=Cmp())
Lexicographical comparison between two containers.
TgtC assign_container(const SrcC &srcc)
Convert one container type to another.
DynList< std::tuple< size_t, typename Container::Item_Type > > enumerate_tuple(const Container &container)
Zip containers with an index (enumerate with zip).
const Container::Item_Type * max_ptr(const Container &container, Cmp cmp=Cmp())
Find the maximum element in a container.
DynList< std::tuple< typename Container1::Item_Type, typename Container2::Item_Type > > tzipEq(const Container1 &a, const Container2 &b)
Zip two containers into tuples; throw if lengths differ.
Operation for_each(Itor beg, const Itor &end, Operation op)
Apply an operation to each element in a range.
Definition ahAlgo.H:76
std::pair< DynList< DynList< T > >, size_t > sequential_groups(const Container< T > &c, Equal &eq)
Group consecutive equal elements together.
static bool init
Definition hash-fct.C:47
size_t insert_in_container(C &c, Args ... args)
Insert multiple items into a container.
DynList< std::tuple< size_t, typename Container::Key_Type > > tindexes(const Container &c)
Return tuples of (index, key).
Itor::difference_type count_if(Itor beg, const Itor &end, Operation op)
Count elements satisfying a predicate.
Definition ahAlgo.H:100
DynList< T > scanl_sum(const Container &container, const T &init)
Compute running sums (scanl with addition).
DynList< std::tuple< typename Container1::Item_Type, typename Container2::Item_Type > > tzip_longest(const Container1 &a, const Container2 &b, const typename Container1::Item_Type &fill_a=typename Container1::Item_Type(), const typename Container2::Item_Type &fill_b=typename Container2::Item_Type())
Zip two containers into tuples, padding the shorter one.
DynList< std::pair< std::invoke_result_t< KeyFunc, const T & >, DynList< T > > > group_by_eq(const Container< T > &c, KeyFunc key_func, KeyEqual key_equal)
Group consecutive elements by a key function with custom equality.
std::string concat(const Args &... args)
Concatenate multiple streamable arguments into a single std::string.
DynList< std::pair< typename Container1::Item_Type, typename Container2::Item_Type > > zip_longest(const Container1 &a, const Container2 &b, const typename Container1::Item_Type &fill_a=typename Container1::Item_Type(), const typename Container2::Item_Type &fill_b=typename Container2::Item_Type())
Zip two containers, padding the shorter one with a fill value.
std::ostream & join(const C &c, const std::string &sep, std::ostream &out)
Join elements of an Aleph-style container into a stream.
Container::Item_Type * find_ptr(Container &container, Pred &pred)
Find the first element satisfying pred.
Container< T > range(const T start, const T end, const T step=1)
Generate a range of values [start, end] with a given step.
void enum_for_each(const Container &container, Operation &operation)
Apply an operation to each element and its index.
C build_container(Args ... args)
Build a container with the given items.
DynList< std::pair< std::invoke_result_t< KeyFunc, const T & >, DynList< T > > > group_by(const Container< T > &c, KeyFunc key_func)
Group consecutive elements by a key function.
Container< T > contiguous_range(T start, const size_t n)
Generate n contiguous values starting from start.
bool none(const Container &container, Operation &operation)
Return true if no element satisfies operation.
void each(size_t start, size_t end, Op &op)
Execute an operation repeatedly over a range of indices.
size_t remove_from_container(C &c, Args ... args)
Remove multiple items from a container.
std::tuple< Container< T1 >, Container< T2 > > tunzip(const Container< std::tuple< T1, T2 > > &l)
Separate a list of tuples into two containers.
DynList< T > maps(const C &c, Op op)
Classic map operation.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
DynList< T > rep(size_t n, const T &item)
Create a sequence of repeated items.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Default filter operation (always true).
Default folding operation (returns default-constructed accumulator).
Default mapping operation (identity).
Abstract base class for optional-like results.
virtual bool is_found() const noexcept=0
virtual T & get_item()=0
virtual const T & get_item() const =0
Represents a missing value.
virtual T & get_item() override
virtual const T & get_item() const override
virtual bool is_found() const noexcept override
Represents a found value (stored by reference).
virtual bool is_found() const noexcept override
virtual const T & get_item() const override
virtual T & get_item() override
Definition fib.C:287
DynList< int > l