/** * Copyright (c) 2022, Timothy Stack * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Timothy Stack nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef lnav_itertools_hh #define lnav_itertools_hh #include #include #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; }; struct second {}; 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; }; struct nth { nonstd::optional a_index; }; struct skip { size_t a_count; }; struct unique {}; struct max_value {}; template struct max_with_init { T m_init; }; struct sum {}; } // 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, }; } inline details::second second() { return details::second{}; } inline details::nth nth(nonstd::optional index) { return details::nth{ index, }; } inline details::skip skip(size_t count) { return details::skip{ count, }; } 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}; } inline auto deref() { return map([](auto iter) { return *iter; }); } template inline details::folder fold(R func, T init) { return details::folder{func, init}; } inline details::unique unique() { return details::unique{}; } 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; } inline details::max_value max() { return details::max_value{}; } template inline details::max_with_init max(T init) { return details::max_with_init{init}; } inline details::sum sum() { return details::sum{}; } } // namespace itertools } // namespace lnav template nonstd::optional>::value, typename std::remove_reference_t::const_iterator, typename std::remove_reference_t::iterator>> operator|(C&& in, const lnav::itertools::details::find_if

& finder) { for (auto iter = in.begin(); iter != in.end(); ++iter) { if (lnav::func::invoke(finder.fi_predicate, *iter)) { return nonstd::make_optional(iter); } } 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 nonstd::optional operator|(const C& in, const lnav::itertools::details::nth indexer) { if (!indexer.a_index.has_value()) { return nonstd::nullopt; } if (indexer.a_index.value() < in.size()) { auto iter = in.begin(); std::advance(iter, indexer.a_index.value()); return nonstd::make_optional(iter); } return nonstd::nullopt; } template nonstd::optional operator|(const C& in, const lnav::itertools::details::max_value maxer) { nonstd::optional retval; for (const auto& elem : in) { if (!retval) { retval = elem; continue; } if (elem > retval.value()) { retval = elem; } } return retval; } template typename C::value_type operator|(const C& in, const lnav::itertools::details::max_with_init maxer) { typename C::value_type retval = (typename C::value_type) maxer.m_init; for (const auto& elem : in) { if (elem > retval) { retval = elem; } } return retval; } template typename C::value_type operator|(const C& in, const lnav::itertools::details::sum summer) { typename C::value_type retval{0}; for (const auto& elem : in) { retval += elem; } return retval; } template C operator|(const C& in, const lnav::itertools::details::skip& skipper) { C retval; if (skipper.a_count < in.size()) { auto iter = in.begin(); std::advance(iter, skipper.a_count); for (; iter != in.end(); ++iter) { retval.emplace_back(*iter); } } return retval; } template std::vector operator|(const std::vector>& in, const lnav::itertools::details::filter_in& filterer) { std::vector retval; for (const auto& elem : in) { if (lnav::func::invoke(filterer.f_func, elem)) { retval.emplace_back(elem.get()); } } return retval; } 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 std::set operator|(C&& in, const lnav::itertools::details::unique& sorter) { return {in.begin(), in.end()}; } 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::value, int> = 0> auto operator|(nonstd::optional in, const lnav::itertools::details::mapper& mapper) -> nonstd::optional< typename std::remove_reference_t>> { if (!in) { return nonstd::nullopt; } return nonstd::make_optional(lnav::func::invoke(mapper.m_func, in.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()); 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|(const std::vector& in, const lnav::itertools::details::mapper& mapper) -> std::vector< typename std::remove_const_t>> { using return_type = std::vector< typename std::remove_const_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 auto operator|(nonstd::optional in, const lnav::itertools::details::mapper& mapper) -> nonstd::optional< typename std::remove_const_t>> { 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< std::remove_const_t> { using return_type = std::vector< std::remove_const_t>; return_type retval; retval.reserve(in.size()); for (const auto& elem : in) { retval.template emplace_back((elem.*mapper.m_func)()); } return retval; } #endif