#ifndef lnav_itertools_hh #define lnav_itertools_hh #include #include #include #include "func_util.hh" #include "optional.hpp" namespace lnav { namespace itertools { struct empty {}; struct not_empty {}; struct full { size_t f_max_size; }; namespace details { template struct unwrap_or { T uo_value; }; template struct find_if { P fi_predicate; }; template struct find { T f_value; }; template struct filter_in { F f_func; }; template struct filter_out { F f_func; }; template struct sort_by { C sb_cmp; }; struct sorted {}; template struct mapper { F m_func; }; template struct folder { R f_func; T f_init; }; template struct prepend { T p_value; }; template struct append { T p_value; }; } // namespace details template inline details::unwrap_or unwrap_or(T value) { return details::unwrap_or{ value, }; } template inline details::find_if

find_if(P predicate) { return details::find_if

{ predicate, }; } template inline details::find find(T value) { return details::find{ value, }; } template inline details::filter_in filter_in(F func) { return details::filter_in{ func, }; } template inline details::filter_out filter_out(F func) { return details::filter_out{ func, }; } template inline details::prepend prepend(T value) { return details::prepend{ std::move(value), }; } template inline details::append append(T value) { return details::append{ std::move(value), }; } template inline details::sort_by sort_with(C cmp) { return details::sort_by{cmp}; } template inline auto sort_by(T C::*m) { return sort_with( [m](const C& lhs, const C& rhs) { return lhs.*m < rhs.*m; }); } template inline details::mapper map(F func) { return details::mapper{func}; } template inline details::folder fold(R func, T init) { return details::folder{func, init}; } inline details::sorted sorted() { return details::sorted{}; } template T chain(const T& value1, const Args&... args) { T retval; for (const auto& arg : {value1, args...}) { for (const auto& elem : arg) { retval.emplace_back(elem); } } return retval; } } // namespace itertools } // namespace lnav template nonstd::optional operator|(const C& in, const lnav::itertools::details::find_if

& finder) { for (const auto& elem : in) { if (lnav::func::invoke(finder.fi_predicate, elem)) { return nonstd::make_optional(elem); } } return nonstd::nullopt; } template nonstd::optional operator|(const C& in, const lnav::itertools::details::find& finder) { size_t retval = 0; for (const auto& elem : in) { if (elem == finder.f_value) { return nonstd::make_optional(retval); } retval += 1; } return nonstd::nullopt; } template C operator|(const C& in, const lnav::itertools::details::filter_in& filterer) { C retval; for (const auto& elem : in) { if (lnav::func::invoke(filterer.f_func, elem)) { retval.emplace_back(elem); } } return retval; } template C operator|(const C& in, const lnav::itertools::details::filter_out& filterer) { C retval; for (const auto& elem : in) { if (!lnav::func::invoke(filterer.f_func, elem)) { retval.emplace_back(elem); } } return retval; } template C operator|(C in, const lnav::itertools::details::prepend& prepender) { in.emplace(in.begin(), prepender.p_value); return in; } template C operator|(C in, const lnav::itertools::details::append& appender) { in.emplace_back(appender.p_value); return in; } template T operator|(const C& in, const lnav::itertools::details::folder& folder) { auto accum = folder.f_init; for (const auto& elem : in) { accum = folder.f_func(elem, accum); } return accum; } template T operator|(T in, const lnav::itertools::details::sort_by& sorter) { std::sort(in.begin(), in.end(), sorter.sb_cmp); return in; } template T operator|(T in, const lnav::itertools::details::sorted& sorter) { std::sort(in.begin(), in.end()); return in; } template auto operator|(const T& in, const lnav::itertools::details::mapper& mapper) -> std::vector { using return_type = std::vector; return_type retval; retval.reserve(in.size()); std::transform( in.begin(), in.end(), std::back_inserter(retval), mapper.m_func); return retval; } template auto operator|(const std::vector>& in, const lnav::itertools::details::mapper& mapper) -> std::vector> { using return_type = std::vector>; return_type retval; retval.reserve(in.size()); std::transform( in.begin(), in.end(), std::back_inserter(retval), [&mapper](const auto& elem) { return ((*elem).*mapper.m_func)(); }); return retval; } template auto operator|(const std::vector>& in, const lnav::itertools::details::mapper& mapper) -> std::vector>> { using return_type = std::vector< typename std::remove_reference_t>>; return_type retval; retval.reserve(in.size()); for (const auto& elem : in) { retval.template emplace_back(((*elem).*mapper.m_func)); } return retval; } template auto operator|(nonstd::optional in, const lnav::itertools::details::mapper& mapper) -> nonstd::optional>> { if (!in) { return nonstd::nullopt; } return nonstd::make_optional((in.value()).*mapper.m_func); } template T operator|(nonstd::optional in, const lnav::itertools::details::unwrap_or& unwrapper) { return in.value_or(unwrapper.uo_value); } template auto operator|(const T& in, const lnav::itertools::details::mapper& mapper) -> std::vector> { using return_type = std::vector>; return_type retval; retval.reserve(in.size()); for (const auto& elem : in) { retval.template emplace_back((elem.*mapper.m_func)()); } return retval; } #endif