28 #ifndef RANGELESS_FN_HPP_ 29 #define RANGELESS_FN_HPP_ 41 #if defined(DOXYGEN) || (defined(RANGELESS_FN_ENABLE_RUN_TESTS) && RANGELESS_FN_ENABLE_RUN_TESTS) 42 # define RANGELESS_FN_ENABLE_PARALLEL 1 43 # define RANGELESS_ENABLE_TSV 1 47 # pragma warning(push) 48 # pragma warning(disable: 4068) // unknown pragmas (for GCC diagnostic push) 52 #define RANGELESS_FN_THROW(msg) throw std::logic_error( std::string{} + __FILE__ + ":" + std::to_string(__LINE__) + ": "#msg ); 69 template<
typename IteratorTag,
typename Iterable>
72 static_assert(std::is_base_of<IteratorTag,
typename std::iterator_traits<typename Iterable::iterator>::iterator_category>::value,
"Iterator category does not meet minimum requirements.");
92 static_assert(!std::is_same<value_type, void>::value,
"Can't have void as value_type - did you perhaps forget a return-statement in your transform-function?");
98 maybe(
const maybe&) =
delete;
99 maybe& operator=(
const maybe&) =
delete;
103 reset(std::move(val));
109 reset(std::move(*other));
123 }
else if(!other.m_empty) {
124 reset(std::move(*other));
175 new (&m_value) T(std::move(val));
183 this->operator*().~T();
188 explicit operator bool() const noexcept
193 T& operator*() noexcept
197 #if __cplusplus >= 201703L 198 return *std::launder(&m_value);
217 const T& operator*() const noexcept
221 #if __cplusplus >= 201703L 222 return *std::launder(&m_value);
237 return {
fn(std::move(**
this)) };
327 #if 0 // MSVC 19.15 does not support noreturn 329 [[ noreturn ]]
operator T()
const 351 template<
typename Gen>
383 std::function<impl::maybe<value_type>()>
gen;
393 template<
typename G,
typename T>
400 template<
typename G,
typename T>
409 template<
typename Gen>
427 static_assert(!std::is_reference<value_type>::value,
"The type returned by the generator-function must be a value-type. Use std::ref if necessary.");
430 : m_gen( std::move(gen) )
443 template<
typename OtherGen>
445 : m_current{ std::move(other.m_current) }
446 , m_gen{ std::move(other.m_gen) }
447 , m_started{ other.m_started }
448 , m_ended{ other.m_ended }
449 , m_resumable{ other.m_resumable }
452 other.m_started =
true;
453 other.m_ended =
true;
477 if(!m_parent || m_parent->m_ended) {
488 p.m_current = p.m_gen();
497 #pragma GCC diagnostic push 498 #pragma GCC diagnostic ignored "-Weffc++" // insists operator++(int) should be returning iterator 501 auto ret = std::move(m_parent->m_current);
505 #pragma GCC diagnostic pop 516 return m_parent == other.m_parent;
521 return m_parent != other.m_parent;
534 if(m_started && !m_resumable) {
535 RANGELESS_FN_THROW(
"seq::begin() can only be called once per instance. Set resumable(true) to override.");
538 auto it =
iterator{ m_ended ? nullptr :
this };
540 if(!m_started && !m_ended) {
583 operator std::vector<value_type>() &&
588 std::vector<value_type> ret{};
591 ret.push_back(std::move(*m_current));
595 for(
auto x = m_gen(); x; x = m_gen()) {
596 ret.push_back(std::move(*x));
619 bool m_started =
false;
620 bool m_ended =
false;
621 bool m_resumable =
false;
625 template<
typename Iterable>
676 template<
typename NullaryInvokable>
679 static_assert(!std::is_reference<decltype(gen_fn())>::value,
"The type returned by gen_fn must be a value-type.");
680 static_assert(!std::is_same<decltype(gen_fn()),
void>::value,
"You forgot a return-statement in your gen-function.");
681 return { { std::move(gen_fn),
false } };
686 template<
typename Iterable>
690 impl::require_iterator_category_at_least<std::forward_iterator_tag>(src);
692 return { { src, src.begin() } };
711 return std::less<T>{}(a, b);
716 const std::reference_wrapper<T>& b)
const 718 return std::less<T>{}(a.get(), b.get());
732 const std::reference_wrapper<T>& b)
const 734 return a.get() == b.get();
741 return (
lt{}(a, b) ? -1
762 return std::less<T>{}(other.
val, this->
val);
768 return other.
val == this->
val;
772 template<
typename Arg>
786 template<
typename A,
typename B>
847 return std::get<U>(x);
913 return { std::move(x) };
929 return { std::move(key_fn) };
939 auto operator()(P ptr)
const ->
typename std::remove_reference<decltype(std::move(*ptr))>::type
941 return std::move(*ptr);
950 return std::move(x.first);
959 return std::move(x.second);
970 return {
i++, std::move(x) };
980 template<
typename Iterator>
989 : it_beg( std::move(b) )
990 , it_end( std::move(e) )
998 Iterator
begin()
const {
return it_beg; }
999 Iterator
end()
const {
return it_end; }
1014 }
else if(e == it_end) {
1017 impl::require_iterator_category_at_least<std::forward_iterator_tag>(*
this);
1032 return it_beg == it_end;
1041 template<
typename Iterator>
1044 return { std::move(it_beg), std::move(it_end) };
1048 template<
typename Iterator>
1051 return { std::move(p.first), std::move(p.second) };
1055 template<
typename Iterable,
1056 typename Iterator =
typename Iterable::iterator>
1061 return { begin(src), end(src) };
1064 template<
typename Iterable,
1065 typename Iterator =
typename Iterable::const_iterator>
1074 return { begin(src), end(src) };
1078 template<
typename Iterable,
1079 typename Iterator =
typename Iterable::const_iterator>
1084 return { begin(src), end(src) };
1110 template<
typename Iterable>
1138 return { std::move(*
it) };
1144 template<
typename Gen>
1151 template<
typename Iterable>
1154 return { { std::move(src) , {},
false } };
1163 template<
typename T>
1170 template<
typename Gen,
1171 typename Vec = std::vector<typename seq<Gen>::value_type>>
1174 return static_cast<Vec>(std::move(r));
1178 template<
typename Iterable,
1179 typename Vec = std::vector<typename Iterable::value_type> >
1188 std::make_move_iterator(src.begin()),
1189 std::make_move_iterator(src.end()) });
1202 template<
typename Key,
1204 typename Vec = std::vector<std::pair<Key, Value>>>
1208 v.reserve(m.size());
1210 #if __cplusplus >= 201703L 1212 auto h = m.extract(m.begin());
1213 v.emplace_back(std::move(h.key()),
1214 std::move(h.mapped()));
1217 for(
auto it = m.begin(), it_end = m.end();
1221 v.emplace_back(std::move(it->first),
1222 std::move(it->second));
1230 template<
typename Container>
1239 return std::move(src);
1242 for(
auto&& x : src) {
1243 dest.insert(
dest.end(), std::move(x));
1245 return std::move(
dest);
1249 template<
typename Iterable>
1255 std::make_move_iterator(src.begin()),
1256 std::make_move_iterator(src.end()));
1258 for(
auto&& x : src) {
1259 dest.insert(
dest.end(), std::move(x));
1262 return std::move(
dest);
1269 template<
typename Iterable>
1270 std::map<typename Iterable::value_type, size_t>
operator()(Iterable&& xs)
const 1272 auto ret = std::map<typename Iterable::value_type, size_t>{};
1273 for(
auto&& x : xs) {
1281 template<
typename Pred>
1295 return std::move(*
this);
1298 template<
typename Iterable>
1301 for(
const auto& x : iterable)
1315 template<
typename F>
1320 template<
typename Iterable>
1323 for(
auto it = src.begin(); it != src.end(); ++it) {
1343 template<
typename Gen>
1353 template<
typename F2>
1358 template<
typename Iterable>
1361 impl::require_iterator_category_at_least<std::forward_iterator_tag>(src);
1363 auto it2 = src.begin();
1364 if(it2 == src.end()) {
1370 for(; it2 != src.end(); it1 = it2, ++it2) {
1378 template<
typename Ret,
typename Op>
1384 template<
typename Iterable>
1388 static_assert(std::is_same<Ret, decltype(
fold_op(std::move(
init), *src.begin()))>::value,
1389 "Type of Init must be the same as the return-type of F");
1391 for(
auto it = src.begin(); it != src.end(); ++it) {
1399 return std::move(
init);
1403 template<
typename Gen>
1406 for(
auto x = src.get_gen()(); x; x = src.get_gen()()) {
1410 return std::move(
init);
1415 template<
typename Op>
1422 template<
typename T>
1426 template<
typename Iterable>
1429 using ret_t = decltype(
fold_op(
any(), *src.begin()));
1432 for(
auto it = src.begin(); it != src.end(); ++it) {
1433 ret =
fold_op(std::move(ret), *it);
1441 template<
typename Gen>
1444 using ret_t = decltype(
fold_op(
any(), std::move(*src.get_gen()())));
1447 for(
auto x = src.get_gen()(); x; x = src.get_gen()()) {
1448 ret =
fold_op(std::move(ret), std::move(*x));
1457 template<
typename F>
1462 template<
typename Iterable>
1465 auto it = src.begin();
1466 auto it_end = src.end();
1474 for(++it; it != it_end; ++it) {
1475 init =
fold_op(std::move(init), *it);
1482 template<
typename Gen>
1485 auto x1 = src.get_gen()();
1491 auto init = std::move(*x1);
1493 for(
auto x = src.get_gen()(); x; x = src.get_gen()()) {
1494 init =
fold_op(std::move(init), std::move(*x));
1507 #define RANGELESS_FN_OVERLOAD_FOR_SEQ(...) \ 1508 template<typename InGen> \ 1509 auto operator()(seq<InGen> in) const -> seq<gen<InGen>> \ 1511 return { { std::move(in.get_gen()), __VA_ARGS__ } }; \ 1519 #define RANGELESS_FN_OVERLOAD_FOR_CONT(...) \ 1520 template<typename Cont> \ 1521 auto operator()(Cont cont) const -> seq<gen<to_seq::gen<Cont>>> \ 1523 return { { { std::move(cont), { }, false }, __VA_ARGS__ } }; \ 1532 #define RANGELESS_FN_OVERLOAD_FOR_VIEW(...) \ 1533 template<typename Iterator> \ 1534 auto operator()(view<Iterator> v) const \ 1535 -> seq<gen<to_seq::gen<view<Iterator>>>> \ 1537 return { { { std::move(v), { }, false }, __VA_ARGS__ } }; \ 1541 template<
typename F>
1546 template<
typename InGen>
1554 static_assert(!std::is_same<value_type, void>::value,
"You forgot a return-statement in your transform-function.");
1566 auto ret =
map_fn(std::move(*x));
1568 return std::move(ret);
1587 template<
typename Iterable>
1604 win_beg = cont.begin();
1605 win_end = cont.begin();
1609 for(
size_t i = 0; i < win_size && win_end != cont.end(); ++i) {
1621 if(win_end == cont.end()) {
1628 return { { win_beg, win_end } };
1632 template<
typename Iterable>
1635 impl::require_iterator_category_at_least<std::forward_iterator_tag>(inps);
1637 return { { std::move(inps),
1646 template<
typename InGen>
1651 using inp_t =
typename InGen::value_type;
1661 if(!queue.empty()) {
1665 while(queue.size() < win_size) {
1670 queue.push_back(std::move(*x));
1673 return { { queue.begin(), queue.end() } };
1684 Note: leaving the original implementation
for reference.
1685 template<
typename F>
1690 template<
typename Gen>
1703 return fn(std::ref(gen));
1722 template<
typename F>
1727 template<
typename InGen>
1733 using inp_t =
typename InGen::value_type;
1752 auto ret = std::move(*parent->inp);
1757 explicit operator bool()
const 1761 return bool(parent->inp);
1800 template<
typename Pred>
1805 template<
typename InGen>
1816 if(found_unsatisfying) {
1822 found_unsatisfying =
true;
1825 return std::move(x);
1831 template<typename Cont>
1832 Cont operator()(Cont cont)
const 1834 auto it = std::find_if_not(cont.begin(), cont.end(), pred);
1835 cont.erase(it, cont.end());
1845 template<
typename Gen>
1849 std::vector<typename seq<Gen>::value_type> queue;
1855 for(
auto x = r.get_gen()(); x; x = r.get_gen()()) {
1860 queue.push_back(std::move(*x));
1862 queue[i % cap] = std::move(*x);
1869 auto it = queue.begin();
1870 std::advance(it, i % cap);
1871 std::rotate(queue.begin(), it, queue.end());
1877 template<
typename Iterable>
1881 static_assert(std::is_rvalue_reference<Iterable&&>::value,
"");
1884 impl::require_iterator_category_at_least<std::forward_iterator_tag>(inps);
1885 const auto size = size_t(std::distance(inps.begin(), inps.end()));
1888 auto it = inps.begin();
1889 std::advance(it, size - cap);
1890 inps.erase(inps.begin(), it);
1892 return std::move(inps);
1895 template<
typename Cont>
1900 if(cap < cont.size()) {
1901 auto it = cont.begin();
1902 std::advance(it, cont.size() - cap);
1903 ret.insert(ret.end(), it, cont.end());
1914 template<
typename InGen>
1928 if(queue.capacity() < cap) {
1937 queue.push_back(std::move(*x));
1941 auto& dest = queue[i++ % cap];
1942 auto ret = std::move(dest);
1947 dest = std::move(*x);
1948 return { std::move(ret) };
1955 template<typename Iterable>
1956 Iterable
operator()(Iterable&& inps)
const 1959 static_assert(std::is_rvalue_reference<Iterable&&>::value,
"");
1962 impl::require_iterator_category_at_least<std::forward_iterator_tag>(inps);
1963 const auto size = size_t(std::distance(inps.begin(), inps.end()));
1966 auto it = inps.begin();
1967 std::advance(it, size - n);
1968 inps.erase(it, inps.end());
1973 return std::move(inps);
1977 template<
typename Cont>
1982 if(n < cont.size()) {
1983 auto it = cont.begin();
1984 std::advance(it, cont.size() - n);
1985 ret.insert(ret.end(), cont.begin(), it);
1993 template<
typename Pred>
1998 template<
typename InGen>
2010 while(!found_unsatisfying && x && pred(*x)) {
2014 found_unsatisfying =
true;
2021 template<typename Iterable>
2022 Iterable operator()(Iterable inps)
const 2024 auto it = std::find_if_not(inps.begin(), inps.end(), pred);
2025 inps.erase(inps.begin(), it);
2037 template<
typename T>
2040 return num_calls++ < cap;
2045 template<
typename Pred>
2055 template<
typename InGen>
2063 static_assert(std::is_same<decltype(pred(*
gen())),
bool>::value,
"The return value of predicate must be convertible to bool.");
2072 while(x && !pred(*x)) {
2087 template<
typename Cont>
2091 auto pred_copy = pred;
2092 std::copy_if(cont.begin(),
2094 std::inserter(ret, ret.end()),
2101 template<
typename Cont>
2104 const Cont& const_cont = cont;
2112 template<
typename Cont>
2115 static_assert(std::is_rvalue_reference<Cont&&>::value,
"");
2118 return std::move(cont);
2123 template<
typename Cont>
2124 void x_EraseRemove(Cont& cont)
const 2126 auto pred_copy = pred;
2129 cont.begin(), cont.end(),
2130 [&pred_copy](
const typename Cont::value_type& x)
2132 return !pred_copy(x);
2142 template<
typename Cont>
2143 auto x_EraseFrom(Cont& cont, pr_high)
const -> decltype(
void(cont.front()))
2174 x_EraseRemove(cont);
2181 template<
typename Iterator>
2182 void x_EraseFrom(view<Iterator>& v, pr_high)
const 2184 impl::require_iterator_category_at_least<std::random_access_iterator_tag>(v);
2192 template<
typename Cont>
2193 auto x_EraseFrom(Cont& cont, pr_low)
const 2196 std::declval<typename Cont::key_type const&>())))
2198 auto pred_copy = pred;
2199 for(
auto it = cont.begin(), it_end =cont.end();
2201 it = pred_copy(*it) ? std::next(it)
2208 template<
typename NotACont>
2209 static void x_EraseFrom(NotACont&, pr_lowest)
2211 static_assert(
sizeof(NotACont) == 0,
"The argument to fn::impl::where is expected to be either a seq<...> or a sequence container or an associative container having equal_range method.");
2212 TheTypeInQuestionIs<NotACont>{};
2217 template<
typename SortedRange,
typename F>
2220 const SortedRange&
r;
2226 return is_subtract ^ std::binary_search(r.begin(), r.end(), x,
comp);
2231 template<
typename F>
2241 template<
typename InGen,
2242 typename Ret =
typename std::vector<typename seq<InGen>::value_type> >
2247 auto& gen = in.get_gen();
2249 for(
auto x = gen(); x; x = gen()) {
2251 const auto which = ret.empty() ? 0
2253 key_fn(*x)) * use_max;
2256 ret.push_back(std::move(*x));
2258 }
else if(which > 0) {
2261 ret.push_back(std::move(*x));
2265 if(ret.capacity() >= ret.size() * 2) {
2266 ret.shrink_to_fit();
2273 template<
typename Cont,
2274 typename Ret = std::vector<typename Cont::value_type> >
2309 auto first_best_it = cont.begin();
2310 auto last_best_it = cont.begin();
2314 auto it = cont.begin();
2315 for(++it; it != cont.end(); ++it) {
2317 key_fn(*first_best_it)) * use_max;
2320 }
else if(which > 0) {
2322 first_best_it = last_best_it = it;
2332 ret.push_back(std::move(*first_best_it));
2336 for(
auto it = first_best_it; it != last_best_it; ++it)
2338 key_fn(ret.back())) * use_max >= 0)
2340 ret.push_back(std::move(*it));
2345 #if 0 // An example of what NOT to do: 2346 auto best_key = key_fn(*cont.begin());
2347 for(
const auto& e : cont) {
2348 auto key = key_fn(e);
2350 best_key = std::move(key);
2356 [&,
this](
const typename Ret::value_type& x)
2359 })(std::forward<Cont>(cont));
2370 template<
typename Gen>
2379 template<
typename Iterable>
2383 using value_type =
typename Iterable::value_type;
2384 using iterator =
typename Iterable::reverse_iterator;
2385 using const_iterator =
typename Iterable::const_reverse_iterator;
2389 return src.rbegin();
2397 const_iterator begin()
const 2399 return src.rbegin();
2402 const_iterator end()
const 2407 const_iterator cbegin()
const 2409 return src.crbegin();
2412 const_iterator cend()
const 2418 template<
typename Iterable>
2419 reversed<Iterable>
operator()(Iterable src)
const 2421 return reversed<Iterable>{ std::move(src) };
2424 #else // The above approach is more clever, and works for all containers that support bidirectional iteration. 2430 template<
typename ReversibleContainer>
2431 auto operator()(ReversibleContainer cont)
const -> ReversibleContainer
2438 template<
typename Iterator>
2441 impl::require_iterator_category_at_least<std::bidirectional_iterator_tag>(v);
2443 using rev_it_t = std::reverse_iterator<Iterator>;
2444 return { rev_it_t{ v.
end() },
2445 rev_it_t{ v.
begin() } };
2470 template<
typename F,
typename SortTag = stable_sort_tag>
2475 template<
typename Gen>
2481 template<
typename Iterable>
2484 impl::require_iterator_category_at_least<std::random_access_iterator_tag>(src);
2488 static_assert(std::is_move_assignable<typename Iterable::value_type>::value,
"value_type must be move-assignable.");
2491 [
this](
const typename Iterable::value_type& x,
2492 const typename Iterable::value_type& y)
2494 return lt{}(key_fn(x), key_fn(y));
2502 template<
typename Iterable,
typename Comp>
2505 std::stable_sort(src.begin(), src.end(), std::move(
comp));
2508 template<
typename Iterable,
typename Comp>
2509 static void s_sort(Iterable& src, Comp comp, unstable_sort_tag)
2511 std::sort(src.begin(), src.end(), std::move(comp));
2528 template<
typename F>
2533 template<
typename InGen>
2542 static_assert(std::is_move_assignable<value_type>::value,
"value_type must be move-assignable.");
2552 return lt{}(key_fn(y), key_fn(x));
2556 assert(heap.empty());
2561 for(
auto x =
gen(); x; x =
gen()) {
2562 heap.push_back(std::move(*x));
2565 std::make_heap(heap.begin(), heap.end(), op_gt);
2572 std::pop_heap(heap.begin(), heap.end(), op_gt);
2573 auto ret = std::move(heap.back());
2575 return { std::move(ret) };
2584 template<
typename F>
2590 template<
typename Iterable>
2591 auto operator()(Iterable src)
const -> std::vector<typename Iterable::value_type>
2598 using value_type =
typename Iterable::value_type;
2602 static_assert(std::is_move_assignable<value_type>::value,
"value_type must be move-assignable.");
2604 auto op_gt = [
this](
const value_type& x,
2605 const value_type& y)
2607 return lt{}(key_fn(y), key_fn(x));
2614 std::vector<value_type> heap{};
2624 const auto& key_x = key_fn(x);
2625 const auto& key_h = key_fn(heap.front());
2630 return lt{}(key_x, key_h) ?
false 2631 :
lt{}(key_h, key_x) ?
true 2639 if(heap.size() >= cap) {
2640 std::pop_heap(heap.begin(), heap.end(), op_gt);
2644 heap.push_back(std::move(x));
2645 std::push_heap(heap.begin(), heap.end(), op_gt);
2648 std::sort_heap(heap.begin(), heap.end(), op_gt);
2656 template<
typename F,
typename BinaryPred = impl::eq>
2673 template<
typename InGen>
2680 using inp_t =
typename InGen::value_type;
2682 using value_type =
typename std::conditional<
2683 std::is_same<inp_t, char>::value,
2685 std::vector<inp_t> >::type;
2687 static_assert(std::is_move_assignable<value_type>::value,
"value_type must be move-assignable.");
2699 garbage = std::move(grbg);
2707 auto curr = std::move(next);
2708 next = std::move(garbage);
2711 for(
auto x =
gen(); x; x =
gen()) {
2712 if(curr.empty() || pred2(key_fn(curr.back()), key_fn(*x))) {
2713 curr.push_back(std::move(*x));
2715 next.push_back(std::move(*x));
2724 return std::move(curr);
2734 template<typename Cont>
2735 auto operator()(Cont cont)
const -> std::vector<Cont>
2740 std::vector<Cont> ret;
2742 auto it = cont.begin();
2743 const auto it_end = cont.end();
2749 ret.push_back(Cont{});
2750 ret.back().insert(ret.back().end(), std::move(*it));
2753 for(; it != it_end; ++it) {
2754 if(!pred2(key_fn(*ret.back().crbegin()),
2757 ret.push_back(Cont{});
2759 auto& dest = ret.back();
2760 dest.insert(dest.end(), std::move(*it));
2769 template<
typename F,
typename BinaryPred = impl::eq>
2775 template<
typename InGen>
2787 return parent->next();
2806 if(!current || reached_subend) {
2807 reached_subend =
true;
2811 auto next = in_gen();
2812 reached_subend = !next || !pred2(key_fn(*current), key_fn(*next));
2813 std::swap(current, next);
2814 return std::move(next);
2827 while(!reached_subend) {
2836 reached_subend =
false;
2837 return {
subgen{
this } };
2854 template<
typename T>
2863 return ++n_calls/2/chunk_size;
2868 template<
typename F>
2886 template<
typename Gen>
2889 typename group_adjacent_by_t::template gen<
2891 std::vector<typename seq<Gen>::value_type>>>>
2898 std::move(range)))));
2902 template<
typename Cont>
2915 using key_t = remove_cvref_t<decltype(key_fn(*cont.begin()))>;
2916 std::map<key_t, Cont, lt_t> m;
2917 for(
auto&& x : cont) {
2918 auto& dest = m[key_fn(x)];
2919 dest.insert(dest.end(), std::move(x));
2925 std::vector<Cont> ret;
2926 ret.reserve(m.size());
2928 ret.push_back(std::move(kv.second));
2938 return group_adjacent_by_t{ key_fn, {} }(
2939 impl::sort_by<F>{ key_fn }(
2971 template<
typename InGen>
2988 #if 0 // We don't really need this 2993 gen& operator=(
gen&&) =
default;
2996 gen& operator=(
const gen&) =
delete;
2997 gen(
const gen&) =
delete;
3003 while(!current_group || it == (*current_group).end()) {
3004 current_group =
gen();
3006 if(!current_group) {
3010 it = (*current_group).begin();
3016 return { std::move(ret) };
3025 template<
typename Iterable,
3026 typename Ret =
typename Iterable::value_type>
3027 Ret
operator()(Iterable src)
const 3034 for(
auto&& v : src) {
3035 ret.insert(ret.end(),
3036 std::make_move_iterator(v.begin()),
3037 std::make_move_iterator(v.end()));
3046 template<
typename Gen>
3054 return { { { std::move(vec_of_seqs) } } };
3060 template<
typename F>
3065 template<
typename InGen>
3080 auto curr = std::move(next);
3083 for(
auto x =
gen(); x; x =
gen()) {
3085 curr = std::move(x);
3086 }
else if(
impl::eq{}(key_fn(*curr), key_fn(*x))) {
3089 next = std::move(x);
3100 template<typename Iterable>
3101 Iterable
operator()(Iterable inps)
const 3103 impl::require_iterator_category_at_least<std::forward_iterator_tag>(inps);
3107 inps.begin(), inps.end(),
3108 [
this](
const typename Iterable::value_type& x,
3109 const typename Iterable::value_type& y)
3111 return impl::eq{}(key_fn(x), key_fn(y));
3122 template<
typename F>
3127 template<
typename InGen>
3135 using key_t =
typename std::decay<decltype(key_fn(*
gen()))>::type;
3139 static_assert(std::is_default_constructible<key_t>::value,
"The type returned by key_fn in unique_all_by must be default-constructible and have the lifetime independent of arg.");
3158 auto k = key_fn(*x);
3160 while(!seen.emplace(std::move(k),
true).second) {
3174 template<typename Iterable>
3175 auto operator()(Iterable src)
const 3181 return unique_adjacent_by<F>{ key_fn }(
3182 sort_by<F>{ key_fn }(
3191 template<
typename Iterable2>
3196 template<
typename Iterable1>
3201 typename Iterable1::iterator
it1;
3202 typename Iterable2::iterator
it2;
3207 typename std::common_type<
3208 typename Iterable1::value_type,
3209 typename Iterable2::value_type
3214 return which == 1 && it1 != inps1.end() ? std::move(*it1++)
3215 : which == 2 && it2 != inps2.end() ? std::move(*it2++)
3216 : which == 0 ? (which = 1, it1 = inps1.begin(), (*this)())
3217 : which == 1 ? (which = 2, it2 = inps2.begin(), (*this)())
3222 template<
typename Iterable1>
3225 return { { std::move(src1), std::move(src2), {}, {}, 0 } };
3230 template<
typename Iterable2,
typename BinaryFn>
3236 template<
typename Iterable1>
3242 typename Iterable1::iterator
it1;
3243 typename Iterable2::iterator
it2;
3257 if(it1 == src1.end() || it2 == src2.end()) {
3261 auto ret =
fn(std::move(*it1), std::move(*it2));
3264 return { std::move(ret) };
3268 template<
typename Iterable1>
3271 return { { std::move(
fn), std::move(src1), std::move(src2), {}, {},
false } };
3276 template<
typename BinaryFn>
3281 template<
typename Iterable>
3286 typename Iterable::iterator
it;
3298 auto prev_it = it == src.end() ? it : it++;
3300 if(it != src.end()) {
3301 return {
fn(*prev_it, *it) };
3308 template<
typename Iterable>
3311 impl::require_iterator_category_at_least<std::forward_iterator_tag>(src);
3312 return { { std::move(
fn), std::move(src), {},
false } };
3317 template<
typename Iterable2,
typename BinaryFn>
3323 template<
typename Iterable1>
3329 typename Iterable1::iterator
it1;
3330 typename Iterable2::iterator
it2;
3337 static_assert(!std::is_rvalue_reference<decltype(*--it1)>::value,
"For cartesian-product expecting upstream iterable to be a bidirectional range yielding lvalue-references or values");
3338 static_assert(!std::is_rvalue_reference<decltype(*--it2)>::value,
"For cartesian-product expecting parameter-iterable to be a bidirectional range yielding lvalue-references or values");
3348 if(it1 == src1.end() || it2 == src2.end()) {
3353 while(it2 == src2.end()) {
3357 if(it1 == src1.end()) {
3362 auto ret =
fn(*it1, *it2);
3364 return { std::move(ret) };
3368 template<
typename Iterable1>
3371 return { { std::move(
fn), std::move(src1), std::move(src2), {}, {},
false } };
3379 template<
class Ret,
class Arg>
3392 template<
class Ret,
class Class,
class Arg>
3398 template<
typename F>
3402 using Arg =
typename std::remove_reference<typename traits::arg>::type;
3403 using Ret =
typename traits::ret;
3413 auto it = m.find(arg);
3414 return it != m.end() ? it->second
3415 : m.emplace(arg,
fn(arg)).first->second;
3420 template<
typename F>
3443 template<
typename T>
3449 template<
typename Gen,
typename T =
typename Gen::value_type>
3452 return { std::move(
seq) };
3475 template<
typename Container>
3478 return { std::move(dest) };
3656 template<
typename F>
3659 return { std::move(
fn) };
3669 template<
typename F>
3686 return { std::move(
map_fn) };
3691 template<
typename F,
typename... Fs>
3694 return { impl::compose(std::move(
fn), std::move(fns)...) };
3728 template<
typename Result,
typename Op>
3738 return { std::move(init), std::move(binary_op) };
3756 template<
typename Op>
3759 return { std::move(binary_op) };
3777 template<
typename Op>
3780 return { std::move(binary_op) };
3803 return { win_size };
3810 template<
typename F>
3813 return { std::move(
fn) };
3820 template<
typename F2>
3823 return { std::move(fn2) };
3831 template<
typename P>
3834 return { std::move(pred) };
3840 return {{ n, 0UL }};
3852 template<
typename P>
3855 return { std::move(pred) };
3861 return {{ n, 0UL }};
3902 template<
typename P>
3905 return { std::move(pred) };
3909 template<
typename SortedForwardRange,
typename F>
3912 return { { r,
false, { std::move(key_fn) } } };
3919 template<
typename SortedForwardRange>
3922 return { { r,
false, { { } } } };
3926 template<
typename SortedForwardRange,
typename F>
3929 return { { r,
true, { std::move(key_fn) } } };
3936 template<
typename SortedForwardRange>
3939 return { { r,
true, { { } } } };
3967 template<
typename F>
3970 return { std::move(key_fn), 1 };
3980 template<
typename F>
3983 return { std::move(key_fn), -1 };
3996 template<
typename Pred>
3999 return { std::move(p),
true };
4032 template<
typename F>
4035 return { std::move(key_fn) };
4058 template<
typename F>
4061 return { std::move(key_fn), {} };
4085 template<
typename F>
4088 return { std::move(key_fn), {} };
4106 template<
typename BinaryPred>
4109 return { {}, std::move(pred2) };
4113 template<
typename BinaryPred>
4116 return { {}, std::move(pred2) };
4173 template<
typename F>
4176 return { std::move(key_fn) };
4186 template<
typename F>
4189 return { std::move(key_fn) };
4206 template<
typename F>
4209 return { std::move(key_fn) };
4225 template<
typename F>
4228 return { std::move(key_fn), n };
4250 template<
typename F>
4253 return { std::move(key_fn) };
4269 template<
typename F>
4272 return { std::move(key_fn) };
4306 template<
typename Iterable>
4309 return { std::move(next) };
4325 template<
typename Iterable,
typename BinaryFn>
4334 return { std::move(second), std::move(
fn) };
4338 template<
typename BinaryFn>
4341 return { std::move(
fn) };
4345 template<
typename Iterable,
typename BinaryFn>
4348 return { std::move(second), std::move(
fn) };
4369 template<
typename Container,
typename P>
4370 auto get_unique(Container& container, P&& pred) -> decltype(*container.begin())
4372 auto best_it = container.end();
4375 for(
auto it = container.begin(),
4376 it_end = container.end();
4388 + std::to_string(n) +
".");
4412 template<
typename Container,
typename P,
typename Construct>
4413 auto set_unique(Container& container, P&& pred, Construct&& con) -> decltype(*container.begin())
4415 auto best_it = container.end();
4418 for(
auto it = container.begin(),
4419 it_end = container.end();
4430 best_it = container.insert(container.end(), con());
4432 if(!pred(*best_it)) {
4439 + std::to_string(n) +
".");
4449 template<
typename Container>
4452 return c.begin() == c.end() ?
typename Container::value_type{} : *c.begin();
4455 template<
typename Container,
typename Pred>
4458 auto it = std::find_if(c.begin(), c.end(), std::forward<Pred>(pred));
4459 return it == c.end() ?
typename Container::value_type{} : *it;
4462 template<
typename Container>
4465 return c.rbegin() == c.rend() ?
typename Container::value_type{} : *c.rbegin();
4468 template<
typename Container,
typename Pred>
4471 auto it = std::find_if(c.rbegin(), c.rend(), std::forward<Pred>(pred));
4472 return it == c.rend() ?
typename Container::value_type{} : *it;
4491 template<
typename F>
4494 return { std::move(
fn), {} };
4513 template<
typename F>
4516 return { std::move(
fn),
false };
4536 #if 0 && (defined(__GNUC__) || defined(__clang__)) 4537 __attribute__ ((warn_unused_result))
4547 template<
typename Arg,
typename F>
4548 auto operator % (Arg&& arg, F&&
fn) -> decltype( std::forward<F>(
fn)(std::forward<Arg>(arg)) )
4551 return std::forward<F>(
fn)(std::forward<Arg>(arg));
4560 template<
typename Arg,
typename F>
4561 auto operator %= (Arg& arg, F&&
fn) -> decltype(
void(std::forward<F>(
fn)(std::move(arg))))
4566 arg =
fn::to(Arg{})(std::forward<F>(
fn)(std::move(arg)));
4583 template<
class Container1,
class Container2>
4585 Container2&& cont2) -> decltype(
void(cont1.insert(cont1.end(), std::move(*cont2.begin()))))
4587 static_assert(std::is_rvalue_reference<Container2&&>::value,
"");
4588 cont1.insert(cont1.end(),
4589 std::make_move_iterator(cont2.begin()),
4590 std::make_move_iterator(cont2.end()));
4599 template<
class Container1,
class Container2>
4601 const Container2& cont2) -> decltype(
void(cont1.insert(cont1.end(), *cont2.begin())))
4603 cont1.insert(cont1.end(),
4612 template<
class Container1,
class Gen>
4615 cont1.insert(cont1.end(),
seq.begin(),
seq.end());
4618 template<
class Container>
4621 cont.insert(cont.end(), std::move(el));
4630 #if RANGELESS_ENABLE_TSV 4646 std::string header =
"";
4655 std::string filename =
"";
4657 bool skip_comments =
true;
4658 bool truncate_blanks =
true;
4659 bool skip_empty =
true;
4669 , m_params{ std::move(p) }
4675 throw std::runtime_error(
"Stream " + m_params.filename +
" is not in good state before reading.");
4679 while(std::getline(m_istr, m_line))
4686 || (m_istr.fail() && !m_istr.eof())
4689 throw std::runtime_error(
"Stream " + m_params.filename +
" terminated abnormally.");
4698 std::istream& m_istr;
4700 bool m_found_header =
false;
4701 std::string m_line =
"";
4706 if(!m_line.empty() && m_line.back() ==
'\r') {
4710 const bool is_comment = !m_line.empty() && m_line[0] ==
'#';
4712 if( !m_params.
header.empty()
4714 && m_line == m_params.
header)
4716 m_found_header =
true;
4722 while(!m_line.empty() && m_line.back() ==
' ') {
4727 while(i < m_line.size() && m_line[i] ==
' ') {
4734 || (m_params.
skip_comments && !m_line.empty() && m_line[0] ==
'#'))
4740 if( !m_line.empty() && !is_comment
4741 && !m_params.
header.empty() && !m_found_header)
4743 throw std::runtime_error(
4744 "Did not find expected header: '" 4759 const bool m_truncate_blanks;
4765 , m_truncate_blanks{ truncate_blanks }
4773 ret.resize(
size_t(1 + std::count(line.begin(), line.end(), m_delim)));
4776 auto capture_next = [&](
size_t b,
size_t e)
4778 if(e == std::string::npos) {
4782 while(m_truncate_blanks && b < e && line[b] ==
' ') {
4785 while(m_truncate_blanks && b < e && line[e-1] ==
' ') {
4789 ret[i++].assign(line, b, e - b);
4792 size_t start_pos = 0, end_pos = 0;
4795 end_pos = line.find(m_delim, start_pos);
4796 capture_next(start_pos, end_pos);
4797 start_pos = end_pos + 1;
4798 }
while(end_pos != std::string::npos);
4808 auto operator()(
const std::string& line) & -> std::reference_wrapper<const tsv::row_t>
4810 m_row = std::move(*
this)(line, std::move(m_row));
4834 return fn::transform( split_on_delim{ delim, params.truncate_blanks } )(
4835 fn::seq( get_next_line{ istr, std::move(params) }) );
4859 , m_end{ m_beg + std::strlen(str) }
4862 template<
typename Str>
4864 : m_beg{ str.begin() == str.end() ? nullptr : &*str.begin() }
4865 , m_end{ str.begin() == str.end() ? nullptr : &*str.begin() + str.size() }
4869 template<typename Enum, typename std::enable_if<std::is_enum<Enum>::value>::type* =
nullptr>
4870 operator Enum() const &&
4872 auto value =
typename std::underlying_type<Enum>::type{};
4873 value = std::move(*
this);
4878 template<typename Number, typename std::enable_if<std::is_arithmetic<Number>::value>::type* =
nullptr>
4879 operator Number() const &&
4881 auto ret = Number{};
4882 char* endptr =
nullptr;
4885 x_parse(ret, &endptr);
4887 throw_if(errno, ret,
"under-or-overflow");
4888 throw_if(!endptr || endptr == m_beg, ret,
"could not interpret");
4889 throw_if(endptr > m_end, ret,
"parsed past the end");
4891 for(; endptr < m_end; ++endptr) {
4892 throw_if(!std::isspace(*endptr), ret,
"trailing non-whitespace characters");
4898 operator bool() const &&
4900 uint8_t ret = std::move(*
this);
4901 throw_if(ret != 0 && ret != 1, ret,
"out of bounds");
4909 template<
typename T>
4910 void throw_if(
bool cond,
const T&,
const char* message)
const 4913 throw std::domain_error(
4915 + std::string(m_beg,
size_t(m_end-m_beg))
4916 +
"' as numeric type '" +
typeid(T).name()
4917 +
"' - " + message +
".");
4921 void x_parse(
long double& d,
char** endptr)
const 4923 d = std::strtold(m_beg, endptr);
4926 void x_parse(
double & d,
char** endptr)
const 4928 d = std::strtod(m_beg, endptr);
4931 void x_parse(
float& d,
char** endptr)
const 4933 d = std::strtof(m_beg, endptr);
4936 template<
typename Integral>
4937 void x_parse(Integral& x,
char** endptr)
const 4939 static_assert(std::is_integral<Integral>::value,
"");
4944 if(std::is_signed<Integral>::value) {
4946 auto num = std::strtoll(m_beg, endptr, 10);
4947 x = static_cast<Integral>(num);
4948 throw_if(x != num, x,
"overflow");
4953 while(ptr < m_end && std::isspace(*ptr)) {
4956 throw_if(ptr < m_end && *ptr ==
'-', x,
"negative number in unsigned conversion");
4958 auto num = std::strtoull(ptr, endptr, 10);
4959 x = static_cast<Integral>(num);
4960 throw_if(x != num, x,
"overflow");
4970 #endif // ENABLE_TSV 4974 #if RANGELESS_FN_ENABLE_RUN_TESTS 4986 #define VERIFY(expr) if(!(expr)) RANGELESS_FN_THROW("Assertion failed: ( "#expr" )."); 5003 X(
int i) : value{ i }
5006 #if defined(__GNUC__) && (__GNUC___ >= 5) 5018 X& operator=(X&&) =
default;
5020 X(
const X&) =
delete;
5021 X& operator=(
const X&) =
delete;
5028 operator const int& ()
const 5033 using Xs = std::vector<X>;
5039 template<
typename UnaryCallable>
5040 auto make_tests(UnaryCallable make_inputs) -> std::map<std::string, std::function<void()>>
5042 std::map<std::string, std::function<void()>> tests{};
5043 using fn::operators::operator%;
5047 auto fold =
fn::foldl_d([](int64_t out, int64_t in)
5054 tests[
"single test of interest"] = [&]
5063 tests[
"Test for NB[3]"] = [&]
5065 auto res = make_inputs({1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20})
5069 return std::move(out) +
"," + in;
5071 VERIFY(res ==
",1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20");
5074 tests[
"foldl"] = [&]
5077 auto res = make_inputs({1,2,3})
5080 return X(out*10+in);
5082 VERIFY(res == 42123);
5090 tests[
"sliding_window"] = [&]
5095 #if __cplusplus >= 201402L 5101 make_inputs({ 1,2,3,4 })
5105 VERIFY(std::distance(v.begin(), v.end()) == 2);
5106 auto it = v.begin();
5107 return (out * 1000) + (*it * 10) + *std::next(it);
5109 VERIFY(result == 12023034);
5115 tests[
"where"] = [&]
5117 auto ret = make_inputs({1,2,3})
5118 %
fn::where([](
int x) {
return x != 2; })
5126 tests[
"where_in_sorted"] = [&]
5128 auto ret = make_inputs({1,2,3,4})
5134 tests[
"where_not_in_sorted"] = [&]
5136 auto ret = make_inputs({1,2,3,4})
5142 tests[
"where_max_by"] = [&]
5144 auto ret = make_inputs({1,3,1,3})
5150 tests[
"where_min_by"] = [&]
5154 auto ret = make_inputs({5,3,5,3})
5160 tests[
"take_while"] = [&]
5162 auto ret = make_inputs({3,4,1,2})
5168 tests[
"drop_while"] = [&]
5170 auto ret = make_inputs({3,4,1,2})
5177 tests[
"take_last"] = [&]
5180 make_inputs({1,2,3})
5185 ret = make_inputs({1,2,3})
5190 ret = make_inputs({1,2,3})
5195 const auto inputs = std::vector<int>{{1,2,3}};
5200 tests[
"drop_last"] = [&]
5203 make_inputs({1,2,3})
5209 ret = make_inputs({1,2,3})
5215 ret = make_inputs({1,2,3})
5221 const auto inputs = std::vector<int>{{1,2,3}};
5226 tests[
"take_first"] = [&]
5229 make_inputs({1,2,3})
5235 tests[
"drop_first"] = [&]
5238 make_inputs({1,2,3})
5247 tests[
"append"] = [&]
5249 auto res = make_inputs({1,2,3})
5253 VERIFY(res == 12345);
5256 tests[
"zip_with"] = [&]
5258 auto res = make_inputs({1,2})
5261 return std::array<int, 2>{{x, y}};
5266 VERIFY(res == 1324);
5272 tests[
"enumerate"] = [&]
5274 auto res = make_inputs({4,5,6})
5278 return std::array<int, 2>{{p.second, int(p.first)}};
5283 VERIFY(res == 405162);
5288 tests[
"values"] = [&]
5290 auto inps = make_inputs({1,2,3});
5292 auto m = std::map<int, decltype(inps) >{};
5293 m.emplace(1, std::move(inps));
5294 m.emplace(2, make_inputs({4,5,6}));
5296 auto res = std::move(m)
5301 VERIFY(res == 123456);
5306 tests[
"group_adjacent"] = [&]
5308 auto res = make_inputs({1,2,2,3,3,3,2,2,1})
5312 return int(v.size());
5315 VERIFY(res == 12321);
5318 tests[
"group_adjacent_if"] = [&]
5320 auto res = make_inputs({1,2,2,4,4,4,2,2,1})
5323 return abs(a - b) < 2;
5327 return int(v.size());
5333 tests[
"group_all"] = [&]
5335 auto res = make_inputs({1,2,2,3,3,3,2,2,1})
5339 return int(v.size());
5345 tests[
"in_groups_of"] = [&]
5347 auto res = make_inputs({1,2,3,4,5})
5351 return int64_t(v.size());
5357 tests[
"concat"] = [&]
5359 auto res = make_inputs({1,2,2,3,3,3,2,2,1})
5363 VERIFY(res == 112222333);
5366 tests[
"unique_adjacent"] = [&]
5368 auto res = make_inputs({1,2,2,3,3,3,2,2,1})
5371 VERIFY(res == 12321);
5374 tests[
"unique_all"] = [&]
5378 auto res = make_inputs({1,2,2,3,3,3,2,2,1})
5397 auto res = make_inputs({3,2,4,1,5})
5401 VERIFY(res == 54321);
5403 res = make_inputs({3,2,4,1,5})
5406 VERIFY(res == 12345);
5409 tests[
"lazy_sort"] = [&]
5411 auto res = make_inputs({3,2,4,1,5})
5415 VERIFY(res == 54321);
5418 tests[
"top_n"] = [&]
5420 auto res = make_inputs({3,2,4,1,5,0})
5427 #if __cplusplus >= 201402L 5428 tests[
"group_adjacent_as_subseqs"] = [&]
5433 make_inputs({1,2,2,3,3,3,4,5})
5440 if(group_num == 4) {
5445 for(
const auto x : subseq) {
5460 VERIFY(res == 1022033050);
5465 tests[
"key_fn returning a reference_wrapper"] = [&]
5468 auto get_ref = [](
const X& x) {
return std::cref(x); };
5481 auto res = make_inputs({2,3,1,2}) %
fn::to(std::set<int>{}) % fold;
5496 static void run_tests()
5498 using fn::operators::operator%;
5500 #if 0 // single test 5502 std::map<std::string, std::function<void()>> tests1{}, tests2{}, test_other{};
5503 test_other[
"single"] = [&]
5510 return (
int)v.size();
5516 std::map<std::string, std::function<void()>>
5517 test_cont{}, test_seq{}, test_view{}, test_other{};
5520 test_cont = make_tests([](std::initializer_list<int> xs)
5524 ret.push_back(X(x));
5530 test_seq = make_tests([](std::initializer_list<int> xs)
5534 ret.push_back(X(x));
5540 test_view = make_tests([](std::initializer_list<int> xs)
5545 static std::vector<Xs> vecs{};
5546 vecs.push_back(Xs{});
5547 auto& ret = vecs.back();
5550 ret.push_back(X(x));
5556 using vec_t = std::vector<int>;
5563 test_other[
"typerased"] = [&]
5577 for(
const auto& x : myseq) {
5581 VERIFY(res == 2468);
5584 test_other[
"for_each"] = [&]
5587 auto vec = vec_t{{1,2,3}};
5592 VERIFY(( vec == vec_t{{10,20,30}} ));
5595 test_other[
"for_each_adjacent"] = [&]
5597 auto vec = vec_t{{1,2,3,4}};
5600 return x2 = x1*10 + x2;
5603 VERIFY(( vec == vec_t{{1,12,123,1234}} ));
5607 test_other[
"zip_adjacent"] = [&]
5617 VERIFY(( res == std::vector<int>{{12,23,34}} ));
5622 test_other[
"fold"] = [&]
5624 const std::string x =
5625 vec_t{{1,2,3}} %
fn::foldl(std::string{
"^"},
5626 [](std::string s,
int x_)
5628 return std::move(s) +
"|" + std::to_string(x_);
5630 VERIFY(x ==
"^|1|2|3");
5633 test_other[
"foldl_d"] = [&]
5635 const std::string x =
5636 vec_t{{1,2,3}} %
fn::foldl_d( [](std::string s,
int x_)
5638 return std::move(s) +
"|" + std::to_string(x_);
5641 VERIFY(x ==
"|1|2|3");
5644 test_other[
"foldl_1"] = [&]
5646 const auto min_int =
5647 std::vector<std::string>{{
"11",
"-333",
"22" }}
5648 %
fn::transform([](
const std::string& s) {
return std::stoi(s); })
5649 %
fn::foldl_1([](
int out,
int in) {
return std::min(out, in); });
5651 VERIFY(min_int == -333);
5658 test_other[
"fn::where with associative containers"] = [&]
5663 auto ints2 = std::set<int>{{111, 333}};
5665 using fn::operators::operator%=;
5667 ints2 %=
fn::where([](
int x) {
return x > 222; });
5668 VERIFY(ints2.size() == 1 && *ints2.begin() == 333);
5670 using map_t = std::map<int, int>;
5671 auto m = map_t{{ {1,111}, {3,333} }};
5673 m %=
fn::where([](
const map_t::value_type& x) {
return x.second > 222; });
5674 VERIFY(m.size() == 1 && m.at(3) == 333);
5679 test_other[
"fn::where with mutable lambdas"] = [&]
5683 auto ints2 = vec_t{{1,2,3}} %
fn::where([i](
int)
mutable {
return i++ >= 1; });
5684 VERIFY(( ints2 == vec_t{{2, 3}} ));
5687 test_other[
"fn::where with const_reference inputs"] = [&]
5690 const auto ints1 = std::set<int>{1,2,3};
5691 auto ints2 = ints1 %
fn::where([](
int x_) {
return x_ > 1; });
5692 VERIFY(( ints2.size() == 2 ));
5695 test_other[
"fn::where with non-const reference inputs"] = [&]
5698 auto ints1 = std::set<int>{1,2,3};
5699 auto ints2 = ints1 %
fn::where([](
int x_) {
return x_ > 1; });
5701 VERIFY(( ints1.size() == 3 ));
5702 VERIFY(( ints2.size() == 2 ));
5706 test_other[
"refs"] = [&]
5708 auto inps = vec_t({1,2,3});
5721 const auto& const_inps = inps;
5735 test_other[
"memoized"] = [&]
5737 size_t exec_count = 0;
5738 auto strs = std::vector<std::string>{{
"333",
"4444",
"22",
"1" }};
5740 using fn::operators::operator%=;
5747 VERIFY((strs == std::vector<std::string>{{
"1",
"22",
"333",
"4444" }}));
5748 VERIFY(exec_count == 4);
5751 test_other[
"scope_guard"] = [&]
5765 on_exit_add1.dismiss();
5770 test_other[
"operator<<=, operator%="] = [&]
5772 using fn::operators::operator<<=;
5773 using fn::operators::operator%=;
5775 auto cont = vec_t{{1,2}};
5776 cont <<= std::set<int>{{3,4}};
5778 const auto const_set = std::set<int>{{5,6}};
5786 cont %=
fn::where([](
int x) {
return x % 2 != 0; });
5788 VERIFY((cont == vec_t{{1,3,5,7,9}}));
5792 test_other[
"generate and output_iterator"] = []
5801 std::copy(r.begin(), r.end(), fn::make_output_iterator([&](
int x)
5806 VERIFY(sum == 1234);
5810 test_other[
"get_unique/set_unique"] = [&]
5812 vec_t ints{{1,2,3}};
5814 auto& x1 =
get_unique(ints, [](
int x_){
return x_ == 2; });
5818 const auto& const_ints = ints;
5819 const auto& x2 =
get_unique(const_ints, [](
int x_){
return x_ == 2; });
5823 auto& y =
set_unique(ints2, [](
int x_) {
return x_ == 42; },
5826 VERIFY( ints2.size() == 4
5827 && ints2.back() == 42
5828 && &ints2.back() == &y);
5831 test_other[
"group_adjacent_by vector-storage-recycling"] = []
5836 std::set<int*> ptrs;
5839 vec_t{2,4,1,3,5,6,7,9}
5845 ptrs.insert(in.data());
5846 return out*10 + int64_t(in.size());
5849 VERIFY((result == 2312));
5850 VERIFY((ptrs.size() <= 2));
5853 test_other[
"decreasing"] = [&]
5857 const auto inp = std::vector<std::string>{
"2",
"333",
"1",
"222",
"3" };
5858 const auto expected = std::vector<std::string>{
"222",
"333",
"1",
"2",
"3" };
5860 auto ret1 = inp %
fn::sort_by([](
const std::string& s)
5864 VERIFY(ret1 == expected);
5866 auto ret2 = inp %
fn::sort_by([](
const std::string& s)
5871 VERIFY(ret2 == expected);
5878 VERIFY(ret3 == expected);
5886 VERIFY(ret4 == expected);
5889 test_other[
"by"] = [&]
5894 std::vector<std::pair<std::unique_ptr<int>,
int>> v{};
5899 const auto xy = std::make_pair(10, 20);
5900 const auto& x = fn::by::first{}(xy);
5901 VERIFY(&x == &xy.first);
5903 std::vector<std::unique_ptr<int> > v2{};
5904 fn::sort_by(fn::by::dereferenced{})(std::move(v2));
5907 test_other[
"exists_where"] = [&]
5909 VERIFY( ( vec_t{{ 1, 2, 3}} %
fn::exists_where([](
int x){
return x == 2; }) ));
5910 VERIFY( !( vec_t{{ 1, 2, 3}} %
fn::exists_where([](
int x){
return x == 5; }) ));
5911 VERIFY( ( vec_t{{ 1, 2, 3}} % !
fn::exists_where([](
int x){
return x == 5; }) ));
5915 #if __cplusplus >= 201402L 5916 test_other[
"compose"] = []
5918 auto my_transform = [](
auto fn)
5926 auto my_where = [](
auto pred)
5928 return fn::adapt([pred = std::move(pred)](
auto gen)
5938 auto my_take_while = [](
auto pred)
5940 return fn::adapt([pred = std::move(pred)](
auto gen)
5943 return pred(x) ? std::move(x) :
fn::end_seq();
5947 auto my_intersperse = [](
auto delim)
5950 return [delim = std::move(delim)](
auto inputs)
5953 inputs = std::move(inputs),
5956 flag =
false]()
mutable 5960 it = inputs.begin();
5963 : (flag = !flag) ? std::move(*it++)
5970 return [delim = std::move(delim)](
auto inputs)
5972 return std::move(inputs)
5975 return std::array<decltype(inp), 2>{{ delim, std::move(inp) }};
5983 return fn::adapt([delim, flag =
false](
auto gen)
mutable 5986 : (flag = !flag) ? gen()
5992 auto my_inclusive_scan = []
5994 return fn::adapt([sum = 0](
auto gen)
mutable 5996 return sum += gen();
6006 % my_where([](
int x)
6011 % my_take_while([](
int x)
6016 % my_intersperse(-1)
6018 % my_transform([](
int x)
6023 % my_inclusive_scan()
6027 VERIFY((res == vec_t{{4, 4, 9, 9, 15}}));
6029 #endif // tests for compose 6032 test_other[
"cartesian_product_with"] = [&]
6045 VERIFY(res == 13014015023024025);
6048 test_other[
"guard_against_multiple_iterations_of_input_range"] = [&]
6050 auto gen_ints = [](
int i,
int j)
6052 return fn::seq([i, j]()
mutable 6062 %
fn::where([](
int x) {
return x % 2 == 0; });
6070 for(
size_t i = 0; i < 2; i++) {
6080 VERIFY(res == 22446);
6084 test_other[
"most 5 top frequent words"] = [&]
6088 std::istringstream istr{};
6090 auto my_isalnum = [](
const int ch)
6092 return std::isalnum(ch) || ch ==
'_';
6095 using counts_t = std::map<std::string, size_t>;
6098 std::istreambuf_iterator<char>(istr.rdbuf()),
6099 std::istreambuf_iterator<char>{})
6103 return (
'A' <= c && c <=
'Z') ? char(c - (
'Z' -
'z')) : c;
6110 %
fn::foldl_d([&](counts_t out,
const std::string& in)
6112 if(my_isalnum(in.front())) {
6115 return std::move(out);
6120 return my_isalnum(s.front());
6127 return kv.first.size();
6137 std::cerr << kv.first <<
"\t" << kv.second <<
"\n";
6142 test_other[
"placement-new without std::launder"] = [&]
6155 VERIFY((*m).n == 42);
6156 VERIFY((*m).r == 1);
6158 m.reset(S{420, x2});
6159 VERIFY((*m).n == 420);
6160 VERIFY((*m).r == 2);
6163 test_other[
"counts"] = [&]
6166 vec_t{{ 1, 1,2, 1,2,3 }}
6168 %
fn::transform([](
const std::map<int, size_t>::value_type& kv)
6170 return kv.first * 10 + int(kv.second);
6174 VERIFY((res == vec_t{{13, 22, 31}}));
6178 test_other[
"tsv"] = [&]
6180 std::string result =
"";
6181 std::istringstream istr{
"Expected Header\n \t r1f1 \t \n#Comment: next line is empty, and next one is blanks\n\n \n r2f1 \tr2f2\t r2f3 "};
6183 tsv::params params{};
6184 params.header =
"Expected Header";
6185 params.filename =
"filename";
6190 for(
const auto& f : row) {
6197 VERIFY(result ==
"|r1f1||;r2f1|r2f2|r2f3|;");
6200 const auto row = tsv::split_on_delim{
',' }(
"a,bb,ccc");
6201 VERIFY((row ==
tsv::row_t{{
"a",
"bb",
"ccc"}}));
6204 test_other[
"to_num"] = [&]
6206 VERIFY(123 ==
int(tsv::to_num(
" +123 ")));
6208 double delta = 123.0 - double(tsv::to_num(
" 123.0 "));
6212 VERIFY(delta < 1e-10);
6214 VERIFY(
bool(tsv::to_num(
" 1 ")));
6217 (void)int8_t(tsv::to_num(
"-129"));
6219 }
catch(
const std::domain_error&) {
6224 (void)
int(tsv::to_num(
"123 4"));
6226 }
catch(
const std::domain_error&) {
6231 (void)uint16_t(tsv::to_num(
"-123"));
6233 }
catch(
const std::domain_error&) {
6237 enum class my_int_t : int{};
6238 my_int_t my_int = tsv::to_num(
"42");
6239 VERIFY(my_int == my_int_t(42));
6243 #endif // single-test vs all 6246 size_t num_failed = 0;
6248 for(
auto&& tests : { test_cont, test_seq, test_view, test_other })
6249 for(
const auto& kv : tests)
6254 }
catch(
const std::exception& e) {
6256 std::cerr <<
"Failed test '" << kv.first <<
"' :" << e.what() <<
"\n";
6259 if(num_failed == 0) {
6260 std::cerr <<
"Ran " << num_ok <<
" tests - OK\n";
6262 throw std::runtime_error(std::to_string(num_failed) +
" tests failed.");
6271 #endif //RANGELESS_FN_ENABLE_RUN_TESTS 6283 #if RANGELESS_FN_ENABLE_PARALLEL 6287 #include <condition_variable> 6307 operator double()
const 6309 return double(std::chrono::duration_cast<std::chrono::nanoseconds>(
6310 clock_t::now() - start_timepoint).count()) * 1e-9;
6313 using clock_t = std::chrono::steady_clock;
6314 clock_t::time_point start_timepoint = clock_t::now();
6323 std::atomic<bool> m_locked = {
false };
6328 return !m_locked.load(std::memory_order_relaxed)
6329 && !m_locked.exchange(
true, std::memory_order_acquire);
6334 for(
size_t i = 0; !try_lock(); i++) {
6335 std::this_thread::sleep_for(
6336 std::chrono::microseconds(5));
6342 m_locked.store(
false, std::memory_order_release);
6351 enum class status { success, closed, timeout };
6412 template <
typename T,
class BasicLockable = std::mutex>
6424 ~synchronized_queue() =
default;
6475 this->operator()(std::move(val));
6506 m_queue.
try_push(std::move(val), no_timeout_sentinel_t{});
6508 assert(st != status::timeout);
6510 if(st == status::closed) {
6514 assert(st == status::success);
6532 return m_queue.x_blocking_pop();
6552 template<
typename F>
6555 auto guard = this->close();
6558 bool threw_in_pop =
true;
6562 threw_in_pop =
false;
6563 sink(std::move(val));
6583 assert(closed() && m_queue.empty());
6592 template <
typename Duration = std::chrono::milliseconds>
6604 const guard_t contention_guard{ m_push_mutex };
6606 lock_t queue_lock{ m_queue_mutex };
6608 ++m_num_waiting_to_push;
6609 const bool ok = x_wait_until([
this]
6611 return m_queue.size() < m_capacity || !m_capacity;
6613 m_can_push, queue_lock, timeout);
6614 --m_num_waiting_to_push;
6617 return status::timeout;
6621 return status::closed;
6624 assert(m_queue.size() < m_capacity);
6629 m_queue.push(std::move(value));
6631 const bool do_notify = m_num_waiting_to_pop > 0;
6632 queue_lock.unlock();
6635 m_can_pop.notify_one();
6638 return status::success;
6644 template <
typename Duration = std::chrono::milliseconds>
6647 const guard_t contention_guard{ m_pop_mutex };
6649 lock_t queue_lock{ m_queue_mutex };
6651 ++m_num_waiting_to_pop;
6652 bool ok = x_wait_until([
this]
6654 return !m_queue.empty() || !m_capacity;
6656 m_can_pop, queue_lock, timeout);
6657 --m_num_waiting_to_pop;
6660 return status::timeout;
6663 if(!m_queue.empty()) {
6665 }
else if(!m_capacity) {
6666 return status::closed;
6671 value = std::move(m_queue.front());
6674 const bool do_notify = m_num_waiting_to_push > 0;
6675 queue_lock.unlock();
6678 m_can_push.notify_one();
6681 return status::success;
6690 return m_queue.size();
6713 close_guard(
const close_guard&) =
default;
6714 close_guard& operator=(
const close_guard&) =
default;
6750 using guard_t = std::lock_guard<BasicLockable>;
6751 using lock_t = std::unique_lock<BasicLockable>;
6752 using queue_t = std::queue<value_type>;
6754 using condvar_t =
typename std::conditional<
6755 std::is_same<BasicLockable, std::mutex>::value,
6756 std::condition_variable,
6757 std::condition_variable_any >::type;
6759 struct no_timeout_sentinel_t
6762 template<
typename F>
6763 bool x_wait_until(F condition, condvar_t& cv, lock_t& lock, no_timeout_sentinel_t)
6765 cv.wait(lock, std::move(condition));
6769 template<
typename Duration,
typename F>
6770 bool x_wait_until(F condition, condvar_t& cv, lock_t& lock, Duration duration)
6772 return cv.wait_for(lock, duration, std::move(condition));
6775 value_type x_blocking_pop()
6777 const guard_t contention_guard{ m_pop_mutex };
6779 lock_t queue_lock{ m_queue_mutex };
6781 ++m_num_waiting_to_pop;
6786 return !m_queue.empty() || !m_capacity;
6788 --m_num_waiting_to_pop;
6790 if(m_queue.empty()) {
6791 throw queue_closed{};
6794 value_type ret = std::move(m_queue.front());
6797 const bool do_notify = m_num_waiting_to_push > 0;
6798 queue_lock.unlock();
6801 m_can_push.notify_one();
6813 guard_t g{ m_queue_mutex };
6816 m_can_pop.notify_all();
6817 m_can_push.notify_all();
6825 const char m_padding0[64] = {};
6827 uint32_t m_num_waiting_to_push = 0;
6828 uint32_t m_num_waiting_to_pop = 0;
6829 size_t m_capacity = size_t(-1);
6830 queue_t m_queue = queue_t{};
6831 BasicLockable m_queue_mutex = {};
6832 BasicLockable m_push_mutex = {};
6833 BasicLockable m_pop_mutex = {};
6834 condvar_t m_can_push = {};
6835 condvar_t m_can_pop = {};
6837 const char m_padding1[64] = {};
6853 template<
typename InGen>
6869 fut = std::async(std::launch::async, [
this]
6871 auto guard = queue->close();
6872 for(
auto x = in_gen(); x; x = in_gen()) {
6873 queue->push(std::move(x));
6880 auto x = queue->pop();
6883 assert(queue->closed());
6904 template<
typename NullaryCallable>
6905 auto operator()(NullaryCallable gen)
const -> std::future<decltype(gen())>
6907 return std::async(std::launch::async, std::move(gen));
6912 template<
typename F,
typename Async>
6922 return std::move(*
this);
6925 #if __cplusplus >= 201402L 6928 auto in_batches_of(
size_t batch_size) &&
6930 assert(batch_size >= 2);
6932 return [ map_fn = std::move(this->map_fn),
6933 async = std::move(this->async),
6934 queue_cap = std::move(this->queue_cap),
6940 auto batch_transform = [ map_fn ](
auto inputs_batch)
6946 std::move(inputs_batch)));
6950 auto par_batch_transform =
6952 std::move(batch_transform),
6956 std::move(par_batch_transform)(
6958 std::move(inputs))));
6962 #endif // __cplusplus >= 201402L 6964 template<
typename InGen>
6975 using queue_t = std::deque<std::future<value_type>>;
6999 if(queue_cap == 0) {
7000 assert(queue.empty());
7005 return map_fn(std::move(*x));
7011 using input_t =
typename InGen::value_type;
7016 auto operator()() -> decltype(
fn(std::move(inp)))
7018 return fn(std::move(inp));
7023 while(queue.size() < queue_cap) {
7030 queue.emplace_back( async( job_t{ map_fn, std::move(*x) }));
7037 auto ret = queue.front().get();
7039 return { std::move(ret) };
7072 return { queue_size };
7157 template<
typename F>
7160 return {
impl::std_async{}, std::move(map_fn), std::thread::hardware_concurrency() };
7193 template<
typename F,
typename Async>
7196 return { std::move(async), std::move(map_fn), std::thread::hardware_concurrency() };
7209 #if RANGELESS_FN_ENABLE_RUN_TESTS 7215 #define VERIFY(expr) if(!(expr)) RANGELESS_FN_THROW("Assertion failed: ( "#expr" )."); 7225 static void run_tests()
7230 mt::synchronized_queue<std::reference_wrapper<int> > queue;
7231 queue.push( std::ref(x));
7232 queue.push( std::ref(x));
7235 auto y = queue.pop();
7236 queue >>= [&](
int& x_) { x_ = 20; };
7242 synchronized_queue<std::string> q{1};
7243 std::string s1 =
"1";
7244 std::string s2 =
"2";
7246 auto st1 = q.try_push(std::move(s1), std::chrono::milliseconds(10));
7247 auto st2 = q.try_push(std::move(s2), std::chrono::milliseconds(10));
7249 VERIFY(st1 == decltype(q)::status::success);
7252 VERIFY(st2 == decltype(q)::status::timeout);
7257 std::cerr <<
"Testing queue...\n";
7258 using queue_t = mt::synchronized_queue<long, mt::lockables::atomic_mutex>;
7263 auto task = std::async(std::launch::async, [&] {
7264 std::this_thread::sleep_for(
7265 std::chrono::milliseconds(100));
7271 auto res = q.try_pop(x, std::chrono::milliseconds(90));
7272 VERIFY(res == queue_t::status::timeout);
7274 auto res2 = q.try_pop(x, std::chrono::milliseconds(20));
7275 VERIFY(res2 == queue_t::status::success);
7278 VERIFY(q.try_pop(x) == queue_t::status::closed);
7279 VERIFY(q.try_push(42) == queue_t::status::closed);
7287 auto task = std::async(std::launch::async, [&] {
7288 std::this_thread::sleep_for(
7289 std::chrono::milliseconds(100));
7293 auto res = q.try_push(42, std::chrono::milliseconds(90));
7294 VERIFY(res == queue_t::status::timeout);
7296 auto res2 = q.try_push(42, std::chrono::milliseconds(20));
7297 VERIFY(res2 == queue_t::status::success);
7298 VERIFY(q.pop() == 42);
7312 VERIFY(q2.approx_size() == 1);
7313 VERIFY(q2.pop() == 123);
7316 queue_t queue{ 2048 };
7320 std::vector<std::future<void>> pushers;
7321 std::vector<std::future<long>> poppers;
7323 const size_t num_cpus = std::thread::hardware_concurrency();
7324 std::cerr <<
"hardware concurrency: " << num_cpus <<
"\n";
7325 const size_t num_jobs = num_cpus / 2;
7326 const int64_t num = 100000;
7330 for(
size_t i = 0; i < num_jobs; i++) {
7335 pushers.emplace_back(
7336 std::async(std::launch::async, [&]
7338 for(
long j = 0; j < num; j++) {
7343 poppers.emplace_back(
7344 std::async(std::launch::async, [&]
7348 queue >>= [&acc](
long x){ acc += x; };
7355 for(
auto& fut : pushers) {
7367 VERIFY(queue.try_push(std::move(x)) == queue_t::status::closed);
7368 queue.push(std::move(x));
7370 }
catch(queue_t::queue_closed&) {}
7374 for(
auto& fut : poppers) {
7377 VERIFY(queue.approx_size() == 0);
7380 auto queue2 = std::move(queue);
7383 assert(queue2.try_pop(x) == queue_t::status::closed);
7386 }
catch(queue_t::closed&) {}
7389 const auto n = int64_t(num_jobs) * num;
7394 std::cerr <<
"Queue throughput: " << double(total)/timer <<
"/s.\n";
7399 using queue_t = synchronized_queue<int>;
7403 auto res = queue.try_pop(x, std::chrono::milliseconds(10));
7404 VERIFY(res == queue_t::status::timeout);
7408 res = queue.try_push(10, std::chrono::milliseconds(10));
7409 VERIFY(res == queue_t::status::timeout);
7414 using fn::operators::operator%;
7431 VERIFY(res == 500000500000);
7432 std::cerr <<
"to_async throughput: " << double(1000000)/timer <<
"/s.\n";
7437 auto res = std::vector<int>({1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20})
7441 return std::move(out) +
"," + std::to_string(in);
7443 VERIFY(res ==
",1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20");
7446 #if __cplusplus >= 201402L 7447 auto res2 = std::vector<int>({1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20})
7451 return std::async(std::launch::async, std::move(job));
7452 }).queue_capacity(10)
7456 return std::move(out) +
"," + in;
7458 VERIFY(res2 ==
",1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20");
7469 #endif // RANGELESS_FN_ENABLE_RUN_TESTS 7471 #endif // RANGELESS_FN_ENABLE_PAR 7479 #if defined(_MSC_VER) 7480 # pragma warning(pop) 7483 #endif // #ifndef RANGELESS_FN_HPP_ impl::async_wr to_async(size_t queue_size=16)
Wrap generating seq in an async-task.
impl::foldl_d< Op > foldl_d(Op binary_op)
Fold-Left-with-Default: this version uses default-initialized value for init.
#define RANGELESS_FN_THROW(msg)
Optionally-bounded blocking concurrent MPMC queue.
auto operator()() -> maybe< value_type >
std::vector< std::string > row_t
~scope_guard() noexcept(noexcept(fn()))
typename InGen::value_type value_type
decltype(gen()) value_type
status try_push(value_type &&value, Duration timeout={})
In case of success, the value will be moved-from.
view< std::reverse_iterator< Iterator > > operator()(view< Iterator > v) const
std::vector< value_type > vec_t
auto operator()() -> maybe< value_type >
auto operator()(Iterable src) &&-> seq< gen< Iterable >>
impl::group_adjacent_by< F > group_adjacent_by(F key_fn)
Group adjacent elements.
impl::where< impl::in_sorted_by< SortedForwardRange, F > > where_in_sorted_by(const SortedForwardRange &r, F key_fn)
auto operator()() -> maybe< value_type >
std::vector< T > operator()(std::vector< T > vec) const
auto operator()(seq< Gen > r) const -> std::vector< typename seq< Gen >::value_type >
bool operator()(const A &a, const B &b) const
impl::sort_by< F, impl::unstable_sort_tag > unstable_sort_by(F key_fn)
maybe< value_type > operator++(int)
Ret operator()(Cont cont) const
impl::where_max_by< F > where_min_by(F key_fn)
impl::take_while< P > take_while(P pred)
Yield elements until pred evaluates to false.
impl::par_transform< F, impl::std_async > transform_in_parallel(F map_fn)
Parallelized version of fn::transform
maybe< value_type > operator()()
push_t & operator=(value_type val)
impl::where< P > where(P pred)
Filter elements.
void operator()(Iterable &&src)
typename Gen::value_type value_type
typename InGen::value_type value_type
impl::group_adjacent_by< impl::chunker > in_groups_of(size_t n)
Group adjacent elements into chunks of specified size.
decltype(fn(*it, *it)) value_type
impl::group_all_by< by::identity > group_all()
seq::value_type value_type
typename InGen::value_type value_type
Cont operator()(const Cont &cont) const
typename queue_t::iterator iterator
decltype(fn(gen_wr{ nullptr })) value_type
synchronized_queue(size_t cap=1024)
impl::where_max_by< F > where_max_by(F key_fn)
Filter elements to those having maximum value of fn.
std::vector< value_type > vec_t
auto operator()(seq< Gen > src) const -> decltype(fold_op(std::move(*src.get_gen()()), std::move(*src.get_gen()())))
void recycle(value_type &grbg)
impl::group_adjacent_by< by::identity > group_adjacent()
impl::reverse reverse()
Reverse the elements in the input container.
impl::where_max_by< by::identity > where_min()
auto operator()() -> maybe< value_type >
close_guard(synchronized_queue &queue)
typename std::common_type< typename Iterable1::value_type, typename Iterable2::value_type >::type value_type
typename Iterable::iterator iterator
seq< gen< Iterable > > operator()(Iterable src) const
Wrap a range (e.g. a container or a view) as seq.
auto operator()() -> maybe< value_type >
auto operator()() -> maybe< value_type >
auto operator()() -> inp_t
static void require_iterator_category_at_least(const Iterable &)
seq & operator=(const seq &)=delete
impl::counts counts()
return map: value_type -> size_t
bool operator<(const gt &other) const
impl::cartesian_product_with< Iterable, BinaryFn > cartesian_product_with(Iterable second, BinaryFn fn)
auto operator()() -> maybe< value_type >
bool operator!=(const iterator &other) const
typename std::decay< decltype(key_fn(*gen()))>::type key_t
Iterable operator()(Iterable src) const
impl::where< impl::in_sorted_by< SortedForwardRange, F > > where_not_in_sorted_by(const SortedForwardRange &r, F key_fn)
bool operator()(const std::reference_wrapper< T > &a, const std::reference_wrapper< T > &b) const
auto operator()(Iterable &&src) const -> decltype(fold_op(std::move(*src.begin()), *src.begin()))
auto operator()(Iterable1 src1) &&-> seq< gen< Iterable1 >>
status try_pop(value_type &value, Duration timeout={})
In case of success, the value will be move-assigned.
bool operator()(const T &a, const T &b) const
maybe< element_type > next()
auto operator()(const T &x) const -> const U &
std::input_iterator_tag iterator_category
auto operator()() -> maybe< value_type >
impl::zip_adjacent< BinaryFn > zip_adjacent(BinaryFn fn)
Yield invocations of fn over pairs of adjacent inputs.
reference operator *() const
auto operator()(seq< InGen > in) const -> Ret
void operator()(seq< Gen > src)
impl::lazy_sort_by< by::identity > lazy_sort()
lazy_sort_by with key_fn = by::identity
impl::memoizer< F > make_memoized(F fn)
Memoizing wrapper for non-recursive non-mutable unary lambdas (not synchronized).
auto from(std::istream &istr, char delim='\t', params params={}) -> fn::impl::seq< fn::impl::transform< tsv::split_on_delim >::gen< fn::impl::catch_end< tsv::get_next_line > > >
Read tab-separated-values from stream.
synchronized_queue::value_type value_type
maybe(maybe &&other) noexcept
auto operator()() -> maybe< value_type >
Implements insert_iterator and unary-invokable.
impl::take_top_n_by< F > take_top_n_by(size_t n, F key_fn)
Return top-n elements, sorted by key_fn.
pointer operator->() const
impl::concat concat()
Flatten the result of group_all_by or group_adjacent_by.
impl::where_max_by< by::identity > where_max()
auto operator()() -> maybe< value_type >
Vec operator()(std::map< Key, Value > m) const
impl::sliding_window sliding_window(size_t win_size)
std::output_iterator_tag iterator_category
impl::unique_all_by< by::identity > unique_all()
impl::exists_where< Pred > exists_where(Pred p)
const impl::comp< F > comp
impl::sort_by< by::identity, impl::stable_sort_tag > sort()
sort_by with key_fn = by::identity
impl::take_last take_last(size_t n=1)
Yield last n elements.
auto operator()() -> maybe< value_type >
impl::sort_by< F, impl::stable_sort_tag > sort_by(F key_fn)
stable-sort and return the input.
view(Iterator b, Iterator e)
Ret operator()(Iterable &&src) &&
typename std::remove_reference< typename traits::arg >::type Arg
A view is just a pair of interators with begin() and end() interface.
impl::foldl< Result, Op > foldl(Result init, Op binary_op)
Range-based version of c++20 (copy-free) std::accumulate
e.g. for tuples or pairs, fn::group_adjacent_by(fn::by::get<string>{})
bool operator()(const T &) const
size_t capacity() const noexcept
maybe & operator=(maybe &&other) noexcept
typename InGen::value_type inp_t
const Ret & operator()(const Arg &arg) const
impl::zip_with< Iterable, BinaryFn > zip_with(Iterable second, BinaryFn fn)
Yield pairs of elements, (up to end of the shorter range)
typename InGen::value_type value_type
typename InGen::value_type inp_t
impl::take_while< impl::call_count_lt > take_first(size_t n=1)
Yield first n elements.
auto operator()(NullaryCallable gen) const -> std::future< decltype(gen())>
Utility to parse numbers.
std::map< typename Iterable::value_type, size_t > operator()(Iterable &&xs) const
std::map< Arg, Ret > Cache
auto operator %=(Arg &arg, F &&fn) -> decltype(void(std::forward< F >(fn)(std::move(arg))))
arg = fn::to(Arg{})(std::forward<F>(fn)(std::move(arg)));
auto recycle(G &gen, T &value, pr_high) -> decltype(gen.recycle(value), void())
auto operator()(ReversibleContainer cont) const -> ReversibleContainer
bool operator()(const std::reference_wrapper< T > &a, const std::reference_wrapper< T > &b) const
LINQ -like library of higher-order functions for data manipulation.
impl::gt< T > decreasing(T x)
Wraps the passed value and exposes inverted operator<.
impl::where< impl::in_sorted_by< SortedForwardRange, by::identity > > where_in_sorted(const SortedForwardRange &r)
Intersect with a sorted range.
seq< Gen > operator()(seq< Gen > seq) const
auto operator()(seq< Gen > r) const -> std::vector< typename seq< Gen >::value_type >
auto operator()(const P &ptr) const -> decltype(*ptr)
Return fn::end_seq() from input-range generator function to signal end-of-inputs.
impl::group_adjacent_by< fn::by::identity, BinaryPred > group_adjacent_if(BinaryPred pred2)
Group adjacent elements if binary predicate holds.
bool operator()(const Iterable &iterable) const
auto get_unique(Container &container, P &&pred) -> decltype(*container.begin())
Access unique element matching the predicate.
constexpr view< Iterator > cfrom(const Iterable &src) noexcept
close_guard close() noexcept
Return an RAII object that will close the queue in its destructor.
impl::seq< impl::catch_end< NullaryInvokable > > seq(NullaryInvokable gen_fn)
Adapt a generator function as InputRange.
split_on_delim(char delim='\t', bool truncate_blanks=true)
impl::drop_while< impl::call_count_lt > drop_first(size_t n=1)
Drop first n elements.
maybe< value_type > operator()()
std::deque< inp_t > queue_t
#define RANGELESS_FN_OVERLOAD_FOR_SEQ(...)
auto set_unique(Container &container, P &&pred, Construct &&con) -> decltype(*container.begin())
Similar to get_unique, but end-insert an element if missing.
std::function< impl::maybe< value_type >)> gen
impl::sort_by< by::identity, impl::unstable_sort_tag > unstable_sort()
Cont operator()(Cont &cont) const
impl::seq< impl::refs_gen< Iterable > > refs(Iterable &src)
Adapt a reference to Iterable as seq yielding reference-wrappers.
auto operator()(const T &x) const -> decltype(*&x.second)
Vec operator()(seq< Gen > r) const
auto operator()(Iterable &&src) const -> decltype(fold_op(any(), *src.begin()))
auto operator()() -> maybe< value_type >
impl::scope_guard< F > make_scope_guard(F fn)
Basic scope guard - execute some code in guard`s destructor.
auto operator()(seq< Gen > src) const -> decltype(fold_op(any(), std::move(*src.get_gen()())))
auto operator()(P ptr) const -> typename std::remove_reference< decltype(std::move(*ptr))>::type
auto operator()(Iterable src) const -> std::vector< typename Iterable::value_type >
auto operator()(const T &x) const -> const T &
Ret operator()(seq< Gen > src) &&
bool closed() const noexcept
Very bare-bones version of std::optional-like with rebinding assignment semantics.
auto operator()() -> maybe< value_type >
typename InGen::value_type value_type
auto operator()(const std::string &line) &-> std::reference_wrapper< const tsv::row_t >
std::unique_ptr< queue_t > queue
bool operator==(const iterator &other) const
auto operator()(T x) const -> typename T::first_type
auto operator()() -> maybe< value_type >
int compare(const T &a, const T &b)
typename InGen::value_type inp_t
impl::to< Container > to(Container dest)
e.g. auto set_of_ints = fn::seq(...) % ... % fn::to(std::set<int>{});
impl::to_vector to_vector()
Move elements of an Iterable to std::vector.
impl::append< Iterable > append(Iterable next)
Yield elements of next after elements of arg.
impl::for_each_adjacent< F2 > for_each_adjacent(F2 fn2)
auto operator()(T x) const -> typename T::second_type
auto operator %(Arg &&arg, F &&fn) -> decltype(std::forward< F >(fn)(std::forward< Arg >(arg)))
return std::forward<F>(fn)(std::forward<Arg>(arg))
auto operator()(const Arg &arg) const -> gt< decltype(val(arg))>
constexpr view< Iterator > from(Iterator it_beg, Iterator it_end) noexcept
Create a range-view from a pair of iterators.
typename Iterable::iterator iterator
seq(seq< OtherGen > other)
void operator<<=(Container &cont, typename Container::value_type el)
auto operator>>=(F &&sink) -> decltype((void) sink(this->pop()))
pop() the values into the provided sink-function until closed and empty.
auto operator()(const std::string &line, row_t ret={}) const &&-> tsv::row_t
typename gen_value_t::value_type value_type
bool operator()(const typename SortedRange::value_type &x) const
synchronized_queue & m_queue
Vec operator()(Iterable src) const
impl::comp< F > make_comp(F key_fn)
Make binary comparison predicate from a key-function.
Cont operator()(Cont &&cont) const
auto operator()() -> maybe< value_type >
auto operator()() -> impl::maybe< value_type >
size_t operator()(const T &) const
auto operator()(seq< Gen > r) const -> std::vector< typename seq< Gen >::value_type >
decltype(cont.begin()) it
typename InGen::value_type element_type
maybe< element_type > current
typename gen_value_t::iterator iterator
auto first_or_default(const Container &c) -> typename Container::value_type
e.g. const CConstRef<CSeq_align> aln = first_or_default( get_alns_annot(...)->Get() );
impl::foldl_1< Op > foldl_1(Op binary_op)
Init-free version of foldl (first element is used as init); requires at least one element.
size_t approx_size() const noexcept
Cont operator()(const Cont &cont) const
auto operator()() -> maybe< value_type >
typename InGen::value_type value_type
#define RANGELESS_FN_OVERLOAD_FOR_VIEW(...)
typename iterator::value_type value_type
typename InGen::value_type value_type
auto operator()(Iterable inps) const -> seq< gen_c< Iterable >>
synchronized_queue & m_queue
bool operator==(const gt &other) const
typename InGen::value_type gen_value_t
auto operator()() -> maybe< value_type >
decltype(fn(std::move(*it1), std::move(*it2))) value_type
const Gen & get_gen() const
bool operator()(const T &a, const T &b) const
any_seq_t< T > make_typerased(impl::seq< Gen > seq)
Type-erase a seq.
typename InGen::value_type value_type
void erase(Iterator b, Iterator e)
decltype(std::ref(*cont.begin())) value_type
#define RANGELESS_FN_OVERLOAD_FOR_CONT(...)
impl::unique_adjacent_by< F > unique_adjacent_by(F key_fn)
Keep first element from every adjacently-equal run of elements.
auto operator()() -> maybe< value_type >
auto operator()(Cont cont) const -> decltype(group_adjacent_by_t
auto operator()() -> maybe< value_type >
impl::take_top_n_by< by::identity > take_top_n(size_t n)
Return top-n elements, sorted by identity.
Container operator()(Iterable src) &&
auto operator()(std::vector< seq< Gen >> vec_of_seqs) const -> seq< gen< to_seq::gen< std::vector< seq< Gen >> > >>
impl::for_each< F > for_each(F fn)
decltype(fn(*it1, *it2)) value_type
auto operator()() -> maybe< value_type >
auto operator()() -> std::reference_wrapper< const std::string >
typename Iterable::value_type value_type
auto operator()(seq< Gen > range) const -> seq< typename group_adjacent_by_t::template gen< to_seq::gen< std::vector< typename seq< Gen >::value_type >>>>
impl::to_seq to_seq()
Wrap an Iterable, taken by value, as seq yielding elements by-move.
void operator()(Iterable &&src)
impl::where< impl::in_sorted_by< SortedForwardRange, by::identity > > where_not_in_sorted(const SortedForwardRange &r)
Subtract a sorted range.
impl::unique_all_by< F > unique_all_by(F key_fn)
Uniquefy elements globally, as-if unique_adjacent_by pre-sorted by same key.
auto last_or_default(const Container &c) -> typename Container::value_type
impl::drop_while< P > drop_while(P pred)
Drop elements until pred evaluates to false.
Container operator()(Container src) &&
std::map< key_t, bool > seen_t
auto operator()(Iterable1 src1) &&-> seq< gen< Iterable1 >>
typename std::conditional< std::is_same< inp_t, char >::value, std::string, std::vector< inp_t > >::type value_type
auto operator()(const T &x) const -> decltype(*&x.first)
seq & set_resumable(bool res=true)
Iterable operator()(Iterable &&inps) const
impl::drop_last drop_last(size_t n=1)
Drop last n elements.
typename InGen::value_type value_type
void operator()(value_type val) noexcept(false)
Blocking push. May throw queue_closed
auto operator()(T x) -> std::pair< size_t, T >
impl::group_all_by< F > group_all_by(F key_fn)
Similar to group_adjacent_by, but presorts the elements.
get_next_line(std::istream &istr, params p=params{})
impl::lazy_sort_by< F > lazy_sort_by(F key_fn)
Unstable lazy sort.
Cont operator()(const Cont &cont) const
auto operator()(Iterable1 src1) &&-> seq< gen< Iterable1 >>
impl::unique_adjacent_by< by::identity > unique_adjacent()
exists_where operator!() &&