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
60#include <stdexcept>
61#include <utility>
62#include <tuple>
63#include <functional>
64#include <algorithm>
65#include <concepts>
66#include <optional>
67#include <type_traits>
68#include <ah-errors.H>
69#include <ah-ranges.H>
70#include <ah-concepts.H>
71#include <hash-dry.H>
72
73namespace Aleph {
77template <typename T>
79{
80 virtual T &get_item() = 0;
81 virtual const T &get_item() const = 0;
82 virtual bool is_found() const noexcept = 0;
84};
85
89{
90 [[noreturn]] T &get_item() override
91 {
92 ah_invalid_argument() << "Access from None type";
93#if defined(__GNUC__) || defined(__clang__)
94 __builtin_unreachable(); // Satisfies compiler after throw
95#elif defined(_MSC_VER)
96 __assume(0);
97#endif
98 }
99
100 [[noreturn]] const T &get_item() const override
101 {
102 ah_invalid_argument() << "Access from None type";
103#if defined(__GNUC__) || defined(__clang__)
105#elif defined(_MSC_VER)
106 __assume(0);
107#endif
108 }
109
110 [[nodiscard]] bool is_found() const noexcept override
111 {
112 return false;
113 }
114};
115
117template <typename T>
118struct Some : public Found_Item<T>
119{
121
122 Some(T &i) : item(i) {}
123
124 T &get_item() override
125 {
126 return item;
127 }
128 const T &get_item() const override
129 {
130 return item;
131 }
132 [[nodiscard]] bool is_found() const noexcept override
133 {
134 return true;
135 }
136};
137
139template <typename tgtT, typename srcT>
141{
142 tgtT operator()(const srcT &item) const noexcept
143 {
144 return static_cast<tgtT>(item);
145 }
146};
147
149template <typename TR, typename TD>
151{
152 TR operator()(const TR & /*acc */, const TD & /* val */) const noexcept
153 {
154 return TR();
155 }
156};
157
162template <typename Key, class Cmp>
164struct DynSetLhash;
165
166namespace functional_detail {
170template <class C>
171using get_it_t = std::decay_t<decltype(std::declval<const C &>().get_it())>;
172
176template <class C>
177using get_curr_t = decltype(std::declval<get_it_t<C> &>().get_curr());
178
182template <class C>
183using get_curr_cref_t = const std::remove_reference_t<get_curr_t<C>> &;
184
186template <typename T, class Eq, typename = void>
187struct Dyn_Set_Lhash_Available : public std::false_type
188{
189};
190
192template <typename T, class Eq>
193struct Dyn_Set_Lhash_Available<T, Eq, std::void_t<decltype(sizeof(DynSetLhash<T, Eq>))>>
194 : public std::true_type
195{
196};
197
198template <typename T, class Eq>
199inline constexpr bool dyn_set_lhash_available = Dyn_Set_Lhash_Available<T, Eq>::value;
200
201template <AlephSequentialIterableContainer Container, class Equal>
202[[nodiscard]] inline bool pairwise_all_unique(const Container &container, Equal &eq)
203{
204 for (auto it1 = container.get_it(); it1.has_curr(); it1.next_ne())
205 {
206 auto it2 = it1;
207 it2.next_ne();
208 for (; it2.has_curr(); it2.next_ne())
209 if (eq(it1.get_curr(), it2.get_curr()))
210 return false;
211 }
212 return true;
213}
214
215template <AlephSequentialIterableContainer Container, class Hash, class Equal>
216 requires std::copy_constructible<typename Container::Item_Type>
217 and requires(const typename Container::Item_Type &v, Hash h, Equal e) {
218 { h(v) } -> std::convertible_to<size_t>;
219 { e(v, v) } -> std::convertible_to<bool>;
220 }
221[[nodiscard]] inline bool all_unique_hash_path(const Container &container, Hash &hash, Equal &eq)
222{
223 using T = typename Container::Item_Type;
224 using Eq_Type = std::remove_cvref_t<Equal>;
225
226 if constexpr (dyn_set_lhash_available<T, Eq_Type>)
227 {
228 using Set_Type = DynSetLhash<T, Eq_Type>;
229 using Hash_Fct = typename Set_Type::Hash_Fct;
230
231 Hash_Fct hash_fct([&hash](const T &value)
232 {
233 return static_cast<size_t>(hash(value));
234 });
235
236 Set_Type seen(17, hash_fct, eq, hash_default_lower_alpha, hash_default_upper_alpha);
237
238 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
239 if (seen.contains_or_insert(it.get_curr()).second)
240 return false;
241 return true;
242 }
243
244 return pairwise_all_unique(container, eq);
245}
246} // namespace functional_detail
247
252template <typename T>
253class DynList;
254
264template <typename T = int, template <typename> class Container = DynList>
265[[nodiscard]] inline Container<T> range(const T start, const T end, const T step = 1)
266{
268 for (T i = start; i <= end; i += step)
269 ret_val.append(i);
270 return ret_val;
271}
272
283template <typename T = int, template <typename> class Container = DynList>
284[[nodiscard]] inline Container<T> nrange(const T start, const T end, const size_t n)
285{
286 ah_domain_error_if(n == 0) << "nrange: n must be greater than 0";
287
289 if (n == 1)
290 {
291 ret_val.append(start);
292 return ret_val;
293 }
294
295 const auto step = static_cast<double>(end - start) / (n - 1);
296 for (size_t i = 0; i < n; ++i)
297 ret_val.append(static_cast<T>(start + i * step));
298
299 return ret_val;
300}
301
313template <typename T = int, template <typename> class Container = DynList, class Op>
314[[nodiscard]] inline auto set_range(const T start, const T end, const T step, Op &op)
315 -> Container<std::decay_t<decltype(op(start))>>
316{
317 Container<std::decay_t<decltype(op(start))>> ret_val;
318 for (T i = start; i <= end; i += step)
319 ret_val.append(op(i));
320 return ret_val;
321}
322
324template <typename T = int, template <typename> class Container = DynList, class Op>
325[[nodiscard]] inline auto set_range(const T start, const T end, const T step = 1, Op &&op = Op())
326 -> Container<std::decay_t<decltype(op(start))>>
327{
328 return set_range<T, Container, Op>(start, end, step, op);
329}
330
350template <typename T = int, template <typename> class Container = DynList>
351[[nodiscard]] inline Container<T> contiguous_range(T start, const size_t n)
352{
354 for (size_t i = 0; i < n; ++i)
355 ret_val.append(start++);
356 return ret_val;
357}
358
366template <typename T = int, template <typename> class Container = DynList>
368{
370 for (T i = 0; i < n; ++i)
371 ret_val.append(i);
372 return ret_val;
373}
374
383template <typename T = int>
384[[nodiscard]] inline DynList<T> rep(const size_t n, const T &item)
385{
387 for (size_t i = 0; i < n; ++i)
388 ret_val.append(item);
389 return ret_val;
390}
391
393template <typename T = int>
394[[nodiscard]] inline DynList<T> rep(const size_t n, T &&item = T())
395{
396 return rep<T>(n, item);
397}
398
399// ─── In-place fill operations ─────────────────────────────────────────────
400
431template <AlephSequentialContainer C>
432void fill(C &container, const typename C::Item_Type &value)
433{
434 container.mutable_for_each([&value](typename C::Item_Type &item)
435 {
436 item = value;
437 });
438}
439
466template <AlephSequentialContainer C>
467 requires requires(typename C::Item_Type v) { ++v; }
468void iota(C &container, typename C::Item_Type start)
469{
470 container.mutable_for_each([&start](typename C::Item_Type &item)
471 {
472 item = start++;
473 });
474}
475
501template <AlephSequentialContainer C>
502 requires requires(typename C::Item_Type v, typename C::Item_Type s) { v += s; }
503void iota(C &container, typename C::Item_Type start, const typename C::Item_Type step)
504{
505 container.mutable_for_each([&start, &step](typename C::Item_Type &item)
506 {
507 item = start;
508 start += step;
509 });
510}
511
534template <class Container>
535[[nodiscard]]
537{
539 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
540 ret.append(&it.get_curr());
541 return ret;
542}
543
548template <class Container>
549[[nodiscard]]
551{
552 using T = const typename Container::Item_Type *;
554 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
555 ret.append(&it.get_curr());
556 return ret;
557}
558
577template <class Op>
578 requires CallableWith<Op &>
579void each(const size_t start, const size_t end, Op &op)
580{
581 for (size_t i = start; i <= end; ++i)
582 op();
583}
584
586template <class Op>
587 requires CallableWith<Op &>
588void each(size_t start, size_t end, Op &&op)
589{
590 each(start, end, op);
591}
592
594template <class Op>
595 requires CallableWith<Op &>
596void each(const size_t n, Op &op)
597{
598 if (n == 0)
599 return;
600 each(0, n - 1, op);
601}
602
604template <class Op>
605 requires CallableWith<Op &>
606void each(size_t n, Op &&op)
607{
608 each(n, op);
609}
610
618template <class Container>
619[[nodiscard]]
620DynList<typename Container::Item_Type> sublist(const Container &c, size_t pos, const size_t stride)
621{
623 try
624 {
625 for (auto it = c.get_it(pos); it.has_curr(); each(0, stride - 1, [&it]()
626 {
627 it.next();
628 }))
629 ret.append(it.get_curr());
630 }
631 catch (const std::overflow_error &)
632 { /* end of container reached */
633 }
634
635 return ret;
636}
637
639template <class Container>
640[[nodiscard]]
642{
643 return sublist(c, 0, stride);
644}
645
668template <class Container, class Operation>
670{
671 container.traverse([&operation](const auto &item)
672 {
673 operation(item);
674 return true;
675 });
676 return container;
677}
678
680template <class Container, class Operation>
681inline const Container &for_each(const Container &container, Operation &operation)
682{
683 container.traverse([&operation](const auto &item)
684 {
685 operation(item);
686 return true;
687 });
688 return container;
689}
690
692template <class Container, class Operation>
694{
695 return for_each<Container, Operation>(container, operation);
696}
697
699template <class Container, class Operation>
700inline const Container &for_each(const Container &container, Operation &&operation = Operation())
701{
702 return for_each<Container, Operation>(container, operation);
703}
704
732template <class Container, class Operation>
734inline void enum_for_each(const Container &container, Operation &operation)
735{
736 size_t i = 0;
737 for (auto it = container.get_it(); it.has_curr(); it.next_ne(), ++i)
738 operation(it.get_curr(), i);
739}
740
742template <class Container, class Operation>
744inline void enum_for_each(const Container &container, Operation &&operation)
745{
746 enum_for_each(container, operation);
747}
748
772template <class Container, class Operation>
773 requires requires(Container &c, Operation &op) { { c.traverse(op) } -> std::convertible_to<bool>; }
774inline bool all(Container &container, Operation &operation)
775{
776 return container.traverse(operation);
777}
778
780template <class Container, class Operation>
781 requires requires(const Container &c, Operation &op) { { c.template traverse<Operation>(op) } -> std::convertible_to<bool>; }
782inline bool all(const Container &container, Operation &operation)
783{
784 return container.template traverse<Operation>(operation);
785}
786
788template <class Container, class Operation>
789 requires requires(Container &c, Operation &op) { { c.traverse(op) } -> std::convertible_to<bool>; }
790inline bool all(Container &container, Operation &&operation = Operation())
791{
792 return all<Container, Operation>(container, operation);
793}
794
796template <class Container, class Operation>
797 requires requires(const Container &c, Operation &op) { { c.template traverse<Operation>(op) } -> std::convertible_to<bool>; }
798inline bool all(const Container &container, Operation &&operation = Operation())
799{
800 return all<Container, Operation>(container, operation);
801}
802
826template <class Container, class Operation>
827inline bool exists(Container &container, Operation &operation)
828{
829 return not container.traverse([&operation](const auto &item)
830 {
831 return not operation(item);
832 });
833}
834
836template <class Container, class Operation>
837inline bool exists(const Container &container, Operation &operation)
838{
839 return not container.traverse([&operation](const auto &item)
840 {
841 return not operation(item);
842 });
843}
844
846template <class Container, class Operation>
847inline bool exists(Container &container, Operation &&operation = Operation())
848{
849 return exists<Container, Operation>(container, operation);
850}
851
853template <class Container, class Operation>
854inline bool exists(const Container &container, Operation &&operation = Operation())
855{
856 return exists<Container, Operation>(container, operation);
857}
858
860template <typename T>
862{
863 bool operator()(const T &) const noexcept
864 {
865 return true;
866 }
867};
868
878template <class Container1,
879 template <typename> class Container2 = Aleph::DynList,
883{
885 container.for_each([&ret_val, &operation](const auto &item)
886 {
887 if (operation(item))
888 ret_val.append(item);
889 });
890 return ret_val;
891}
892
894template <class Container1,
895 template <typename> class Container2 = Aleph::DynList,
899{
901 container.for_each([&ret_val, &operation](const auto &item)
902 {
903 if (operation(item))
904 ret_val.append(item);
905 });
906 return ret_val;
907}
908
910template <class Container1,
911 template <typename> class Container2 = Aleph::DynList,
918
920template <class Container1,
921 template <typename> class Container2 = Aleph::DynList,
928
937template <typename T, class C, class Op>
938 requires requires(DynList<T> &ret, Op &op) { ret.append(op(std::declval<functional_detail::get_curr_t<C>>())); }
939[[nodiscard]] DynList<T> maps(const C &c, Op op)
940{
942 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
943 ret.append(op(it.get_curr()));
944 return ret;
945}
946
953template <typename T, class Container, class Operation>
954[[nodiscard]] inline T foldl(const Container &container, const T &init, Operation operation)
955{
956#if ALEPH_HAS_RANGES
957 if constexpr (std::ranges::range<Container>)
958 return detail::ranges_fold_left(container, init, std::move(operation));
959 else
960#endif
961 {
962 T ret_val = init;
963 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
964 ret_val = operation(ret_val, it.get_curr());
965 return ret_val;
966 }
967}
968
993template <class Container1, class Container2>
995zip(const Container1 &a, const Container2 &b)
996{
997 typedef typename Container1::Item_Type T1;
998 typedef typename Container2::Item_Type T2;
1000
1001 auto it1 = a.get_it();
1002 auto it2 = b.get_it();
1003 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
1004 ret_val.append(std::pair<T1, T2>(it1.get_curr(), it2.get_curr()));
1005
1006 return ret_val;
1007}
1008
1035template <class Container1, class Container2>
1037tzip(const Container1 &a, const Container2 &b)
1038{
1039 typedef typename Container1::Item_Type T1;
1040 typedef typename Container2::Item_Type T2;
1041 using Tuple = std::tuple<T1, T2>;
1043
1044 auto it1 = a.get_it();
1045 auto it2 = b.get_it();
1046 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
1047 ret_val.append(Tuple(it1.get_curr(), it2.get_curr()));
1048
1049 return ret_val;
1050}
1051
1078template <class Container1, class Container2>
1080zipEq(const Container1 &a, const Container2 &b)
1081{
1082 typedef typename Container1::Item_Type T1;
1083 typedef typename Container2::Item_Type T2;
1085
1086 auto it1 = a.get_it();
1087 auto it2 = b.get_it();
1088 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
1089 ret_val.append(std::pair<T1, T2>(it1.get_curr(), it2.get_curr()));
1090
1091 ah_length_error_if(it1.has_curr() or it2.has_curr()) << "Container sizes mismatch";
1092
1093 return ret_val;
1094}
1095
1112template <class Container1, class Container2>
1114tzipEq(const Container1 &a, const Container2 &b)
1115{
1116 typedef typename Container1::Item_Type T1;
1117 typedef typename Container2::Item_Type T2;
1118 using Tuple = std::tuple<T1, T2>;
1120
1121 auto it1 = a.get_it();
1122 auto it2 = b.get_it();
1123 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
1124 ret_val.append(Tuple(it1.get_curr(), it2.get_curr()));
1125
1126 ah_length_error_if(it1.has_curr() or it2.has_curr()) << "Container sizes mismatch";
1127
1128 return ret_val;
1129}
1130
1156template <class Container>
1157[[nodiscard]]
1158auto inline enumerate(const Container &c)
1159{
1160 using Item = typename Container::Item_Type;
1161 using Pair = std::pair<Item, size_t>;
1163 size_t i = 0;
1164 c.for_each([&i, &ret](const Item &item)
1165 {
1166 ret.append(Pair(item, i++));
1167 });
1168 return ret;
1169}
1170
1199template <class C1, class C2, class Eq = std::equal_to<typename C1::Item_Type>>
1200[[nodiscard]] inline bool eq(const C1 &c1, const C2 &c2, Eq e = Eq())
1201{
1202 auto it1 = c1.get_it();
1203 auto it2 = c2.get_it();
1204 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
1205 if (not(e(it1.get_curr(), it2.get_curr())))
1206 return false;
1207
1208 return not(it1.has_curr() or it2.has_curr());
1209}
1210
1212template <typename T>
1213[[nodiscard]] inline bool operator==(const DynList<T> &l1, const DynList<T> &l2)
1214{
1215 return eq(l1, l2);
1216}
1217
1219template <class C1, class C2, class Eq>
1220[[nodiscard]] inline bool containers_eq(const C1 &c1, const C2 &c2, Eq e)
1221{
1222 return eq(c1, c2, e);
1223}
1224
1251template <class C1, class C2, class Eq = std::equal_to<typename C1::Item_Type>>
1252[[nodiscard]] inline std::tuple<bool, size_t, typename C1::Item_Type, typename C2::Item_Type>
1253are_eq(const C1 &c1, const C2 &c2, Eq e = Eq())
1254{
1255 using T = typename C1::Item_Type;
1256 auto it1 = c1.get_it();
1257 auto it2 = c2.get_it();
1258 size_t n = 0;
1259 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne(), n++)
1260 {
1261 auto &i1 = it1.get_curr();
1262 auto &i2 = it2.get_curr();
1263 if (not(e(i1, i2)))
1264 return std::make_tuple(false, n, i1, i2);
1265 }
1266
1267 return std::make_tuple(not(it1.has_curr() or it2.has_curr()), n, T(), T());
1268}
1269
1296template <class C1, class C2, class Cmp = std::less<typename C1::Item_Type>>
1297[[nodiscard]] inline bool lesser(const C1 &c1, const C2 &c2, Cmp cmp = Cmp())
1298{
1299 auto it1 = c1.get_it();
1300 auto it2 = c2.get_it();
1301 for (; it1.has_curr() and it2.has_curr(); it1.next_ne(), it2.next_ne())
1302 {
1303 auto &curr1 = it1.get_curr();
1304 auto &curr2 = it2.get_curr();
1305 if (cmp(curr1, curr2))
1306 return true;
1307 if (cmp(curr2, curr1))
1308 return false;
1309 }
1310
1311 if (not it1.has_curr() and not it2.has_curr())
1312 return false;
1313
1314 return it2.has_curr();
1315}
1316
1333template <class C1, class C2, class Eq = std::equal_to<typename C1::Item_Type>>
1334[[nodiscard]] inline bool diff(const C1 &c1, const C2 &c2, Eq e = Eq())
1335{
1336 return not eq(c1, c2, e);
1337}
1338
1363template <class Container>
1364[[nodiscard]] inline auto unzip(const Container &l)
1365{
1366 using T1 = std::decay_t<decltype(l.get_first().first)>;
1367 using T2 = std::decay_t<decltype(l.get_first().second)>;
1370 for (auto it = l.get_it(); it.has_curr(); it.next_ne())
1371 {
1372 auto &curr = it.get_curr();
1373 l1.append(curr.first);
1374 l2.append(curr.second);
1375 }
1376
1377 return std::make_pair(std::move(l1), std::move(l2));
1378}
1379
1406template <template <typename> class Container, typename T1, typename T2>
1407[[nodiscard]] inline std::tuple<Container<T1>, Container<T2>> tunzip(
1408 const Container<std::tuple<T1, T2>> &l)
1409{
1412 for (auto it = l.get_it(); it.has_curr(); it.next_ne())
1413 {
1414 auto &curr = it.get_curr();
1415 l1.append(std::get<0>(curr));
1416 l2.append(std::get<1>(curr));
1417 }
1418
1419 return std::make_tuple(std::move(l1), std::move(l2));
1420}
1421
1428template <class SrcContainer, template <typename> class TgtContainer = Aleph::DynList>
1429[[nodiscard]] inline std::pair<TgtContainer<typename SrcContainer::Item_Type>,
1432 std::function<bool(const typename SrcContainer::Item_Type &)> operation)
1433{
1434 typedef typename SrcContainer::Item_Type Type;
1435 typedef std::pair<TgtContainer<Type>, TgtContainer<Type>> Pair;
1436
1437 Pair ret_val;
1438 for_each(c, [&ret_val, &operation](const Type &item)
1439 {
1440 if (operation(item))
1441 ret_val.first.append(item);
1442 else
1443 ret_val.second.append(item);
1444 });
1445 return ret_val;
1446}
1447
1449template <class Container>
1451{
1452 using T = typename Container::Key_Type;
1453 using Pair = std::pair<size_t, T>;
1454 size_t i = 0;
1455
1456 return c.Container::template maps<Pair>([&i](const T &d)
1457 {
1458 return Pair(i++, d);
1459 });
1460}
1461
1463template <class Container>
1465 const Container &c)
1466{
1467 using T = typename Container::Key_Type;
1468 using Tuple = std::tuple<size_t, typename Container::Key_Type>;
1469 size_t i = 0;
1470 return c.Container::template maps<std::tuple<size_t, T>>([&i](const T &d)
1471 {
1472 return Tuple(i++, d);
1473 });
1474}
1475
1496template <typename T, template <typename> class Container>
1498{
1500 l.for_each([&ret_val](const T &item)
1501 {
1502 ret_val.insert(item);
1503 });
1504 return ret_val;
1505}
1506
1528template <class Container>
1529[[nodiscard]]
1530auto gen_seq_list_tuples(const Container &c, size_t n)
1531{
1532 using T = typename Container::Item_Type;
1533 auto it = c.get_it();
1534 DynList<T> l;
1535 for (size_t i = 0; i < n; ++i, it.next())
1536 l.append(it.get_curr());
1537
1539 ret.append(l);
1540 for (; it.has_curr(); it.next_ne())
1541 {
1542 l.remove_first();
1543 l.append(it.get_curr());
1544 ret.append(l);
1545 }
1546
1547 return ret;
1548}
1549
1575template <typename T, template <typename> class Container, class Equal>
1576[[nodiscard]] std::pair<DynList<DynList<T>>, size_t> sequential_groups(const Container<T> &c,
1577 Equal &eq)
1578{
1579 using P = std::pair<DynList<DynList<T>>, size_t>;
1580 if (c.is_empty())
1581 return P(DynList<DynList<T>>(), 0);
1582
1583 DynList<DynList<T>> ret; // this will be the result
1584
1585 DynList<T> *group = &ret.append(DynList<T>()); // creates a first group
1586
1587 auto it = c.get_it(); // put the firstitem into the group
1588 auto curr_item = it.get_curr();
1589 group->append(curr_item);
1590
1591 size_t count = 1; // count the number of groups
1592
1593 for (it.next(); it.has_curr(); it.next_ne())
1594 {
1595 auto &curr = it.get_curr();
1596 if (not eq(curr, curr_item)) // group change?
1597 {
1598 curr_item = curr;
1599 group = &ret.append(DynList<T>()); // create new group and insert it
1600 ++count; // increase the number of groups
1601 }
1602
1603 group->append(curr);
1604 }
1605
1606 return P(ret, count);
1607}
1608
1610template <typename T, template <typename> class Container, class Equal = std::equal_to<T>>
1611[[nodiscard]] std::pair<DynList<DynList<T>>, size_t> sequential_groups(const Container<T> &c,
1612 Equal &&eq = Equal())
1613{
1614 return sequential_groups(c, eq);
1615}
1616
1644template <typename T, template <typename> class Container, class Equal>
1645[[nodiscard]] std::pair<DynList<T>, size_t> unique_sequential(const Container<T> &c, Equal &eq)
1646{
1647 using P = std::pair<DynList<T>, size_t>;
1648 if (c.is_empty())
1649 return P(DynList<T>(), 0);
1650
1652
1653 auto it = c.get_it(); // put the first item
1654 auto curr_item = it.get_curr();
1655 ret.append(curr_item);
1656
1657 size_t count = 1; // count the number of groups
1658
1659 for (it.next(); it.has_curr(); it.next_ne())
1660 {
1661 auto &curr = it.get_curr();
1662 if (not eq(curr, curr_item)) // group change?
1663 {
1664 curr_item = curr;
1665 ret.append(curr_item);
1666 ++count; // increase the number of groups
1667 }
1668 }
1669
1670 return P(ret, count);
1671}
1672
1674template <typename T, template <typename> class Container, class Equal = std::equal_to<T>>
1675[[nodiscard]] std::pair<DynList<T>, size_t> unique_sequential(const Container<T> &c,
1676 Equal &&eq = Equal())
1677{
1678 return unique_sequential(c, eq);
1679}
1680
1705template <class Itor1, class Itor2 = Itor1>
1707{
1708 Itor1 it1;
1709 Itor2 it2;
1710
1711public:
1713 Pair_Iterator(Itor1 i1, Itor2 i2) : it1(i1), it2(i2) {}
1714
1719 template <class C1, class C2>
1720 Pair_Iterator(const C1 &c1, const C2 &c2) : Pair_Iterator(c1.get_it(), c2.get_it())
1721 {}
1722
1726 [[nodiscard]] bool has_curr() const noexcept
1727 {
1728 return it1.has_curr() and it2.has_curr();
1729 }
1730
1732 [[nodiscard]] bool has_curr1() const noexcept
1733 {
1734 return it1.has_curr();
1735 }
1736
1738 [[nodiscard]] bool has_curr2() const noexcept
1739 {
1740 return it2.has_curr();
1741 }
1742
1747 auto get_curr() const
1748 {
1749 return std::make_pair(it1.get_curr(), it2.get_curr());
1750 }
1751
1756 auto get_curr_ne() const noexcept
1757 {
1758 return std::make_pair(it1.get_curr_ne(), it2.get_curr_ne());
1759 }
1760
1764 void next()
1765 {
1766 it1.next();
1767 it2.next();
1768 }
1769
1773 void next_ne() noexcept
1774 {
1775 it1.next_ne();
1776 it2.next_ne();
1777 }
1778
1783 [[nodiscard]] bool was_traversed() const noexcept
1784 {
1785 return not(it1.has_curr() or it2.has_curr());
1786 }
1787};
1788
1803template <class C1, class C2>
1805 const C1 &c1,
1806 const C2 &c2)
1807{
1808 using I1 = typename C1::Iterator;
1809 using I2 = typename C2::Iterator;
1810 auto i1 = c1.get_it();
1811 auto i2 = c2.get_it();
1812 return Pair_Iterator<I1, I2>(i1, i2);
1813}
1814
1816template <class C1, class C2>
1818 const C1 &c1,
1819 const C2 &c2,
1820 const size_t pos)
1821{
1822 using I1 = typename C1::Iterator;
1823 using I2 = typename C2::Iterator;
1824 auto i1 = c1.get_it();
1825 auto i2 = c2.get_it();
1826 for (size_t i = 0; i < pos; ++i)
1827 {
1828 i1.next();
1829 i2.next();
1830 }
1831 return Pair_Iterator<I1, I2>(i1, i2);
1832}
1833
1835template <class C>
1836inline void insert_in_container(C &, size_t &)
1837{}
1838
1839template <class C, typename T, typename... Args>
1840inline void insert_in_container(C &c, size_t &n, const T &item, Args &...args)
1841{
1842 c.insert(item);
1843 ++n;
1844 insert_in_container(c, n, args...);
1845}
1847
1851template <class C, typename... Args>
1852inline size_t insert_in_container(C &c, Args... args)
1853{
1854 size_t n = 0;
1855 insert_in_container(c, n, args...);
1856 return n;
1857}
1858
1860template <class C>
1861inline void append_in_container(C &, size_t &)
1862{}
1863
1864template <class C, typename T, typename... Args>
1865inline void append_in_container(C &c, size_t &n, const T &item, Args &...args)
1866{
1867 c.append(item);
1868 ++n;
1869 append_in_container(c, n, args...);
1870}
1872
1876template <class C, typename... Args>
1877inline size_t append_in_container(C &c, Args... args)
1878{
1879 size_t n = 0;
1880 append_in_container(c, n, args...);
1881 return n;
1882}
1883
1885template <class C, typename... Args>
1887{
1888 C c;
1890 return c;
1891}
1892
1894template <class SrcC, class TgtC>
1896{
1897 TgtC ret;
1898 for (auto it = srcc.get_it(); it.has_curr(); it.next_ne())
1899 ret.append(it.get_curr());
1900
1901 return ret;
1902}
1903
1905template <typename T, typename... Args>
1910
1912template <class C>
1913inline void remove_from_container(C &, size_t &)
1914{}
1915
1916template <class C, typename T, typename... Args>
1917inline void remove_from_container(C &c, size_t &n, const T &item, Args &...args)
1918{
1919 c.remove(item);
1920 ++n;
1921 remove_from_container(c, n, args...);
1922}
1924
1928template <class C, typename... Args>
1929inline size_t remove_from_container(C &c, Args... args)
1930{
1931 size_t n = 0;
1932 remove_from_container(c, n, args...);
1933 return n;
1934}
1935
1936// These functions are defined in tpl_dynSetHash.H
1937
1939template <typename T, template <typename> class Container>
1940[[nodiscard]] inline DynList<T> join(const Container<T> &c1, const Container<T> &c2);
1941
1943template <typename T, template <typename> class Container>
1944[[nodiscard]] inline DynList<T> intercept(const Container<T> &c1, const Container<T> &c2);
1945
1947template <typename T, template <typename> class Container>
1948[[nodiscard]] inline DynList<T> unique(const Container<T> &c);
1949
1951template <typename T, template <typename> class Container>
1952[[nodiscard]] inline DynList<T> repeated(const Container<T> &c);
1953
1955template <typename T, template <typename> class Container>
1957
1978template <typename T, template <typename> class C1, template <typename> class C2>
1980{
1982 for (auto it_c = c.get_it(); it_c.has_curr(); it_c.next_ne())
1983 {
1984 const auto &curr_c = it_c.get_curr();
1985 for (auto it = curr_c.get_it(); it.has_curr(); it.next_ne())
1986 ret.append(it.get_curr());
1987 }
1988 return ret;
1989}
1990
2002template <typename T, template <typename> class C1, template <typename> class C2, template <typename> class C3>
2004{
2006 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
2007 ret.append(flatten(it.get_curr()));
2008 return ret;
2009}
2010
2022template <typename T,
2023 template <typename> class C1,
2024 template <typename> class C2,
2025 template <typename> class C3,
2026 template <typename> class C4>
2028{
2030 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
2031 ret.append(flatten(it.get_curr()));
2032 return ret;
2033}
2034
2046template <typename T,
2047 template <typename> class C1,
2048 template <typename> class C2,
2049 template <typename> class C3,
2050 template <typename> class C4,
2051 template <typename> class C5>
2053{
2055 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
2056 ret.append(flatten(it.get_curr()));
2057 return ret;
2058}
2059
2079template <typename T>
2080[[nodiscard]] inline bool is_inside(const T &val, const DynList<T> &values)
2081{
2082 for (const auto &v : values)
2083 if (val == v)
2084 return true;
2085 return false;
2086}
2087
2105template <typename T>
2106[[nodiscard]] inline bool is_equal(const T &val)
2107{
2108 (void) val;
2109 return false;
2110}
2111
2118template <typename T, typename U, typename... Args>
2119[[nodiscard]] inline bool is_equal(const T &val, const U &rhs, const Args &...args)
2120{
2121 return (val == rhs) or is_equal(val, args...);
2122}
2123
2130template <class Container, class Operation>
2131[[nodiscard]] inline bool none(const Container &container, Operation &operation)
2132{
2133 return not exists(container, operation);
2134}
2135
2137template <class Container, class Operation>
2138[[nodiscard]] inline bool none(const Container &container, Operation &&operation = Operation())
2139{
2140 return none<Container, Operation>(container, operation);
2141}
2142
2170template <class Container, class Pred>
2171[[nodiscard]] inline typename Container::Item_Type *find_ptr(Container &container, Pred &pred)
2172{
2173 typename Container::Item_Type *result = nullptr;
2174 container.traverse([&result, &pred](auto &item)
2175 {
2176 if (pred(item))
2177 {
2178 result = &item;
2179 return false;
2180 }
2181 return true;
2182 });
2183 return result;
2184}
2185
2187template <class Container, class Pred>
2188[[nodiscard]] inline const typename Container::Item_Type *find_ptr(const Container &container,
2189 Pred &pred)
2190{
2191 const typename Container::Item_Type *result = nullptr;
2192 container.traverse([&result, &pred](const auto &item)
2193 {
2194 if (pred(item))
2195 {
2196 result = &item;
2197 return false;
2198 }
2199 return true;
2200 });
2201 return result;
2202}
2203
2205template <class Container, class Pred>
2206[[nodiscard]] inline typename Container::Item_Type *find_ptr(Container &container, Pred &&pred)
2207{
2208 return find_ptr<Container, Pred>(container, pred);
2209}
2210
2212template <class Container, class Pred>
2213[[nodiscard]] inline const typename Container::Item_Type *find_ptr(const Container &container,
2214 Pred &&pred)
2215{
2216 return find_ptr<Container, Pred>(container, pred);
2217}
2218
2241template <class Container, class Pred>
2242[[nodiscard]] inline std::optional<typename Container::Item_Type> find_opt(const Container &container,
2243 Pred &pred)
2244{
2245 std::optional<typename Container::Item_Type> result;
2246 container.traverse([&result, &pred](const auto &item)
2247 {
2248 if (pred(item))
2249 {
2250 result = item;
2251 return false;
2252 }
2253 return true;
2254 });
2255 return result;
2256}
2257
2259template <class Container, class Pred>
2260[[nodiscard]] inline std::optional<typename Container::Item_Type> find_opt(const Container &container,
2261 Pred &&pred)
2262{
2263 return find_opt<Container, Pred>(container, pred);
2264}
2265
2275template <typename T, class Container, class Operation>
2276 requires requires(T &acc, Operation &op, T &x) { acc = op(x, acc); }
2277[[nodiscard]] inline T foldr(const Container &container, const T &init, Operation operation)
2278{
2279 DynList<T> reversed;
2280 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2281 reversed.insert(it.get_curr());
2282
2283 T ret_val = init;
2284 for (auto it = reversed.get_it(); it.has_curr(); it.next_ne())
2285 ret_val = operation(it.get_curr(), ret_val);
2286 return ret_val;
2287}
2288
2296template <class Container, typename T = typename Container::Item_Type>
2297[[nodiscard]] inline T sum(const Container &container, const T &init = T{})
2298{
2299#if ALEPH_HAS_RANGES
2300 if constexpr (std::ranges::range<Container>)
2301 return detail::ranges_fold_left(container, init, std::plus<>{});
2302 else
2303#endif
2304 {
2305 T result = init;
2306 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2307 result = result + it.get_curr();
2308 return result;
2309 }
2310}
2311
2319template <class Container, typename T = typename Container::Item_Type>
2320[[nodiscard]] inline T product(const Container &container, const T &init = T{1})
2321{
2322#if ALEPH_HAS_RANGES
2323 if constexpr (std::ranges::range<Container>)
2324 return detail::ranges_fold_left(container, init, std::multiplies<>{});
2325 else
2326#endif
2327 {
2328 T result = init;
2329 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2330 result = result * it.get_curr();
2331 return result;
2332 }
2333}
2334
2342template <class C1, class C2>
2344{
2346 for (auto it = c1.get_it(); it.has_curr(); it.next_ne())
2347 result.append(it.get_curr());
2348 for (auto it = c2.get_it(); it.has_curr(); it.next_ne())
2349 result.append(it.get_curr());
2350 return result;
2351}
2352
2360template <class Container, class Pred>
2363{
2365 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
2366 {
2367 const auto &item = it.get_curr();
2368 if (not pred(item))
2369 break;
2370 result.append(item);
2371 }
2372 return result;
2373}
2374
2382template <class Container, class Pred>
2385{
2387 bool dropping = true;
2388 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
2389 {
2390 const auto &item = it.get_curr();
2391 if (dropping and pred(item))
2392 continue;
2393 dropping = false;
2394 result.append(item);
2395 }
2396 return result;
2397}
2398
2408template <class Container, class Op>
2409[[nodiscard]] inline auto flat_map(const Container &container, Op op)
2411{
2412 using ResultItemType =
2413 typename std::decay_t<decltype(op(std::declval<typename Container::Item_Type>()))>::Item_Type;
2415 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2416 {
2417 auto sub = op(it.get_curr());
2418 for (auto sit = sub.get_it(); sit.has_curr(); sit.next_ne())
2419 result.append(sit.get_curr());
2420 }
2421 return result;
2422}
2423
2433template <typename T, class Container>
2434[[nodiscard]] inline DynList<T> scanl_sum(const Container &container, const T &init)
2435{
2436 DynList<T> result;
2437 T acc = init;
2438 result.append(acc);
2439 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2440 {
2441 acc = acc + it.get_curr();
2442 result.append(acc);
2443 }
2444 return result;
2445}
2446
2457template <typename T, class Container, class Op>
2458 requires requires(T &acc, Op &op) { acc = op(acc, std::declval<functional_detail::get_curr_t<Container>>()); }
2459[[nodiscard]] inline DynList<T> scanl(const Container &container, const T &init, Op op)
2460{
2461 DynList<T> result;
2462 T acc = init;
2463 result.append(acc);
2464 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2465 {
2466 acc = op(acc, it.get_curr());
2467 result.append(acc);
2468 }
2469 return result;
2470}
2471
2479template <class Container, class Cmp = std::less<typename Container::Item_Type>>
2480 requires PredicateWith<Cmp &, functional_detail::get_curr_cref_t<Container>, const typename Container::Item_Type &>
2481[[nodiscard]] inline const typename Container::Item_Type *min_ptr(const Container &container,
2482 Cmp cmp = Cmp())
2483{
2484 auto it = container.get_it();
2485 if (not it.has_curr())
2486 return nullptr;
2487
2488 const typename Container::Item_Type *min_elem = &it.get_curr();
2489 for (it.next_ne(); it.has_curr(); it.next_ne())
2490 {
2491 const auto &curr = it.get_curr();
2492 if (cmp(curr, *min_elem))
2493 min_elem = &curr;
2494 }
2495 return min_elem;
2496}
2497
2505template <class Container, class Cmp = std::less<typename Container::Item_Type>>
2507[[nodiscard]] inline const typename Container::Item_Type *max_ptr(const Container &container,
2508 Cmp cmp = Cmp())
2509{
2510 auto it = container.get_it();
2511 if (not it.has_curr())
2512 return nullptr;
2513
2514 const typename Container::Item_Type *max_elem = &it.get_curr();
2515 for (it.next_ne(); it.has_curr(); it.next_ne())
2516 {
2517 const auto &curr = it.get_curr();
2518 if (cmp(*max_elem, curr))
2519 max_elem = &curr;
2520 }
2521 return max_elem;
2522}
2523
2531template <class Container, class Cmp = std::less<typename Container::Item_Type>>
2532 requires PredicateWith<Cmp &, functional_detail::get_curr_cref_t<Container>, const typename Container::Item_Type &> and
2534[[nodiscard]] inline std::pair<const typename Container::Item_Type *, const typename Container::Item_Type *>
2535minmax_ptr(const Container &container, Cmp cmp = Cmp())
2536{
2537 using T = typename Container::Item_Type;
2538 auto it = container.get_it();
2539 if (not it.has_curr())
2540 return {nullptr, nullptr};
2541
2542 const T *min_elem = &it.get_curr();
2543 const T *max_elem = min_elem;
2544 for (it.next_ne(); it.has_curr(); it.next_ne())
2545 {
2546 const auto &curr = it.get_curr();
2547 if (cmp(curr, *min_elem))
2548 min_elem = &curr;
2549 if (cmp(*max_elem, curr))
2550 max_elem = &curr;
2551 }
2552 return {min_elem, max_elem};
2553}
2554
2562template <class Container, class Pred>
2564[[nodiscard]] inline size_t count_if(const Container &container, Pred pred)
2565{
2566 size_t count = 0;
2567 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2568 if (pred(it.get_curr()))
2569 ++count;
2570 return count;
2571}
2572
2589template <AlephSequentialIterableContainer Container, class Equal>
2590[[nodiscard]] inline bool all_unique(const Container &container, Equal &eq)
2591{
2592 using T = typename Container::Item_Type;
2593 using Eq = std::remove_cvref_t<Equal>;
2594
2595 if constexpr (std::is_same_v<Eq, std::equal_to<T>> and std::copy_constructible<T>
2596 and requires(const T &v) {
2597 { std::hash<T>{}(v) } -> std::convertible_to<size_t>;
2598 })
2599 {
2600 auto hash = [](const T &value) -> size_t
2601 {
2602 return std::hash<T>{}(value);
2603 };
2604 return functional_detail::all_unique_hash_path(container, hash, eq);
2605 }
2606
2607 return functional_detail::pairwise_all_unique(container, eq);
2608}
2609
2624template <AlephSequentialIterableContainer Container,
2625 class Equal = std::equal_to<typename Container::Item_Type>>
2626[[nodiscard]] inline bool all_unique(const Container &container, Equal &&eq = Equal())
2627{
2628 return all_unique<Container, Equal>(container, eq);
2629}
2630
2646template <AlephSequentialIterableContainer Container, class Hash, class Equal>
2647 requires std::copy_constructible<typename Container::Item_Type>
2648 and requires(const typename Container::Item_Type &v, Hash h, Equal e) {
2649 { h(v) } -> std::convertible_to<size_t>;
2650 { e(v, v) } -> std::convertible_to<bool>;
2651 }
2652[[nodiscard]] inline bool all_unique(const Container &container, Hash &hash, Equal &eq)
2653{
2654 return functional_detail::all_unique_hash_path(container, hash, eq);
2655}
2656
2658template <AlephSequentialIterableContainer Container, class Hash, class Equal>
2659 requires std::copy_constructible<typename Container::Item_Type>
2660 and requires(const typename Container::Item_Type &v, Hash h, Equal e) {
2661 { h(v) } -> std::convertible_to<size_t>;
2662 { e(v, v) } -> std::convertible_to<bool>;
2663 }
2664[[nodiscard]] inline bool all_unique(const Container &container, Hash &&hash, Equal &&eq)
2665{
2666 using Hash_Type = std::remove_reference_t<Hash>;
2667 using Eq_Type = std::remove_reference_t<Equal>;
2668
2669 Hash_Type hash_obj = std::forward<Hash>(hash);
2670 Eq_Type eq_obj = std::forward<Equal>(eq);
2671 return all_unique(container, hash_obj, eq_obj);
2672}
2673
2681template <class Container>
2682[[nodiscard]] inline bool contains(const Container &container,
2683 const typename Container::Item_Type &value)
2684{
2685 for (auto it = container.get_it(); it.has_curr(); it.next_ne())
2686 if (it.get_curr() == value)
2687 return true;
2688 return false;
2689}
2690
2699template <class Container>
2701 const Container &container)
2702{
2703 using T = typename Container::Item_Type;
2704 using Tuple = std::tuple<size_t, T>;
2705 DynList<Tuple> result;
2706 size_t i = 0;
2707 for (auto it = container.get_it(); it.has_curr(); it.next_ne(), ++i)
2708 result.append(Tuple(i, it.get_curr()));
2709 return result;
2710}
2711
2746template <class Container1, class Container2>
2749 const Container2 &b,
2750 const typename Container1::Item_Type &fill_a = typename Container1::Item_Type(),
2751 const typename Container2::Item_Type &fill_b = typename Container2::Item_Type())
2752{
2753 using T1 = typename Container1::Item_Type;
2754 using T2 = typename Container2::Item_Type;
2756
2757 auto it1 = a.get_it();
2758 auto it2 = b.get_it();
2759
2760 // Process while both have elements
2761 while (it1.has_curr() and it2.has_curr())
2762 {
2763 ret_val.append(std::pair<T1, T2>(it1.get_curr(), it2.get_curr()));
2764 it1.next_ne();
2765 it2.next_ne();
2766 }
2767
2768 // Process remaining elements from the first container
2769 while (it1.has_curr())
2770 {
2771 ret_val.append(std::pair<T1, T2>(it1.get_curr(), fill_b));
2772 it1.next_ne();
2773 }
2774
2775 // Process remaining elements from the second container
2776 while (it2.has_curr())
2777 {
2778 ret_val.append(std::pair<T1, T2>(fill_a, it2.get_curr()));
2779 it2.next_ne();
2780 }
2781
2782 return ret_val;
2783}
2784
2816template <class Container1, class Container2>
2819 const Container2 &b,
2820 const typename Container1::Item_Type &fill_a = typename Container1::Item_Type(),
2821 const typename Container2::Item_Type &fill_b = typename Container2::Item_Type())
2822{
2823 using T1 = typename Container1::Item_Type;
2824 using T2 = typename Container2::Item_Type;
2825 using Tuple = std::tuple<T1, T2>;
2827
2828 auto it1 = a.get_it();
2829 auto it2 = b.get_it();
2830
2831 while (it1.has_curr() and it2.has_curr())
2832 {
2833 ret_val.append(Tuple(it1.get_curr(), it2.get_curr()));
2834 it1.next_ne();
2835 it2.next_ne();
2836 }
2837
2838 while (it1.has_curr())
2839 {
2840 ret_val.append(Tuple(it1.get_curr(), fill_b));
2841 it1.next_ne();
2842 }
2843
2844 while (it2.has_curr())
2845 {
2846 ret_val.append(Tuple(fill_a, it2.get_curr()));
2847 it2.next_ne();
2848 }
2849
2850 return ret_val;
2851}
2852
2888template <class Container1, class Container2>
2890 std::optional<typename Container2::Item_Type>>>
2892{
2893 using T1 = typename Container1::Item_Type;
2894 using T2 = typename Container2::Item_Type;
2895 using Opt1 = std::optional<T1>;
2896 using Opt2 = std::optional<T2>;
2898
2899 auto it1 = a.get_it();
2900 auto it2 = b.get_it();
2901
2902 while (it1.has_curr() and it2.has_curr())
2903 {
2904 ret_val.append(std::make_pair(Opt1(it1.get_curr()), Opt2(it2.get_curr())));
2905 it1.next_ne();
2906 it2.next_ne();
2907 }
2908
2909 while (it1.has_curr())
2910 {
2911 ret_val.append(std::make_pair(Opt1(it1.get_curr()), std::nullopt));
2912 it1.next_ne();
2913 }
2914
2915 while (it2.has_curr())
2916 {
2917 ret_val.append(std::make_pair(std::nullopt, Opt2(it2.get_curr())));
2918 it2.next_ne();
2919 }
2920
2921 return ret_val;
2922}
2923
2972template <typename T, template <typename> class Container, class KeyFunc>
2973[[nodiscard]]
2976{
2977 using Key = std::invoke_result_t<KeyFunc, const T &>;
2978 using Group = DynList<T>;
2979 using Result = DynList<std::pair<Key, Group>>;
2980
2981 Result ret;
2982 if (c.is_empty())
2983 return ret;
2984
2985 auto it = c.get_it();
2986 Key curr_key = key_func(it.get_curr());
2987 Group *curr_group = &ret.append(std::make_pair(curr_key, Group())).second;
2988 curr_group->append(it.get_curr());
2989
2990 for (it.next_ne(); it.has_curr(); it.next_ne())
2991 {
2992 const auto &item = it.get_curr();
2993 Key new_key = key_func(item);
2994
2995 if (new_key != curr_key)
2996 {
2997 curr_key = new_key;
2998 curr_group = &ret.append(std::make_pair(curr_key, Group())).second;
2999 }
3000
3001 curr_group->append(item);
3002 }
3003
3004 return ret;
3005}
3006
3038template <typename T, template <typename> class Container, class KeyFunc, class KeyEqual>
3039[[nodiscard]]
3042{
3043 using Key = std::invoke_result_t<KeyFunc, const T &>;
3044 using Group = DynList<T>;
3045 using Result = DynList<std::pair<Key, Group>>;
3046
3047 Result ret;
3048 if (c.is_empty())
3049 return ret;
3050
3051 auto it = c.get_it();
3052 Key curr_key = key_func(it.get_curr());
3053 Group *curr_group = &ret.append(std::make_pair(curr_key, Group())).second;
3054 curr_group->append(it.get_curr());
3055
3056 for (it.next_ne(); it.has_curr(); it.next_ne())
3057 {
3058 const auto &item = it.get_curr();
3059 Key new_key = key_func(item);
3060
3062 {
3063 curr_key = new_key;
3064 curr_group = &ret.append(std::make_pair(curr_key, Group())).second;
3065 }
3066
3067 curr_group->append(item);
3068 }
3069
3070 return ret;
3071}
3072
3110template <typename T, template <typename> class Container, class KeyFunc, class Reducer>
3111[[nodiscard]]
3113 std::pair<std::invoke_result_t<KeyFunc, const T &>, std::invoke_result_t<Reducer, const DynList<T> &>>>
3114{
3115 using Key = std::invoke_result_t<KeyFunc, const T &>;
3116 using ReducedType = std::invoke_result_t<Reducer, const DynList<T> &>;
3118
3119 auto groups = group_by(c, key_func);
3120 Result ret;
3121
3122 for (auto it = groups.get_it(); it.has_curr(); it.next_ne())
3123 {
3124 auto &[key, group] = it.get_curr();
3125 ret.append(std::make_pair(key, reducer(group)));
3126 }
3127
3128 return ret;
3129}
3130
3131} // end namespace Aleph
3132
3133#endif // AH_FUNCTIONAL_H
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
Exception handling system with formatted messages for Aleph-w.
#define ah_length_error_if(C)
Throws std::length_error if condition holds.
Definition ah-errors.H:703
#define ah_invalid_argument()
Throws std::invalid_argument unconditionally.
Definition ah-errors.H:676
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
C++20 Ranges support and adaptors for Aleph-w containers.
long double h
Definition btreepic.C:154
size_t size_t int32_t value
Definition ca-c-api.h:116
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & insert(const T &item)
Definition htlist.H:1220
T & append(const T &item)
Definition htlist.H:1271
T & get_first() const
Return the first item of the list.
Definition htlist.H:1375
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:796
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:228
pair< size_t, string > P
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
Common hash table utilities and base classes.
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
decltype(std::declval< get_it_t< C > & >().get_curr()) get_curr_t
Type of it.get_curr() on a get_it_t<C> lvalue.
const std::remove_reference_t< get_curr_t< C > > & get_curr_cref_t
Type of const auto &item = it.get_curr().
bool pairwise_all_unique(const Container &container, Equal &eq)
bool all_unique_hash_path(const Container &container, Hash &hash, Equal &eq)
constexpr bool dyn_set_lhash_available
std::decay_t< decltype(std::declval< const C & >().get_it())> get_it_t
Type of auto it = c.get_it() for a const C &c.
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.
void each(const size_t start, const size_t end, Op &op)
Execute an operation repeatedly over a range of indices.
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.
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.
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.
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:114
bool operator==(const DynList< T > &l1, const DynList< T > &l2)
Equality operator for DynList.
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)
Return intersection of two containers as a DynList.
void enum_for_each(const Container &container, Operation &operation)
Apply an operation to each element and its index.
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)
bool all_unique(const Container &container, Equal &eq)
Check if all elements in a container are unique using a comparator.
DynList< std::pair< T, size_t > > repeated_with_index(const Container< T > &c)
Return repeated elements paired with their occurrence count.
T foldr(const Container &container, const T &init, Operation operation)
Right fold (reduce).
Container2< typename Container1::Item_Type > filter(Container1 &container, Operation &operation)
Filter elements that satisfy operation.
size_t remove_from_container(C &c, Args... args)
Remove multiple items from a container.
bool is_inside(const T &val, const DynList< T > &values)
Check if a value is present in a list.
std::string concat(const Args &...args)
Concatenate multiple arguments into a single std::string.
DynList< T > repeated(const Container< T > &c)
Return elements that appear more than once in the container.
const float hash_default_upper_alpha
Definition hash-dry.C:40
const Container::Item_Type * max_ptr(const Container &container, Cmp cmp=Cmp())
Find the maximum element in a container.
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.
bool all(Container &container, Operation &operation)
Return true if all elements satisfy a predicate.
Pair_Iterator< typename C1::Iterator, typename C2::Iterator > get_pair_it(const C1 &c1, const C2 &c2)
Create a Pair_Iterator for two containers.
void fill(Itor beg, const Itor &end, const T &value)
Fill a range with a value.
Definition ahAlgo.H:707
and
Check uniqueness with explicit hash + equality functors.
auto enumerate(const Container &c)
Return pairs of (element, index).
DynList< T > build_dynlist(Args... args)
Build a DynList with the given items.
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:105
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.
void iota(C &container, typename C::Item_Type start)
Fill all elements of a container with unit-step sequential values.
std::optional< typename Container::Item_Type > find_opt(const Container &container, Pred &pred)
Find the first element satisfying pred (safe version).
DynList< T > rep(const size_t n, const T &item)
Create a sequence of repeated items.
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).
auto get_curr() const
Return the current tuple (bounds-checked).
Definition ah-zip.H:145
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.
and PredicateWith< Cmp &, const typename Container::Item_Type &, functional_detail::get_curr_cref_t< Container > > 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.
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).
bool lesser(const C1 &c1, const C2 &c2, Cmp cmp=Cmp())
Lexicographical comparison between two containers.
DynList< typename Container::Item_Type > take_while(const Container &c, Pred pred)
Return elements while predicate is true (take_while).
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).
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.
size_t append_in_container(C &c, Args... args)
Append 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< T > scanl(const Container &container, const T &init, Op op)
Prefix scan with custom operation.
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.
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.
DynList< typename Container::Item_Type > sublist(const Container &c, size_t pos, const size_t stride)
Extract a sublist using a stride.
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.
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.
const float hash_default_lower_alpha
Definition hash-dry.C:38
bool none(const Container &container, Operation &operation)
Return true if no element satisfies operation.
static std::atomic< bool > init
Definition hash-fct.C:54
DynList< typename Container::Item_Type > drop_while(const Container &c, Pred pred)
Skip elements while predicate is true (drop_while).
size_t insert_in_container(C &c, Args... args)
Insert multiple items into a container.
const Container::Item_Type * min_ptr(const Container &container, Cmp cmp=Cmp())
Find the minimum element in a container.
@ Tuple
Tuple type such as (Int, Bool).
std::tuple< Container< T1 >, Container< T2 > > tunzip(const Container< std::tuple< T1, T2 > > &l)
Separate a list of tuples into two containers.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
C build_container(Args... args)
Build a container with the given items.
DynList< T > maps(const C &c, Op op)
Classic map operation.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
STL namespace.
Default filter operation (always true).
bool operator()(const T &) const noexcept
Default folding operation (returns default-constructed accumulator).
TR operator()(const TR &, const TD &) const noexcept
Default mapping operation (identity).
tgtT operator()(const srcT &item) const noexcept
Hash-based dynamic set (defined in tpl_dynSetHash.H).
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.
const T & get_item() const override
T & get_item() override
bool is_found() const noexcept override
Represents a found value (stored by reference).
const T & get_item() const override
bool is_found() const noexcept override
T & get_item() override
DynList< int > l1
DynList< int > l2
DynList< int > l