32# ifndef AH_STL_FUNCTIONAL_H
33# define AH_STL_FUNCTIONAL_H
74# include <type_traits>
84# include <unordered_set>
85# include <unordered_map>
101 template <
typename T>
102 struct has_size : std::bool_constant<requires { std::declval<T>().size(); }> {};
104 template <
typename T>
108 template <
typename T>
109 struct is_std_hashable : std::bool_constant<requires { std::hash<T>{}(std::declval<T>()); }> {};
111 template <
typename T>
115 template <
typename T>
118 std::declval<T>().rbegin();
119 std::declval<T>().rend();
122 template <
typename T>
126 template <
typename Container>
136 template <
typename Result,
typename Container>
140 result.reserve(c.size());
144 template <
typename Result>
147 if constexpr (
requires { result.reserve(n); })
174 template <
typename T =
int>
177 std::vector<T> result;
178 if (step > 0
and start <= end)
180 result.reserve(
static_cast<size_t>((end - start) / step + 1));
181 for (
T i = start; i <= end; i += step)
186 result.reserve(
static_cast<size_t>((start - end) / (-step) + 1));
187 for (
T i = start; i >= end; i += step)
202 template <
typename T =
int>
205 std::vector<T> result;
206 result.reserve(
static_cast<size_t>(n));
207 for (
T i = 0; i < n; ++i)
223 template <
typename T =
double>
226 std::vector<T> result;
227 if (n == 0)
return result;
231 result.push_back(start);
236 const auto step = (end - start) /
static_cast<T>(n - 1);
237 for (
size_t i = 0; i < n; ++i)
238 result.push_back(start +
static_cast<T>(i) * step);
252 template <
typename T>
255 return std::vector<T>(n,
value);
268 template <
typename Gen>
271 using T = std::decay_t<
decltype(
gen(
size_t{}))>;
272 std::vector<T> result;
275 for (
size_t i = 0; i < n; ++i)
293 template <
typename Op,
typename Container>
297 for (
const auto & item: c)
310 template <
typename Op,
typename Container>
315 for (
const auto & item: c)
334 template <
typename Op,
typename Container>
337 using T =
typename Container::value_type;
338 using R = std::decay_t<decltype(op(std::declval<T>()))>;
340 std::vector<R> result;
343 for (
const auto & item: c)
344 result.push_back(
op_ref(item));
358 template <
typename Op,
typename Container>
361 using T =
typename Container::value_type;
362 using R = std::decay_t<
decltype(op(
size_t{}, std::declval<T>()))>;
364 std::vector<R> result;
368 for (
const auto & item: c)
369 result.push_back(
op_ref(i++, item));
383 template <
typename Pred,
typename Container>
386 using T =
typename Container::value_type;
388 std::vector<T> result;
390 for (
const auto & item: c)
392 result.push_back(item);
406 template <
typename Pred,
typename Container>
409 using T =
typename Container::value_type;
411 std::vector<T> result;
414 for (
const auto & item: c)
417 result.push_back(item);
441 template <
typename T,
typename Op,
typename Container>
445 if constexpr (std::ranges::range<Container>)
452 for (
const auto & item: c)
479 template <
typename T,
typename Op,
typename Container>
482 static_assert(stl_detail::has_reverse_iterators_v<Container>,
483 "stl_foldr requires a container with reverse iterators (rbegin/rend)");
486 for (
auto it = c.rbegin(); it != c.rend(); ++it)
508 template <
typename T,
typename Op,
typename Container>
511 std::vector<T> result;
512 if constexpr (stl_detail::has_size_v<Container>)
513 result.reserve(c.size() + 1);
514 result.push_back(
init);
518 for (
const auto & item: c)
521 result.push_back(
acc);
537 template <
typename T,
typename Op,
typename Container>
540 static_assert(stl_detail::has_reverse_iterators_v<Container>,
541 "stl_scan_right requires a container with reverse iterators (rbegin/rend)");
542 std::vector<T> result;
543 if constexpr (stl_detail::has_size_v<Container>)
544 result.reserve(c.size() + 1);
547 result.push_back(
acc);
550 for (
auto it = c.rbegin(); it != c.rend(); ++it)
553 result.push_back(
acc);
556 std::reverse(result.begin(), result.end());
561 template <
typename T,
typename Op,
typename Container>
581 template <
typename Pred,
typename Container>
585 if constexpr (std::ranges::range<Container>)
591 for (
const auto & item: c)
608 template <
typename Pred,
typename Container>
612 if constexpr (std::ranges::range<Container>)
618 for (
const auto & item: c)
626 template <
typename Pred,
typename Container>
638 template <
typename Pred,
typename Container>
658 template <
typename Pred,
typename Container>
661 using T =
typename Container::value_type;
664 for (
const auto & item: c)
666 return std::optional<T>(item);
667 return std::optional<T>{};
680 template <
typename Pred,
typename Container>
683 using T =
typename Container::value_type;
685 std::optional<T> result;
687 for (
const auto & item: c)
703 template <
typename Pred,
typename Container>
708 for (
const auto & item: c)
727 template <
typename Op,
typename Container>
730 using T =
typename Container::value_type;
731 using OptType = std::decay_t<
decltype(op(
size_t{}, std::declval<T>()))>;
732 static_assert(std::is_default_constructible_v<OptType>,
733 "stl_find_mapi requires the return type to be default-constructible (like std::optional)");
737 for (
const auto & item: c)
738 if (
auto result =
op_ref(i++, item))
753 template <
typename T,
typename Container>
756 for (
const auto & item: c)
776 template <
typename Pred,
typename Container>
781 for (
const auto & item: c)
797 template <
typename T,
typename Container>
801 for (
const auto & item: c)
821 template <
typename Container>
824 using T =
typename Container::value_type;
826 std::vector<T> result;
829 for (
const auto & item: c)
831 if (
count >= n)
break;
832 result.push_back(item);
848 template <
typename Container>
851 using T =
typename Container::value_type;
853 std::vector<T> result;
854 if constexpr (stl_detail::has_size_v<Container>)
856 if (
const size_t size = c.size();
size > n)
857 result.reserve(
size - n);
860 for (
const auto & item: c)
863 result.push_back(item);
879 template <
typename Container>
882 using T =
typename Container::value_type;
884 std::vector<T> result;
888 if constexpr (!stl_detail::has_size_v<Container>)
891 std::vector<T>
all(c.begin(), c.end());
893 const size_t skip =
size > n ? (
size - n) : 0;
894 result.reserve(
size > n ? n :
size);
895 for (
size_t i = skip; i <
size; ++i)
896 result.push_back(std::move(
all[i]));
903 const size_t skip =
size > n ? (
size - n) : 0;
906 for (
const auto & item: c)
909 result.push_back(item);
926 template <
typename Pred,
typename Container>
929 using T =
typename Container::value_type;
931 std::vector<T> result;
933 for (
const auto & item: c)
937 result.push_back(item);
952 template <
typename Pred,
typename Container>
955 using T =
typename Container::value_type;
957 std::vector<T> result;
960 for (
const auto & item: c)
965 result.push_back(item);
983 template <
typename Container>
986 using T =
typename Container::value_type;
990 return std::optional<T>{};
991 return std::optional<T>(*it);
1003 template <
typename Container>
1006 using T =
typename Container::value_type;
1008 auto it = c.begin();
1010 return std::optional<T>{};
1013 if constexpr (stl_detail::has_reverse_iterators_v<Container>)
1015 return std::optional<T>(*c.rbegin());
1022 for (; it != c.end(); ++it)
1024 return std::optional<T>(last);
1038 template <
typename Container>
1041 using T =
typename Container::value_type;
1044 for (
const auto & item: c)
1047 return std::optional<T>(item);
1050 return std::optional<T>{};
1066 template <
typename Container>
1069 using T =
typename Container::value_type;
1071 auto it = c.begin();
1073 return std::optional<T>{};
1077 for (; it != c.end(); ++it)
1080 return std::optional<T>(min_val);
1092 template <
typename Container>
1095 using T =
typename Container::value_type;
1097 auto it = c.begin();
1099 return std::optional<T>{};
1103 for (; it != c.end(); ++it)
1106 return std::optional<T>(max_val);
1118 template <
typename Container>
1121 using T =
typename Container::value_type;
1122 using ResultType = std::optional<std::pair<T, T>>;
1124 auto it = c.begin();
1132 for (; it != c.end(); ++it)
1134 if (*it < min_val) min_val = *it;
1135 if (*it > max_val) max_val = *it;
1137 return ResultType(std::make_pair(min_val, max_val));
1150 template <
typename Key,
typename Container>
1153 using T =
typename Container::value_type;
1155 auto it = c.begin();
1157 return std::optional<T>{};
1164 for (; it != c.end(); ++it)
1186 template <
typename Key,
typename Container>
1189 using T =
typename Container::value_type;
1191 auto it = c.begin();
1193 return std::optional<T>{};
1200 for (; it != c.end(); ++it)
1225 template <
typename Container>
1228 using T =
typename Container::value_type;
1230 for (
const auto & item: c)
1244 template <
typename Container>
1247 using T =
typename Container::value_type;
1248 if (c.empty())
return T{};
1250 auto it = c.begin();
1253 for (; it != c.end(); ++it)
1272 template <
typename Pred,
typename Container>
1275 using T =
typename Container::value_type;
1279 for (
const auto & item: c)
1301 template <
typename Container1,
typename Container2>
1304 using T1 =
typename Container1::value_type;
1305 using T2 =
typename Container2::value_type;
1307 std::vector<std::pair<T1, T2>> result;
1308 if constexpr (stl_detail::has_size_v<Container1> && stl_detail::has_size_v<Container2>)
1309 result.reserve(std::min(
c1.size(),
c2.size()));
1310 auto it1 =
c1.begin();
1311 auto it2 =
c2.begin();
1312 for (; it1 !=
c1.end()
and it2 !=
c2.end(); ++it1, ++it2)
1313 result.emplace_back(*it1, *it2);
1326 template <
typename Container>
1329 using PairType =
typename Container::value_type;
1330 using T1 = std::decay_t<decltype(std::declval<PairType>().first)>;
1331 using T2 = std::decay_t<decltype(std::declval<PairType>().second)>;
1338 for (
const auto & p: c)
1340 v1.push_back(p.first);
1341 v2.push_back(p.second);
1343 return std::make_pair(std::move(v1), std::move(v2));
1355 template <
typename Container>
1358 using T =
typename Container::value_type;
1360 std::vector<std::pair<size_t, T>> result;
1363 for (
const auto & item: c)
1364 result.emplace_back(i++, item);
1382 template <
typename Container1,
typename Container2>
1385 auto it1 =
c1.begin();
1386 auto it2 =
c2.begin();
1387 for (; it1 !=
c1.end()
and it2 !=
c2.end(); ++it1, ++it2)
1388 if (
not (*it1 == *it2))
1390 return it1 ==
c1.end()
and it2 ==
c2.end();
1403 template <
typename Container1,
typename Container2>
1406 auto it1 =
c1.begin();
1407 auto it2 =
c2.begin();
1409 for (; it1 !=
c1.end()
and it2 !=
c2.end(); ++it1, ++it2)
1411 if (*it1 < *it2)
return -1;
1412 if (*it2 < *it1)
return 1;
1415 if (it1 ==
c1.end()
and it2 ==
c2.end())
return 0;
1416 return (it1 ==
c1.end()) ? -1 : 1;
1432 template <
typename Container>
1435 using T =
typename Container::value_type;
1437 std::vector<T> result(c.begin(), c.end());
1438 std::reverse(result.begin(), result.end());
1451 template <
typename Container>
1454 using T =
typename Container::value_type;
1456 std::vector<T> result(c.begin(), c.end());
1471 template <
typename Cmp,
typename Container>
1474 using T =
typename Container::value_type;
1476 std::vector<T> result(c.begin(), c.end());
1494 template <
typename Container>
1497 using T =
typename Container::value_type;
1499 std::vector<T> result;
1500 for (
const auto & item: c)
1501 if (result.empty()
or not (result.back() == item))
1502 result.push_back(item);
1532 template <
typename Container>
1535 using T =
typename Container::value_type;
1537 std::vector<T> result;
1541 if constexpr (!stl_detail::is_std_hashable_v<T>)
1544 for (
const auto & item : c)
1545 if (std::find(result.begin(), result.end(), item) == result.end())
1546 result.push_back(item);
1551 for (
const auto & item : c)
1552 if (std::find(result.begin(), result.end(), item) == result.end())
1553 result.push_back(item);
1558 std::unordered_set<T>
seen;
1560 for (
const auto & item : c)
1561 if (
seen.insert(item).second)
1562 result.push_back(item);
1582 template <
typename Container1,
typename Container2>
1585 using T =
typename Container1::value_type;
1587 std::vector<T> result;
1588 if constexpr (stl_detail::has_size_v<Container1> && stl_detail::has_size_v<Container2>)
1589 result.reserve(
c1.size() +
c2.size());
1590 for (
const auto & item:
c1)
1591 result.push_back(item);
1592 for (
const auto & item:
c2)
1593 result.push_back(item);
1606 template <
typename Container>
1610 using T =
typename InnerContainer::value_type;
1612 std::vector<T> result;
1613 for (
const auto & inner: c)
1614 for (
const auto & item: inner)
1615 result.push_back(item);
1629 template <
typename Op,
typename Container>
1632 using T =
typename Container::value_type;
1633 using InnerContainer = std::decay_t<decltype(op(std::declval<T>()))>;
1634 using R =
typename InnerContainer::value_type;
1636 std::vector<R> result;
1638 for (
const auto & item: c)
1657 template <
typename Container>
1660 using T =
typename Container::value_type;
1662 std::vector<std::vector<T>> result;
1663 if (c.empty())
return result;
1665 auto it = c.begin();
1666 result.emplace_back();
1667 result.back().push_back(*it);
1671 for (; it != c.end(); ++it)
1673 if (
not (*it == current))
1675 result.emplace_back();
1678 result.back().push_back(*it);
1712 template <
typename Key,
typename Container>
1715 using T =
typename Container::value_type;
1716 using K = std::decay_t<decltype(key(std::declval<T>()))>;
1718 std::vector<std::pair<K, std::vector<T>>> result;
1723 if constexpr (!stl_detail::is_std_hashable_v<K>)
1726 for (
const auto & item : c)
1729 auto it = std::find_if(result.begin(), result.end(),
1730 [&
k](
const auto & p) { return p.first == k; });
1731 if (it != result.end())
1732 it->second.push_back(item);
1734 result.emplace_back(std::move(
k), std::vector<T>{item});
1740 for (
const auto & item : c)
1743 auto it = std::find_if(result.begin(), result.end(),
1744 [&
k](
const auto & p) { return p.first == k; });
1745 if (it != result.end())
1746 it->second.push_back(item);
1748 result.emplace_back(std::move(
k), std::vector<T>{item});
1757 for (
const auto & item : c)
1760 auto [it, inserted] =
key_to_index.try_emplace(
k, result.size());
1762 result.emplace_back(std::move(
k), std::vector<T>{item});
1764 result[it->second].second.push_back(item);
1775 namespace stl_comb_detail
1777 template <
typename T,
typename Op>
1780 if (start >= arr.size())
1783 for (
size_t i = start; i < arr.size(); ++i)
1785 std::swap(arr[start], arr[i]);
1788 std::swap(arr[start], arr[i]);
1791 std::swap(arr[start], arr[i]);
1796 template <
typename T,
typename Op>
1798 std::vector<T> & current, Op &
op_ref)
1800 if (current.size() ==
k)
1803 for (
size_t i = start; i <= arr.size() - (
k - current.size()); ++i)
1805 current.push_back(arr[i]);
1816 template <
typename T,
typename Op>
1818 std::vector<T> & current, std::vector<bool> &
used, Op &
op_ref)
1820 if (current.size() ==
k)
1823 for (
size_t i = 0; i < arr.size(); ++i)
1825 if (
used[i])
continue;
1827 current.push_back(arr[i]);
1864 template <
typename Op,
typename Container>
1867 using T =
typename Container::value_type;
1868 std::vector<T> arr(c.begin(), c.end());
1884 template <
typename Container>
1887 using T =
typename Container::value_type;
1888 std::vector<std::vector<T>> result;
1892 result.push_back(p);
1923 template <
typename Op,
typename Container>
1926 using T =
typename Container::value_type;
1927 std::vector<T> arr(c.begin(), c.end());
1932 std::vector<T> current;
1948 template <
typename Container>
1951 using T =
typename Container::value_type;
1952 std::vector<std::vector<T>> result;
1956 result.push_back(
combo);
1987 template <
typename Op,
typename Container>
1990 using T =
typename Container::value_type;
1991 std::vector<T> arr(c.begin(), c.end());
1996 std::vector<T> current;
1998 std::vector<bool>
used(arr.size(),
false);
2013 template <
typename Container>
2016 using T =
typename Container::value_type;
2017 std::vector<std::vector<T>> result;
2021 result.push_back(arr);
2044 template <
typename T>
2047 std::vector<std::vector<T>> result;
2054 result.push_back({
elem});
2057 for (
size_t i = 1; i <
containers.size(); ++i)
2060 for (
const auto & partial: result)
2082 template <
typename Container>
2085 using T =
typename Container::value_type;
2086 std::vector<T> arr(c.begin(), c.end());
2087 std::vector<std::vector<T>> result;
2089 const size_t n = arr.size();
2093 throw std::overflow_error(
"stl_power_set: container too large (n >= 63 would overflow)");
2095 const size_t total = 1ULL << n;
2096 result.reserve(total);
2098 for (
size_t mask = 0; mask < total; ++mask)
2100 std::vector<T> subset;
2101 for (
size_t i = 0; i < n; ++i)
2102 if (mask & (1ULL << i))
2103 subset.push_back(arr[i]);
2104 result.push_back(std::move(subset));
2130 template <
typename Container>
2133 using T =
typename Container::value_type;
2134 std::vector<std::vector<T>> result;
2136 if (n == 0)
return result;
2138 std::vector<T> arr(c.begin(), c.end());
2139 if (arr.size() < n)
return result;
2141 for (
size_t i = 0; i <= arr.size() - n; ++i)
2142 result.emplace_back(arr.begin() + i, arr.begin() + i + n);
2163 template <
typename Container>
2166 using T =
typename Container::value_type;
2167 std::vector<std::vector<T>> result;
2169 if (n == 0)
return result;
2171 std::vector<T> arr(c.begin(), c.end());
2173 for (
size_t i = 0; i < arr.size(); i += n)
2175 size_t end = std::min(i + n, arr.size());
2176 result.emplace_back(arr.begin() + i, arr.begin() + end);
2198 template <
typename T,
typename Container>
2201 std::vector<T> result;
2204 for (
const auto & item: c)
2207 result.push_back(sep);
2208 result.push_back(item);
2225 template <
typename Container>
2228 using T =
typename Container::value_type;
2230 std::vector<T> first, second;
2232 for (
const auto & item: c)
2235 first.push_back(item);
2237 second.push_back(item);
2241 return std::make_pair(std::move(first), std::move(second));
2256 template <
typename Pred,
typename Container>
2259 using T =
typename Container::value_type;
2261 std::vector<T> first, second;
2262 auto & pred_ref =
pred;
2265 for (
const auto & item: c)
2266 if (taking and pred_ref(item))
2267 first.push_back(item);
2271 second.push_back(item);
2274 return std::make_pair(std::move(first), std::move(second));
2286 template <
typename Container>
2289 using T =
typename Container::value_type;
2290 std::vector<T> arr(c.begin(), c.end());
2292 if (not arr.empty())
2307 template <
typename Container>
2310 using T =
typename Container::value_type;
2311 std::vector<T> result;
2314 for (
const auto & item: c)
2319 result.push_back(item);
2349 template <
typename Container>
2352 using T =
typename Container::value_type;
2354 std::vector<std::pair<T, size_t>> result;
2355 const size_t size = stl_detail::safe_size(c);
2358 if constexpr (!stl_detail::is_std_hashable_v<T>)
2361 for (
const auto & item : c)
2363 auto it = std::find_if(result.begin(), result.end(),
2364 [&item](
const auto & p) { return p.first == item; });
2365 if (it != result.end())
2368 result.emplace_back(item, 1);
2371 else if (
size <= stl_detail::ADAPTIVE_THRESHOLD)
2374 for (
const auto & item : c)
2376 auto it = std::find_if(result.begin(), result.end(),
2377 [&item](
const auto & p) { return p.first == item; });
2378 if (it != result.end())
2381 result.emplace_back(item, 1);
2387 std::unordered_map<T, size_t> counts;
2388 counts.reserve(
size);
2389 std::vector<T> order;
2390 order.reserve(
size);
2392 for (
const auto & item : c)
2394 auto [it, inserted] = counts.try_emplace(item, 0);
2397 order.push_back(item);
2400 result.reserve(order.size());
2401 for (
const auto & item : order)
2402 result.emplace_back(item, counts[item]);
2418 template <
typename Pred,
typename Container>
2421 using T =
typename Container::value_type;
2423 std::vector<T> result;
2424 auto & pred_ref =
pred;
2425 for (
const auto & item: c)
2426 if (not pred_ref(item))
2427 result.push_back(item);
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
C++20 Ranges support and adaptors for Aleph-w containers.
size_t size_t int32_t value
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
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.
bool ranges_any_of(const Container &c, Pred &&pred)
Fallback any_of using range-based for loop.
bool ranges_all_of(const Container &c, Pred &&pred)
Fallback all_of using range-based for loop.
bool arrangements_impl(const std::vector< T > &arr, size_t k, std::vector< T > ¤t, std::vector< bool > &used, Op &op_ref)
bool permutations_impl(std::vector< T > &arr, size_t start, Op &op_ref)
bool combinations_impl(const std::vector< T > &arr, size_t k, size_t start, std::vector< T > ¤t, Op &op_ref)
constexpr size_t ADAPTIVE_THRESHOLD
Threshold for switching from linear to hash-based algorithms.
constexpr bool is_std_hashable_v
void try_reserve_n(Result &result, size_t n)
Helper to reserve with a specific size if the result supports it.
size_t safe_size(const Container &c)
Helper to get container size safely (returns 0 for containers without size())
void try_reserve(Result &result, const Container &c)
Helper to reserve if possible.
constexpr bool has_reverse_iterators_v
constexpr bool has_size_v
Main namespace for Aleph-w library functions.
auto stl_first(const Container &c)
Get first element.
T stl_reduce(T init, Op &&op, const Container &c)
Alias for stl_foldl.
std::vector< T > stl_scan_left(T init, Op &&op, const Container &c)
Scan left - fold with all intermediate results.
bool stl_any(Pred &&pred, const Container &c)
Alias for stl_exists.
auto stl_span(Pred &&pred, const Container &c)
Split at predicate boundary (span in Haskell).
auto stl_take_last(size_t n, const Container &c)
Take last n elements.
auto stl_chunks(size_t n, const Container &c)
Split container into chunks of size n (each_slice in Ruby).
int stl_compare(const Container1 &c1, const Container2 &c2)
Compare two containers lexicographically.
auto stl_min_max(const Container &c)
Get both min and max in a single pass.
auto stl_last(const Container &c)
Get last element.
bool stl_traverse_arrangements(size_t k, Op &&op, const Container &c)
Traverse all k-arrangements (k-permutations) of a container.
auto stl_distinct(const Container &c)
Remove all duplicates (keeps first occurrence).
auto stl_max(const Container &c)
Get maximum element.
size_t size(Node *root) noexcept
void sort_range(Range &r, Cmp cmp)
Sort a whole range in place, portably across the ranges divide.
auto stl_flatten(const Container &c)
Flatten a container of containers.
auto stl_reject(Pred &&pred, const Container &c)
Filter out elements (reject in Ruby, opposite of filter).
auto stl_filter(Pred &&pred, const Container &c)
Filter elements satisfying predicate.
auto stl_arrangements(size_t k, const Container &c)
Generate all k-arrangements (k-permutations) of a container.
auto stl_drop(size_t n, const Container &c)
Drop first n elements, return the rest.
auto stl_enumerate_to_pairs(const Container &c)
Enumerate container (return pairs of index and element).
bool stl_equal(const Container1 &c1, const Container2 &c2)
Check equality of two containers.
auto stl_concat(const Container1 &c1, const Container2 &c2)
Concatenate two containers.
auto stl_combinations(size_t k, const Container &c)
Generate all k-combinations of a container.
auto stl_take_while(Pred &&pred, const Container &c)
Take elements while predicate is true.
auto stl_find_mapi(Op &&op, const Container &c)
Find and map with index (find_mapi in ML).
auto stl_nth(const size_t n, const Container &c)
Get n-th element.
auto stl_map(Op &&op, const Container &c)
Map operation - transform each element.
bool stl_mem(const T &target, const Container &c)
Check if element exists in container (mem in ML).
std::optional< size_t > stl_find_index(Pred &&pred, const Container &c)
Find index of first element satisfying predicate.
T stl_foldl(T init, Op &&op, const Container &c)
Left fold (foldl) - reduce from left to right.
bool all(Container &container, Operation &operation)
Return true if all elements satisfy a predicate.
auto stl_min_by(Key &&key, const Container &c)
Get minimum element by key function.
std::vector< T > stl_linspace(T start, T end, size_t n)
Generate n evenly spaced values between start and end.
and
Check uniqueness with explicit hash + equality functors.
bool stl_exists(Pred &&pred, const Container &c)
Check if any element satisfies predicate.
std::decay_t< typename HeadC::Item_Type > T
auto stl_take(size_t n, const Container &c)
Take first n elements.
auto stl_generate(size_t n, Gen &&gen)
Generate a vector using a generator function.
std::vector< T > stl_range(T start, T end, T step=1)
Generate a range of values [start, end] with given step.
auto stl_init(const Container &c)
Get all elements except the last (init in Haskell).
bool stl_traverse_permutations(Op &&op, const Container &c)
Traverse all permutations of a container.
size_t stl_count_value(const T &target, const Container &c)
Count occurrences of a value.
auto stl_sort(const Container &c)
Return sorted copy of container.
auto stl_permutations(const Container &c)
Generate all permutations of a container.
auto stl_tally(const Container &c)
Count occurrences of each element (tally in Ruby, frequencies).
bool stl_all(Pred &&pred, const Container &c)
Check if all elements satisfy predicate.
auto stl_partition(Pred &&pred, const Container &c)
Partition elements by predicate.
auto stl_unique(const Container &c)
Remove consecutive duplicates.
auto stl_mapi(Op &&op, const Container &c)
Map with index (mapi in ML).
size_t stl_count(Pred &&pred, const Container &c)
Count elements satisfying predicate.
void stl_for_each_indexed(Op &&op, const Container &c)
Apply operation to each element with index.
auto stl_sum(const Container &c)
Sum all elements.
auto stl_sliding_window(size_t n, const Container &c)
Sliding window of size n over container (each_cons in Ruby).
auto stl_max_by(Key &&key, const Container &c)
Get maximum element by key function.
auto stl_group_by(Key &&key, const Container &c)
Group elements by key function.
auto stl_min(const Container &c)
Get minimum element.
bool stl_none(Pred &&pred, const Container &c)
Check if no element satisfies predicate.
auto stl_reverse(const Container &c)
Return reversed copy of container.
auto stl_flat_map(Op &&op, const Container &c)
Flat map - map then flatten.
std::vector< T > stl_rep(size_t n, const T &value)
Generate a vector of n repeated values.
bool stl_traverse_combinations(size_t k, Op &&op, const Container &c)
Traverse all k-combinations of a container.
T stl_foldr(T init, Op &&op, const Container &c)
Right fold (foldr) - reduce from right to left.
std::vector< T > stl_scan_right(T init, Op &&op, const Container &c)
Scan right - right fold with all intermediate results.
auto stl_unzip_pairs(const Container &c)
Unzip pairs into two vectors.
auto stl_drop_while(Pred &&pred, const Container &c)
Drop elements while predicate is true, return the rest.
auto stl_intersperse(const T &sep, const Container &c)
Insert element between each pair (intersperse in Haskell).
auto stl_cartesian_product(const std::vector< std::vector< T > > &containers)
Generate cartesian product of multiple containers.
auto stl_product(const Container &c)
Product of all elements.
auto stl_tail(const Container &c)
Get all elements except the first (tail in Haskell).
auto stl_filteri(Pred &&pred, const Container &c)
Filter with index (filteri in ML).
auto stl_find(Pred &&pred, const Container &c)
Find first element satisfying predicate.
void stl_for_each(Op &&op, const Container &c)
Apply operation to each element (for_each).
static std::atomic< bool > init
auto stl_split_at(size_t n, const Container &c)
Split at position n, returning (take n, drop n) in one pass.
auto stl_sort_by(Cmp &&cmp, const Container &c)
Return sorted copy using custom comparator.
auto stl_power_set(const Container &c)
Generate power set (all subsets) of a container.
auto stl_group(const Container &c)
Group consecutive equal elements.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
auto stl_zip_to_pairs(const Container1 &c1, const Container2 &c2)
Zip two containers into pairs.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
auto stl_find_last(Pred &&pred, const Container &c)
Find last element satisfying predicate.
Detect if a container has reverse iterators.
Detect if a type has a size() method.
Detect if a type is hashable via std::hash.