mirror of https://github.com/tstack/lnav
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
401 lines
7.7 KiB
C++
401 lines
7.7 KiB
C++
|
|
#ifndef lnav_itertools_hh
|
|
#define lnav_itertools_hh
|
|
|
|
#include <algorithm>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#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<typename T>
|
|
struct unwrap_or {
|
|
T uo_value;
|
|
};
|
|
|
|
template<typename P>
|
|
struct find_if {
|
|
P fi_predicate;
|
|
};
|
|
|
|
template<typename T>
|
|
struct find {
|
|
T f_value;
|
|
};
|
|
|
|
template<typename F>
|
|
struct filter_in {
|
|
F f_func;
|
|
};
|
|
|
|
template<typename F>
|
|
struct filter_out {
|
|
F f_func;
|
|
};
|
|
|
|
template<typename C>
|
|
struct sort_by {
|
|
C sb_cmp;
|
|
};
|
|
|
|
struct sorted {};
|
|
|
|
template<typename F>
|
|
struct mapper {
|
|
F m_func;
|
|
};
|
|
|
|
template<typename R, typename T>
|
|
struct folder {
|
|
R f_func;
|
|
T f_init;
|
|
};
|
|
|
|
template<typename T>
|
|
struct prepend {
|
|
T p_value;
|
|
};
|
|
|
|
template<typename T>
|
|
struct append {
|
|
T p_value;
|
|
};
|
|
|
|
} // namespace details
|
|
|
|
template<typename T>
|
|
inline details::unwrap_or<T>
|
|
unwrap_or(T value)
|
|
{
|
|
return details::unwrap_or<T>{
|
|
value,
|
|
};
|
|
}
|
|
|
|
template<typename P>
|
|
inline details::find_if<P>
|
|
find_if(P predicate)
|
|
{
|
|
return details::find_if<P>{
|
|
predicate,
|
|
};
|
|
}
|
|
|
|
template<typename T>
|
|
inline details::find<T>
|
|
find(T value)
|
|
{
|
|
return details::find<T>{
|
|
value,
|
|
};
|
|
}
|
|
|
|
template<typename F>
|
|
inline details::filter_in<F>
|
|
filter_in(F func)
|
|
{
|
|
return details::filter_in<F>{
|
|
func,
|
|
};
|
|
}
|
|
|
|
template<typename F>
|
|
inline details::filter_out<F>
|
|
filter_out(F func)
|
|
{
|
|
return details::filter_out<F>{
|
|
func,
|
|
};
|
|
}
|
|
|
|
template<typename T>
|
|
inline details::prepend<T>
|
|
prepend(T value)
|
|
{
|
|
return details::prepend<T>{
|
|
std::move(value),
|
|
};
|
|
}
|
|
|
|
template<typename T>
|
|
inline details::append<T>
|
|
append(T value)
|
|
{
|
|
return details::append<T>{
|
|
std::move(value),
|
|
};
|
|
}
|
|
|
|
template<typename C>
|
|
inline details::sort_by<C>
|
|
sort_with(C cmp)
|
|
{
|
|
return details::sort_by<C>{cmp};
|
|
}
|
|
|
|
template<typename C, typename T>
|
|
inline auto
|
|
sort_by(T C::*m)
|
|
{
|
|
return sort_with(
|
|
[m](const C& lhs, const C& rhs) { return lhs.*m < rhs.*m; });
|
|
}
|
|
|
|
template<typename F>
|
|
inline details::mapper<F>
|
|
map(F func)
|
|
{
|
|
return details::mapper<F>{func};
|
|
}
|
|
|
|
template<typename R, typename T>
|
|
inline details::folder<R, T>
|
|
fold(R func, T init)
|
|
{
|
|
return details::folder<R, T>{func, init};
|
|
}
|
|
|
|
inline details::sorted
|
|
sorted()
|
|
{
|
|
return details::sorted{};
|
|
}
|
|
|
|
template<typename T, typename... Args>
|
|
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<typename C, typename P>
|
|
nonstd::optional<typename C::value_type>
|
|
operator|(const C& in, const lnav::itertools::details::find_if<P>& finder)
|
|
{
|
|
for (const auto& elem : in) {
|
|
if (lnav::func::invoke(finder.fi_predicate, elem)) {
|
|
return nonstd::make_optional(elem);
|
|
}
|
|
}
|
|
|
|
return nonstd::nullopt;
|
|
}
|
|
|
|
template<typename C, typename T>
|
|
nonstd::optional<size_t>
|
|
operator|(const C& in, const lnav::itertools::details::find<T>& 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<typename C, typename F>
|
|
C
|
|
operator|(const C& in, const lnav::itertools::details::filter_in<F>& filterer)
|
|
{
|
|
C retval;
|
|
|
|
for (const auto& elem : in) {
|
|
if (lnav::func::invoke(filterer.f_func, elem)) {
|
|
retval.emplace_back(elem);
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
template<typename C, typename F>
|
|
C
|
|
operator|(const C& in, const lnav::itertools::details::filter_out<F>& filterer)
|
|
{
|
|
C retval;
|
|
|
|
for (const auto& elem : in) {
|
|
if (!lnav::func::invoke(filterer.f_func, elem)) {
|
|
retval.emplace_back(elem);
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
template<typename C, typename T>
|
|
C
|
|
operator|(C in, const lnav::itertools::details::prepend<T>& prepender)
|
|
{
|
|
in.emplace(in.begin(), prepender.p_value);
|
|
|
|
return in;
|
|
}
|
|
|
|
template<typename C, typename T>
|
|
C
|
|
operator|(C in, const lnav::itertools::details::append<T>& appender)
|
|
{
|
|
in.emplace_back(appender.p_value);
|
|
|
|
return in;
|
|
}
|
|
|
|
template<typename C, typename R, typename T>
|
|
T
|
|
operator|(const C& in, const lnav::itertools::details::folder<R, T>& folder)
|
|
{
|
|
auto accum = folder.f_init;
|
|
|
|
for (const auto& elem : in) {
|
|
accum = folder.f_func(elem, accum);
|
|
}
|
|
|
|
return accum;
|
|
}
|
|
|
|
template<typename T, typename C>
|
|
T
|
|
operator|(T in, const lnav::itertools::details::sort_by<C>& sorter)
|
|
{
|
|
std::sort(in.begin(), in.end(), sorter.sb_cmp);
|
|
|
|
return in;
|
|
}
|
|
|
|
template<typename T>
|
|
T
|
|
operator|(T in, const lnav::itertools::details::sorted& sorter)
|
|
{
|
|
std::sort(in.begin(), in.end());
|
|
|
|
return in;
|
|
}
|
|
|
|
template<typename T, typename F>
|
|
auto
|
|
operator|(const T& in, const lnav::itertools::details::mapper<F>& mapper)
|
|
-> std::vector<decltype(mapper.m_func(typename T::value_type{}))>
|
|
{
|
|
using return_type
|
|
= std::vector<decltype(mapper.m_func(typename T::value_type{}))>;
|
|
return_type retval;
|
|
|
|
retval.reserve(in.size());
|
|
std::transform(
|
|
in.begin(), in.end(), std::back_inserter(retval), mapper.m_func);
|
|
|
|
return retval;
|
|
}
|
|
|
|
template<typename T, typename F>
|
|
auto
|
|
operator|(const std::vector<std::shared_ptr<T>>& in,
|
|
const lnav::itertools::details::mapper<F>& mapper)
|
|
-> std::vector<typename std::remove_const_t<decltype(((*in.front())
|
|
.*mapper.m_func)())>>
|
|
{
|
|
using return_type = std::vector<typename std::remove_const_t<decltype((
|
|
(*in.front()).*mapper.m_func)())>>;
|
|
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<typename T, typename F>
|
|
auto
|
|
operator|(const std::vector<std::shared_ptr<T>>& in,
|
|
const lnav::itertools::details::mapper<F>& mapper)
|
|
-> std::vector<typename std::remove_reference_t<
|
|
typename std::remove_const_t<decltype(((*in.front()).*mapper.m_func))>>>
|
|
{
|
|
using return_type = std::vector<
|
|
typename std::remove_reference_t<typename std::remove_const_t<decltype((
|
|
(*in.front()).*mapper.m_func))>>>;
|
|
return_type retval;
|
|
|
|
retval.reserve(in.size());
|
|
for (const auto& elem : in) {
|
|
retval.template emplace_back(((*elem).*mapper.m_func));
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
template<typename T, typename F>
|
|
auto
|
|
operator|(nonstd::optional<T> in,
|
|
const lnav::itertools::details::mapper<F>& mapper)
|
|
-> nonstd::optional<typename std::remove_reference_t<
|
|
typename std::remove_const_t<decltype(((in.value()).*mapper.m_func))>>>
|
|
{
|
|
if (!in) {
|
|
return nonstd::nullopt;
|
|
}
|
|
|
|
return nonstd::make_optional((in.value()).*mapper.m_func);
|
|
}
|
|
|
|
template<typename T>
|
|
T
|
|
operator|(nonstd::optional<T> in,
|
|
const lnav::itertools::details::unwrap_or<T>& unwrapper)
|
|
{
|
|
return in.value_or(unwrapper.uo_value);
|
|
}
|
|
|
|
template<typename T, typename F>
|
|
auto
|
|
operator|(const T& in, const lnav::itertools::details::mapper<F>& mapper)
|
|
-> std::vector<std::remove_const_t<decltype(((typename T::value_type{})
|
|
.*mapper.m_func)())>>
|
|
{
|
|
using return_type = std::vector<std::remove_const_t<decltype((
|
|
(typename T::value_type{}).*mapper.m_func)())>>;
|
|
return_type retval;
|
|
|
|
retval.reserve(in.size());
|
|
for (const auto& elem : in) {
|
|
retval.template emplace_back((elem.*mapper.m_func)());
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
#endif
|