To make it easy to apply LINQ operators, the library defines, for each operator, a corresponding function that simply returns the function object. Then, coveo::linq::operator|()
is used to apply the LINQ operator to a sequence. What this means internally is that operator|()
calls the operator's function object's operator()()
member function, passing it the sequence to apply it to. The operator's function object must then perform its work and return either a new sequence or perhaps a single value (for a terminal operator).
Here is a real-world example of this. Let's say we wanted to implement a new LINQ operator named step
that steps through a sequence by specific increments. First, we declare the shell of our function object that implements the operator, along with an operator()()
so that the operator can be applied to a sequence:
Note that the sequence's type is not specified in the class template itself - when the operator's function object will be created, we won't know the type of sequence yet. Instead, it is specified as a template argument to operator()()
itself. Also note that the function object's constructor must receive all parameters it needs to work (except for the sequence of course). In our case, we receive the number of steps to use for each invocation.
Because our operator must step through elements of the sequence it is applied to, it needs to return a new sequence. Furthermore, that sequence must wrap the source sequence to be able to iterate its elements. One way to do this without implementing complex sequence logic is by using coveo::enumerable
. This sequence wrapper's only requirement is that we implement a next delegate: a function that, when called, returns a pointer to the next element in the sequence, or nullptr
when done. coveo::enumerable
is used extensively in the coveo::linq
library to implement LINQ operators.
Now, all that is left is to implement the operator logic itself: iterating over the sequence, stepping through elements by a specific increment.
Note that we also added a "helper function" that returns our operator's function object's implementation. This function will be the one used to invoke our LINQ operator:
Implementing a terminal operator is even easier, because there's no need to provide a sequence implementation. Let's say we want to implement a prod
operator that calculates the product of all sequence elements. Like the coveo::linq::sum()
operator, it could be done by using a numerical function to get a numerical value for each sequence element. It could be done like this:
For more examples on how to implement LINQ operators, the easiest way is probably to have a look at the implementation of the operators included in the coveo::linq
library itself. While the helper functions are documented here, it is possible to look at the internal implementations in the file coveo/linq/detail/linq_detail.h :
#ifndef COVEO_LINQ_DETAIL_H
#define COVEO_LINQ_DETAIL_H
#include <algorithm>
#include <cstddef>
#include <forward_list>
#include <functional>
#include <iterator>
#include <map>
#include <memory>
#include <set>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
namespace coveo {
namespace linq {
namespace detail {
template<typename Pred>
class proxy_cmp
{
private:
const typename std::decay<Pred>::type* ppred_;
public:
explicit proxy_cmp(const Pred& pred)
: ppred_(std::addressof(pred)) { }
template<typename T, typename U>
auto operator()(T&& left, U&& right) const -> decltype((*ppred_)(std::forward<T>(left), std::forward<U>(right))) {
return (*ppred_)(std::forward<T>(left), std::forward<U>(right));
}
};
template<typename Pred>
class deref_cmp
{
private:
Pred pred_;
public:
explicit deref_cmp(Pred&& pred)
: pred_(std::forward<Pred>(pred)) { }
template<typename T, typename U>
auto operator()(T* const pleft, U* const pright) const -> decltype(pred_(*pleft, *pright)) {
return pred_(*pleft, *pright);
}
};
template<typename Selector>
class indexless_selector_proxy
{
private:
Selector sel_;
public:
explicit indexless_selector_proxy(Selector&& sel)
: sel_(std::forward<Selector>(sel)) { }
template<typename T>
auto operator()(T&& element, std::size_t) -> decltype(sel_(std::forward<T>(element))) {
return sel_(std::forward<T>(element));
}
};
template<typename Seq>
class deref_next_impl
{
public:
private:
struct deref_info {
Seq seq_;
iterator_type iend_;
explicit deref_info(Seq&& seq)
: seq_(std::forward<Seq>(seq)),
iend_(std::end(seq_)) { }
deref_info(const deref_info&) = delete;
deref_info& operator=(const deref_info&) = delete;
};
using deref_info_sp = std::shared_ptr<deref_info>;
deref_info_sp spinfo_;
iterator_type icur_;
public:
explicit deref_next_impl(Seq&& seq)
: spinfo_(std::make_shared<deref_info>(std::forward<Seq>(seq))),
icur_(std::begin(spinfo_->seq_)) { }
if (icur_ != spinfo_->iend_) {
pobj = *icur_;
++icur_;
}
return pobj;
}
};
template<typename Seq>
auto make_deref_next_impl(Seq&& seq) -> deref_next_impl<Seq> {
return deref_next_impl<Seq>(std::forward<Seq>(seq));
}
template<typename = void>
struct identity {
template<typename T>
auto operator()(T&& obj) const -> decltype(std::forward<T>(obj)) {
return std::forward<T>(obj);
}
};
template<typename = void>
struct pair_of {
template<typename T, typename U>
auto operator()(T&& obj1, U&& obj2) const -> std::pair<T, U> {
return std::pair<T, U>(std::forward<T>(obj1), std::forward<U>(obj2));
}
};
template<typename = void>
struct less {
template<typename T, typename U>
auto operator()(T&& left, U&& right) const -> decltype(std::forward<T>(left) < std::forward<U>(right)) {
return std::forward<T>(left) < std::forward<U>(right);
}
};
template<typename = void>
struct greater {
template<typename T, typename U>
auto operator()(T&& left, U&& right) const -> decltype(std::forward<T>(left) > std::forward<U>(right)) {
return std::forward<T>(left) > std::forward<U>(right);
}
};
template<typename T, typename... Args>
auto make_unique(Args&&... args) -> std::unique_ptr<T> {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
template<typename F>
class aggregate_impl_1
{
private:
const F& agg_f_;
public:
explicit aggregate_impl_1(const F& agg_f)
: agg_f_(agg_f) { }
template<typename Seq>
auto operator()(Seq&& seq) -> typename std::decay<decltype(*std::begin(seq))>::type {
auto it = std::begin(seq);
auto end = std::end(seq);
if (it == end) {
}
for (++it; it != end; ++it) {
}
}
};
template<typename Acc, typename F>
class aggregate_impl_2
{
private:
const Acc& seed_;
const F& agg_f_;
public:
aggregate_impl_2(const Acc& seed, const F& agg_f)
: seed_(seed), agg_f_(agg_f) { }
template<typename Seq>
auto operator()(Seq&& seq) -> Acc {
for (auto&& element : seq) {
}
}
};
template<typename Acc, typename F, typename RF>
class aggregate_impl_3 : public aggregate_impl_2<Acc, F>
{
private:
const RF& result_f_;
public:
aggregate_impl_3(const Acc& seed, const F& agg_f, const RF& result_f)
: aggregate_impl_2<Acc, F>(seed, agg_f), result_f_(result_f) { }
template<typename Seq>
auto operator()(Seq&& seq) -> decltype(result_f_(std::declval<Acc>())) {
return result_f_(aggregate_impl_2<Acc, F>::operator()(seq));
}
};
template<typename Pred>
class all_impl
{
private:
const Pred& pred_;
public:
explicit all_impl(const Pred& pred)
: pred_(pred) { }
template<typename Seq>
auto operator()(Seq&& seq) -> bool {
return std::all_of(std::begin(seq), std::end(seq), pred_);
}
};
template<typename = void>
class any_impl_0
{
public:
template<typename Seq>
auto operator()(Seq&& seq) -> bool {
return std::begin(seq) != std::end(seq);
}
};
template<typename Pred>
class any_impl_1
{
private:
const Pred& pred_;
public:
explicit any_impl_1(const Pred& pred)
: pred_(pred) { }
template<typename Seq>
auto operator()(Seq&& seq) -> bool {
return std::any_of(std::begin(seq), std::end(seq), pred_);
}
};
template<typename F>
class average_impl
{
private:
const F& num_f_;
public:
explicit average_impl(const F& num_f)
: num_f_(num_f) { }
template<typename Seq>
auto operator()(Seq&& seq)
-> typename std::decay<decltype(num_f_(*std::begin(seq)))>::type
{
auto it = std::begin(seq);
auto end = std::end(seq);
if (it == end) {
}
auto total = num_f_(*it);
decltype(total)
count = 1;
for (++it; it != end; ++it) {
total += num_f_(*it);
}
}
};
template<typename U>
class cast_selector
{
public:
template<typename T>
auto operator()(T&& obj) const -> U {
return static_cast<U>(obj);
}
};
template<typename Seq2>
class concat_impl
{
private:
template<typename Seq1>
class next_impl
{
public:
using enum_type = typename std::conditional<std::is_const<typename seq_traits<Seq1>::value_type>::value ||
std::is_const<typename seq_traits<Seq2>::value_type>::value,
private:
class concat_info
{
private:
Seq1 seq1_;
first_iterator_type iend1_;
Seq2 seq2_;
second_iterator_type iend2_;
public:
concat_info(Seq1&& seq1, Seq2&& seq2)
: seq1_(std::forward<Seq1>(seq1)),
iend1_(std::end(seq1_)),
seq2_(std::forward<Seq2>(seq2)),
iend2_(std::end(seq2_)) { }
concat_info(const concat_info&) = delete;
concat_info& operator=(const concat_info&) = delete;
first_iterator_type first_begin() {
return std::begin(seq1_);
}
second_iterator_type second_begin() {
return std::begin(seq2_);
}
auto get_next(first_iterator_type& icur1, second_iterator_type& icur2) -> enum_pointer {
enum_pointer pobj = nullptr;
if (icur1 != iend1_) {
enum_reference robj = *icur1;
pobj = std::addressof(robj);
++icur1;
} else if (icur2 != iend2_) {
enum_reference robj = *icur2;
pobj = std::addressof(robj);
++icur2;
}
return pobj;
}
};
using concat_info_sp = std::shared_ptr<concat_info>;
concat_info_sp spinfo_;
first_iterator_type icur1_;
second_iterator_type icur2_;
public:
next_impl(Seq1&& seq1, Seq2&& seq2)
: spinfo_(std::make_shared<concat_info>(std::forward<Seq1>(seq1), std::forward<Seq2>(seq2))),
icur1_(spinfo_->first_begin()), icur2_(spinfo_->second_begin()) { }
auto operator()() -> decltype(spinfo_->get_next(icur1_, icur2_)) {
return spinfo_->get_next(icur1_, icur2_);
}
};
private:
Seq2 seq2_;
public:
explicit concat_impl(Seq2&& seq2)
: seq2_(std::forward<Seq2>(seq2)) { }
concat_impl(const concat_impl&) = delete;
concat_impl(concat_impl&&) = default;
concat_impl& operator=(const concat_impl&) = delete;
concat_impl& operator=(concat_impl&&) = default;
template<typename Seq1>
auto operator()(Seq1&& seq1)
-> enumerable<typename next_impl<Seq1>::enum_type>
{
typename enumerable<typename next_impl<Seq1>::enum_type>::size_delegate siz;
if (siz1 != nullptr && siz2 != nullptr) {
std::size_t size = siz1() + siz2();
siz = [size]() -> std::size_t { return size; };
}
return { next_impl<Seq1>(std::forward<Seq1>(seq1), std::forward<Seq2>(seq2_)),
siz };
}
};
template<typename T>
class contains_impl_1
{
private:
const T& obj_;
public:
explicit contains_impl_1(const T& obj)
: obj_(obj) { }
template<typename Seq>
auto operator()(Seq&& seq) -> bool {
bool found = false;
for (auto&& element : seq) {
if (element == obj_) {
found = true;
break;
}
}
return found;
}
};
template<typename T, typename Pred>
class contains_impl_2
{
private:
const T& obj_;
const Pred& pred_;
public:
contains_impl_2(const T& obj, const Pred& pred)
: obj_(obj), pred_(pred) { }
template<typename Seq>
auto operator()(Seq&& seq) -> bool {
bool found = false;
for (auto&& element : seq) {
if (pred_(element, obj_)) {
found = true;
break;
}
}
return found;
}
};
template<typename = void>
class count_impl_0
{
private:
template<typename Seq,
typename = typename std::enable_if<coveo::detail::has_size_const_method<typename std::decay<Seq>::type>::value, void>::type>
auto impl(Seq&& seq) -> std::size_t {
return seq.size();
}
template<typename Seq,
typename _V = typename std::enable_if<!coveo::detail::has_size_const_method<typename std::decay<Seq>::type>::value, void*>::type>
auto impl(Seq&& seq, _V = nullptr) -> std::size_t {
return static_cast<std::size_t>(std::distance(std::begin(seq), std::end(seq)));
}
public:
template<typename Seq>
auto operator()(Seq&& seq) -> std::size_t {
return impl(std::forward<Seq>(seq));
}
};
template<typename Pred>
class count_impl_1
{
private:
const Pred& pred_;
public:
explicit count_impl_1(const Pred& pred)
: pred_(pred) { }
template<typename Seq>
auto operator()(Seq&& seq) -> std::size_t {
return static_cast<std::size_t>(std::count_if(std::begin(seq), std::end(seq), pred_));
}
};
template<typename = void>
class default_if_empty_impl_0
{
public:
template<typename Seq>
auto operator()(Seq&& seq)
-> enumerable<typename seq_traits<Seq>::const_value_type>
{
enumerable<typename seq_traits<Seq>::const_value_type> e;
if (any_impl_0<>()(std::forward<Seq>(seq))) {
} else {
}
return e;
}
};
template<typename T>
class default_if_empty_impl_1
{
private:
const T& obj_;
public:
explicit default_if_empty_impl_1(const T& obj)
: obj_(obj) { }
template<typename Seq>
auto operator()(Seq&& seq)
-> enumerable<typename seq_traits<Seq>::const_value_type>
{
enumerable<typename seq_traits<Seq>::const_value_type> e;
if (any_impl_0<>()(std::forward<Seq>(seq))) {
} else {
}
return e;
}
};
template<typename Pred>
class distinct_impl
{
private:
template<typename Seq>
class next_impl
{
private:
using seen_elements_set = std::set<typename seq_traits<Seq>::const_pointer, deref_cmp<proxy_cmp<Pred>>>;
class distinct_info
{
private:
Seq seq_;
iterator_type iend_;
Pred pred_;
public:
distinct_info(Seq&& seq, Pred&& pred)
: seq_(std::forward<Seq>(seq)),
iend_(std::end(seq_)),
pred_(std::forward<Pred>(pred)) { }
distinct_info(const distinct_info&) = delete;
distinct_info& operator=(const distinct_info&) = delete;
iterator_type seq_begin() {
return std::begin(seq_);
}
seen_elements_set init_seen_elements() {
return seen_elements_set(deref_cmp<proxy_cmp<Pred>>(proxy_cmp<Pred>(pred_)));
}
auto get_next(iterator_type& icur, seen_elements_set& seen)
{
for (; pobj == nullptr && icur != iend_; ++icur) {
auto pobjtmp = std::addressof(robjtmp);
if (seen.emplace(pobjtmp).second) {
pobj = pobjtmp;
}
}
return pobj;
}
};
using distinct_info_sp = std::shared_ptr<distinct_info>;
distinct_info_sp spinfo_;
iterator_type icur_;
seen_elements_set seen_;
public:
next_impl(Seq&& seq, Pred&& pred)
: spinfo_(std::make_shared<distinct_info>(std::forward<Seq>(seq), std::forward<Pred>(pred))),
icur_(spinfo_->seq_begin()), seen_(spinfo_->init_seen_elements()) { }
auto operator()() -> decltype(spinfo_->get_next(icur_, seen_)) {
return spinfo_->get_next(icur_, seen_);
}
};
private:
Pred pred_;
public:
explicit distinct_impl(Pred&& pred)
: pred_(std::forward<Pred>(pred)) { }
distinct_impl(const distinct_impl&) = delete;
distinct_impl(distinct_impl&&) = default;
distinct_impl& operator=(const distinct_impl&) = delete;
distinct_impl& operator=(distinct_impl&&) = default;
template<typename Seq>
auto operator()(Seq&& seq)
{
return next_impl<Seq>(std::forward<Seq>(seq), std::forward<Pred>(pred_));
}
};
template<typename = void>
class element_at_impl
{
private:
std::size_t n_;
private:
template<typename Seq>
auto impl(Seq&& seq, std::random_access_iterator_tag) -> decltype(*std::begin(seq)) {
auto icur = std::begin(seq);
auto iend = std::end(seq);
if (static_cast<std::size_t>(iend - icur) <= n_) {
}
icur += n_;
return *icur;
}
template<typename Seq>
auto impl(Seq&& seq, std::input_iterator_tag) -> decltype(*std::begin(seq)) {
auto icur = std::begin(seq);
auto iend = std::end(seq);
for (std::size_t i = 0; i < n_ && icur != iend; ++i, ++icur) {
}
if (icur == iend) {
}
return *icur;
}
public:
explicit element_at_impl(std::size_t n)
: n_(n) { }
template<typename Seq>
auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
return impl(std::forward<Seq>(seq),
}
};
template<typename = void>
class element_at_or_default_impl
{
private:
std::size_t n_;
private:
template<typename Seq>
auto icur = std::begin(seq);
auto iend = std::end(seq);
return static_cast<std::size_t>(iend - icur) > n_ ? *(icur + n_)
}
template<typename Seq>
auto icur = std::begin(seq);
auto iend = std::end(seq);
for (std::size_t i = 0; i < n_ && icur != iend; ++i, ++icur) {
}
return icur != iend ? *icur
}
public:
element_at_or_default_impl(std::size_t n)
: n_(n) { }
template<typename Seq>
return impl(std::forward<Seq>(seq),
}
};
template<typename Seq2, typename Pred>
class except_impl
{
private:
template<typename Seq1>
class next_impl
{
private:
using elements_to_filter_v = std::vector<typename seq_traits<Seq2>::const_pointer>;
class filter_info
{
private:
Seq1 seq1_;
first_iterator_type iend1_;
Seq2 seq2_;
deref_cmp<Pred> pred_;
elements_to_filter_v v_to_filter_;
bool init_called_ = false;
void init() {
auto icur2 = std::begin(seq2_);
auto iend2 = std::end(seq2_);
for (; icur2 != iend2; ++icur2) {
v_to_filter_.emplace_back(std::addressof(robjtmp));
}
std::sort(v_to_filter_.begin(), v_to_filter_.end(), pred_);
init_called_ = true;
}
public:
filter_info(Seq1&& seq1, Seq2&& seq2, Pred&& pred)
: seq1_(std::forward<Seq1>(seq1)), iend1_(std::end(seq1_)),
seq2_(std::forward<Seq2>(seq2)), pred_(std::forward<Pred>(pred)) { }
filter_info(const filter_info&) = delete;
filter_info& operator=(const filter_info&) = delete;
first_iterator_type first_begin() {
return std::begin(seq1_);
}
if (!init_called_) {
init();
}
return std::binary_search(v_to_filter_.cbegin(), v_to_filter_.cend(), pobj, pred_);
}
for (; pobj == nullptr && icur1 != iend1_; ++icur1) {
auto pobjtmp = std::addressof(robjtmp);
if (!filtered(pobjtmp)) {
pobj = pobjtmp;
}
}
return pobj;
}
};
using filter_info_sp = std::shared_ptr<filter_info>;
filter_info_sp spfilter_;
first_iterator_type icur_;
public:
next_impl(Seq1&& seq1, Seq2&& seq2, Pred&& pred)
: spfilter_(std::make_shared<filter_info>(std::forward<Seq1>(seq1),
std::forward<Seq2>(seq2),
std::forward<Pred>(pred))),
icur_(spfilter_->first_begin()) { }
auto operator()() -> decltype(spfilter_->get_next(icur_)) {
return spfilter_->get_next(icur_);
}
};
private:
Seq2 seq2_;
Pred pred_;
public:
except_impl(Seq2&& seq2, Pred&& pred)
: seq2_(std::forward<Seq2>(seq2)), pred_(std::forward<Pred>(pred)) { }
except_impl(const except_impl&) = delete;
except_impl(except_impl&&) = default;
except_impl& operator=(const except_impl&) = delete;
except_impl& operator=(except_impl&&) = default;
template<typename Seq1>
auto operator()(Seq1&& seq1)
{
return next_impl<Seq1>(std::forward<Seq1>(seq1),
std::forward<Seq2>(seq2_),
std::forward<Pred>(pred_));
}
};
template<typename = void>
class first_impl_0
{
public:
template<typename Seq>
auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
auto icur = std::begin(seq);
if (icur == std::end(seq)) {
}
return *icur;
}
};
template<typename Pred>
class first_impl_1
{
private:
const Pred& pred_;
public:
explicit first_impl_1(const Pred& pred)
: pred_(pred) { }
template<typename Seq>
auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
auto icur = std::begin(seq);
auto iend = std::end(seq);
if (icur == iend) {
}
auto ifound = std::find_if(icur, iend, pred_);
if (ifound == iend) {
}
return *ifound;
}
};
template<typename = void>
class first_or_default_impl_0
{
public:
template<typename Seq>
auto icur = std::begin(seq);
return icur != std::end(seq) ? *icur
}
};
template<typename Pred>
class first_or_default_impl_1
{
private:
const Pred& pred_;
public:
explicit first_or_default_impl_1(const Pred& pred)
: pred_(pred) { }
template<typename Seq>
auto iend = std::end(seq);
auto ifound = std::find_if(std::begin(seq), iend, pred_);
return ifound != iend ? *ifound
}
};
template<typename KeySelector,
typename ValueSelector,
typename ResultSelector,
typename Pred>
class group_by_impl
{
private:
template<typename Seq>
class next_impl
{
public:
using value_v = std::vector<typename std::decay<value>::type>;
using values_by_key_m = std::map<typename std::decay<key>::type, value_v, proxy_cmp<Pred>>;
using result = decltype(std::declval<ResultSelector>()(std::declval<key>(), std::declval<values>()));
using result_v = std::vector<typename std::decay<result>::type>;
private:
class groups_info
{
private:
Seq seq_;
KeySelector key_sel_;
ValueSelector value_sel_;
ResultSelector result_sel_;
Pred pred_;
result_v results_;
bool init_called_ = false;
void init() {
values_by_key_m groups{proxy_cmp<Pred>(pred_)};
for (auto&& obj : seq_) {
groups[key_sel_(obj)].emplace_back(value_sel_(obj));
}
results_.reserve(groups.size());
for (auto&& group_pair : groups) {
results_.emplace_back(result_sel_(group_pair.first,
}
init_called_ = true;
}
public:
groups_info(Seq&& seq, KeySelector&& key_sel, ValueSelector&& value_sel,
ResultSelector&& result_sel, Pred&& pred)
: seq_(std::forward<Seq>(seq)),
key_sel_(std::forward<KeySelector>(key_sel)),
value_sel_(std::forward<ValueSelector>(value_sel)),
result_sel_(std::forward<ResultSelector>(result_sel)),
pred_(std::forward<Pred>(pred)) { }
groups_info(const groups_info&) = delete;
groups_info& operator=(const groups_info&) = delete;
const result_v& get_results() {
if (!init_called_) {
init();
}
return results_;
}
};
using groups_info_sp = std::shared_ptr<groups_info>;
groups_info_sp spgroups_;
typename result_v::const_iterator icurr_{};
typename result_v::const_iterator iendr_{};
bool init_called_ = false;
void init() {
const auto& results = spgroups_->get_results();
icurr_ = std::begin(results);
iendr_ = std::end(results);
init_called_ = true;
}
public:
next_impl(Seq&& seq, KeySelector&& key_sel, ValueSelector&& value_sel,
ResultSelector&& result_sel, Pred&& pred)
: spgroups_(std::make_shared<groups_info>(std::forward<Seq>(seq),
std::forward<KeySelector>(key_sel),
std::forward<ValueSelector>(value_sel),
std::forward<ResultSelector>(result_sel),
std::forward<Pred>(pred))) { }
if (!init_called_) {
init();
}
if (icurr_ != iendr_) {
pobj = std::addressof(robj);
++icurr_;
}
return pobj;
}
};
private:
KeySelector key_sel_;
ValueSelector value_sel_;
ResultSelector result_sel_;
Pred pred_;
public:
group_by_impl(KeySelector&& key_sel, ValueSelector&& value_sel,
ResultSelector&& result_sel, Pred&& pred)
: key_sel_(std::forward<KeySelector>(key_sel)),
value_sel_(std::forward<ValueSelector>(value_sel)),
result_sel_(std::forward<ResultSelector>(result_sel)),
pred_(std::forward<Pred>(pred)) { }
group_by_impl(const group_by_impl&) = delete;
group_by_impl(group_by_impl&&) = default;
group_by_impl& operator=(const group_by_impl&) = delete;
group_by_impl& operator=(group_by_impl&&) = default;
template<typename Seq>
auto operator()(Seq&& seq)
-> enumerable<typename seq_traits<typename next_impl<Seq>::result_v>::const_value_type>
{
return next_impl<Seq>(std::forward<Seq>(seq),
std::forward<KeySelector>(key_sel_),
std::forward<ValueSelector>(value_sel_),
std::forward<ResultSelector>(result_sel_),
std::forward<Pred>(pred_));
}
};
template<typename InnerSeq,
typename OuterKeySelector,
typename InnerKeySelector,
typename ResultSelector,
typename Pred>
class group_join_impl
{
private:
template<typename OuterSeq>
class next_impl
{
public:
using inner_element_v = std::vector<typename seq_traits<InnerSeq>::pointer>;
using inner_elements = enumerable<typename seq_traits<InnerSeq>::const_value_type>;
std::declval<inner_elements>()));
using result_v = std::vector<typename std::decay<result>::type>;
private:
class groups_info
{
private:
OuterSeq outer_seq_;
InnerSeq inner_seq_;
OuterKeySelector outer_key_sel_;
InnerKeySelector inner_key_sel_;
ResultSelector result_sel_;
Pred pred_;
result_v results_;
bool init_called_ = false;
void init() {
using groups_m = std::map<typename std::decay<key>::type, inner_element_v, proxy_cmp<Pred>>;
groups_m keyed_inner_elems{proxy_cmp<Pred>(pred_)};
for (auto&& inner_elem : inner_seq_) {
keyed_inner_elems[inner_key_sel_(inner_elem)].emplace_back(std::addressof(robj));
}
const auto iendki = keyed_inner_elems.end();
for (auto&& outer_elem : outer_seq_) {
const key outer_key = outer_key_sel_(outer_elem);
const auto icurki = keyed_inner_elems.find(outer_key);
inner_elements inner_elems;
if (icurki != iendki) {
const std::size_t inner_size = icurki->second.size();
inner_elems = inner_elements(make_deref_next_impl(icurki->second),
[inner_size]() -> std::size_t { return inner_size; });
}
results_.emplace_back(result_sel_(outer_elem, inner_elems));
}
init_called_ = true;
}
public:
groups_info(OuterSeq&& outer_seq, InnerSeq&& inner_seq,
OuterKeySelector&& outer_key_sel, InnerKeySelector&& inner_key_sel,
ResultSelector&& result_sel, Pred&& pred)
: outer_seq_(std::forward<OuterSeq>(outer_seq)),
inner_seq_(std::forward<InnerSeq>(inner_seq)),
outer_key_sel_(std::forward<OuterKeySelector>(outer_key_sel)),
inner_key_sel_(std::forward<InnerKeySelector>(inner_key_sel)),
result_sel_(std::forward<ResultSelector>(result_sel)),
pred_(std::forward<Pred>(pred)) { }
groups_info(const groups_info&) = delete;
groups_info& operator=(const groups_info&) = delete;
const result_v& get_results() {
if (!init_called_) {
init();
}
return results_;
}
};
using groups_info_sp = std::shared_ptr<groups_info>;
groups_info_sp spgroups_;
typename result_v::const_iterator icurr_{};
typename result_v::const_iterator iendr_{};
bool init_called_ = false;
void init() {
const auto& results = spgroups_->get_results();
icurr_ = std::begin(results);
iendr_ = std::end(results);
init_called_ = true;
}
public:
next_impl(OuterSeq&& outer_seq, InnerSeq&& inner_seq,
OuterKeySelector&& outer_key_sel, InnerKeySelector&& inner_key_sel,
ResultSelector&& result_sel, Pred&& pred)
: spgroups_(std::make_shared<groups_info>(std::forward<OuterSeq>(outer_seq),
std::forward<InnerSeq>(inner_seq),
std::forward<OuterKeySelector>(outer_key_sel),
std::forward<InnerKeySelector>(inner_key_sel),
std::forward<ResultSelector>(result_sel),
std::forward<Pred>(pred))) { }
if (!init_called_) {
init();
}
if (icurr_ != iendr_) {
pobj = std::addressof(robj);
++icurr_;
}
return pobj;
}
};
private:
InnerSeq inner_seq_;
OuterKeySelector outer_key_sel_;
InnerKeySelector inner_key_sel_;
ResultSelector result_sel_;
Pred pred_;
public:
group_join_impl(InnerSeq&& inner_seq,
OuterKeySelector&& outer_key_sel,
InnerKeySelector&& inner_key_sel,
ResultSelector&& result_sel,
Pred&& pred)
: inner_seq_(std::forward<InnerSeq>(inner_seq)),
outer_key_sel_(std::forward<OuterKeySelector>(outer_key_sel)),
inner_key_sel_(std::forward<InnerKeySelector>(inner_key_sel)),
result_sel_(std::forward<ResultSelector>(result_sel)),
pred_(std::forward<Pred>(pred)) { }
group_join_impl(const group_join_impl&) = delete;
group_join_impl(group_join_impl&&) = default;
group_join_impl& operator=(const group_join_impl&) = delete;
group_join_impl& operator=(group_join_impl&&) = default;
template<typename OuterSeq>
auto operator()(OuterSeq&& outer_seq)
-> enumerable<typename seq_traits<typename next_impl<OuterSeq>::result_v>::const_value_type>
{
return next_impl<OuterSeq>(std::forward<OuterSeq>(outer_seq),
std::forward<InnerSeq>(inner_seq_),
std::forward<OuterKeySelector>(outer_key_sel_),
std::forward<InnerKeySelector>(inner_key_sel_),
std::forward<ResultSelector>(result_sel_),
std::forward<Pred>(pred_));
}
};
template<typename Seq2, typename Pred>
class intersect_impl
{
public:
template<typename Seq1>
class next_impl
{
private:
using seq2_element_v = std::vector<typename seq_traits<Seq2>::pointer>;
class intersect_info
{
private:
Seq1 seq1_;
first_iterator_type iend1_;
Seq2 seq2_;
deref_cmp<Pred> pred_;
seq2_element_v v_in_seq2_;
bool init_called_ = false;
void init() {
auto icur2 = std::begin(seq2_);
auto iend2 = std::end(seq2_);
for (; icur2 != iend2; ++icur2) {
v_in_seq2_.emplace_back(std::addressof(robjtmp));
}
std::sort(v_in_seq2_.begin(), v_in_seq2_.end(), pred_);
init_called_ = true;
}
public:
intersect_info(Seq1&& seq1, Seq2&& seq2, Pred&& pred)
: seq1_(std::forward<Seq1>(seq1)),
iend1_(std::end(seq1_)),
seq2_(std::forward<Seq2>(seq2)),
pred_(std::forward<Pred>(pred)) { }
intersect_info(const intersect_info&) = delete;
intersect_info& operator=(const intersect_info&) = delete;
first_iterator_type first_begin() {
return std::begin(seq1_);
}
if (!init_called_) {
init();
}
return std::binary_search(v_in_seq2_.cbegin(), v_in_seq2_.cend(), pobj, pred_);
}
for (; pobj == nullptr && icur1 != iend1_; ++icur1) {
auto pobjtmp = std::addressof(robjtmp);
if (is_in_seq2(pobjtmp)) {
pobj = pobjtmp;
}
}
return pobj;
}
};
using intersect_info_sp = std::shared_ptr<intersect_info>;
intersect_info_sp spint_info_;
first_iterator_type icur_;
public:
next_impl(Seq1&& seq1, Seq2&& seq2, Pred&& pred)
: spint_info_(std::make_shared<intersect_info>(std::forward<Seq1>(seq1),
std::forward<Seq2>(seq2),
std::forward<Pred>(pred))),
icur_(spint_info_->first_begin()) { }
auto operator()() -> decltype(spint_info_->get_next(icur_)) {
return spint_info_->get_next(icur_);
}
};
private:
Seq2 seq2_;
Pred pred_;
public:
intersect_impl(Seq2&& seq2, Pred&& pred)
: seq2_(std::forward<Seq2>(seq2)),
pred_(std::forward<Pred>(pred)) { }
intersect_impl(const intersect_impl&) = delete;
intersect_impl(intersect_impl&&) = default;
intersect_impl& operator=(const intersect_impl&) = delete;
intersect_impl& operator=(intersect_impl&&) = default;
template<typename Seq1>
auto operator()(Seq1&& seq1)
{
return next_impl<Seq1>(std::forward<Seq1>(seq1),
std::forward<Seq2>(seq2_),
std::forward<Pred>(pred_));
}
};
template<typename InnerSeq,
typename OuterKeySelector,
typename InnerKeySelector,
typename ResultSelector,
typename Pred>
class join_impl
{
private:
template<typename OuterSeq>
class next_impl
{
public:
using inner_element_v = std::vector<typename seq_traits<InnerSeq>::pointer>;
using result_v = std::vector<typename std::decay<result>::type>;
private:
class join_info
{
private:
OuterSeq outer_seq_;
InnerSeq inner_seq_;
OuterKeySelector outer_key_sel_;
InnerKeySelector inner_key_sel_;
ResultSelector result_sel_;
Pred pred_;
result_v results_;
bool init_called_ = false;
void init() {
using groups_m = std::map<typename std::decay<key>::type, inner_element_v, proxy_cmp<Pred>>;
groups_m keyed_inner_elems{proxy_cmp<Pred>(pred_)};
for (auto&& inner_elem : inner_seq_) {
keyed_inner_elems[inner_key_sel_(inner_elem)].emplace_back(std::addressof(robj));
}
const auto iendki = keyed_inner_elems.end();
for (auto&& outer_elem : outer_seq_) {
const key outer_key = outer_key_sel_(outer_elem);
const auto icurki = keyed_inner_elems.find(outer_key);
if (icurki != iendki) {
for (auto* pinner_elem : icurki->second) {
results_.emplace_back(result_sel_(outer_elem, *pinner_elem));
}
}
}
init_called_ = true;
}
public:
join_info(OuterSeq&& outer_seq, InnerSeq&& inner_seq,
OuterKeySelector&& outer_key_sel, InnerKeySelector&& inner_key_sel,
ResultSelector&& result_sel, Pred&& pred)
: outer_seq_(std::forward<OuterSeq>(outer_seq)),
inner_seq_(std::forward<InnerSeq>(inner_seq)),
outer_key_sel_(std::forward<OuterKeySelector>(outer_key_sel)),
inner_key_sel_(std::forward<InnerKeySelector>(inner_key_sel)),
result_sel_(std::forward<ResultSelector>(result_sel)),
pred_(std::forward<Pred>(pred)) { }
join_info(const join_info&) = delete;
join_info& operator=(const join_info&) = delete;
const result_v& get_results() {
if (!init_called_) {
init();
}
return results_;
}
};
using join_info_sp = std::shared_ptr<join_info>;
join_info_sp spjoin_info_;
typename result_v::const_iterator icurr_{};
typename result_v::const_iterator iendr_{};
bool init_called_ = false;
void init() {
const auto& results = spjoin_info_->get_results();
icurr_ = std::begin(results);
iendr_ = std::end(results);
init_called_ = true;
}
public:
next_impl(OuterSeq&& outer_seq, InnerSeq&& inner_seq,
OuterKeySelector&& outer_key_sel, InnerKeySelector&& inner_key_sel,
ResultSelector&& result_sel, Pred&& pred)
: spjoin_info_(std::make_shared<join_info>(std::forward<OuterSeq>(outer_seq),
std::forward<InnerSeq>(inner_seq),
std::forward<OuterKeySelector>(outer_key_sel),
std::forward<InnerKeySelector>(inner_key_sel),
std::forward<ResultSelector>(result_sel),
std::forward<Pred>(pred))) { }
if (!init_called_) {
init();
}
if (icurr_ != iendr_) {
pobj = std::addressof(robj);
++icurr_;
}
return pobj;
}
};
private:
InnerSeq inner_seq_;
OuterKeySelector outer_key_sel_;
InnerKeySelector inner_key_sel_;
ResultSelector result_sel_;
Pred pred_;
public:
join_impl(InnerSeq&& inner_seq,
OuterKeySelector&& outer_key_sel,
InnerKeySelector&& inner_key_sel,
ResultSelector&& result_sel,
Pred&& pred)
: inner_seq_(std::forward<InnerSeq>(inner_seq)),
outer_key_sel_(std::forward<OuterKeySelector>(outer_key_sel)),
inner_key_sel_(std::forward<InnerKeySelector>(inner_key_sel)),
result_sel_(std::forward<ResultSelector>(result_sel)),
pred_(std::forward<Pred>(pred)) { }
join_impl(const join_impl&) = delete;
join_impl(join_impl&&) = default;
join_impl& operator=(const join_impl&) = delete;
join_impl& operator=(join_impl&&) = default;
template<typename OuterSeq>
auto operator()(OuterSeq&& outer_seq)
-> enumerable<typename seq_traits<typename next_impl<OuterSeq>::result_v>::const_value_type>
{
return next_impl<OuterSeq>(std::forward<OuterSeq>(outer_seq),
std::forward<InnerSeq>(inner_seq_),
std::forward<OuterKeySelector>(outer_key_sel_),
std::forward<InnerKeySelector>(inner_key_sel_),
std::forward<ResultSelector>(result_sel_),
std::forward<Pred>(pred_));
}
};
template<typename = void>
class last_impl_0
{
private:
template<typename Seq>
auto impl(Seq&& seq, std::bidirectional_iterator_tag) -> decltype(*std::begin(seq)) {
auto ricur = seq.rbegin();
if (ricur == seq.rend()) {
}
return *ricur;
}
template<typename Seq>
auto impl(Seq&& seq, std::input_iterator_tag) -> decltype(*std::begin(seq)) {
auto icur = std::begin(seq);
auto iend = std::end(seq);
if (icur == iend) {
}
decltype(icur) iprev;
while (icur != iend) {
iprev = icur;
++icur;
}
return *iprev;
}
public:
template<typename Seq>
auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
return impl(std::forward<Seq>(seq),
}
};
template<typename Pred>
class last_impl_1
{
private:
const Pred& pred_;
private:
template<typename Seq>
auto impl(Seq&& seq, std::bidirectional_iterator_tag) -> decltype(*std::begin(seq)) {
auto ricur = seq.rbegin();
auto riend = seq.rend();
if (ricur == riend) {
}
auto rifound = std::find_if(ricur, riend, pred_);
if (rifound == riend) {
}
return *rifound;
}
template<typename Seq>
auto impl(Seq&& seq, std::input_iterator_tag) -> decltype(*std::begin(seq)) {
auto icur = std::begin(seq);
auto iend = std::end(seq);
if (icur == iend) {
}
auto ifound = iend;
while (icur != iend) {
if (pred_(*icur)) {
ifound = icur;
}
++icur;
}
if (ifound == iend) {
}
return *ifound;
}
public:
explicit last_impl_1(const Pred& pred)
: pred_(pred) { }
template<typename Seq>
auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
return impl(std::forward<Seq>(seq),
}
};
template<typename = void>
class last_or_default_impl_0
{
private:
template<typename Seq>
auto ricur = seq.rbegin();
return ricur != seq.rend() ? *ricur
}
template<typename Seq>
auto icur = std::begin(seq);
auto iend = std::end(seq);
auto iprev = iend;
while (icur != iend) {
iprev = icur;
++icur;
}
return iprev != iend ? *iprev
}
public:
template<typename Seq>
return impl(std::forward<Seq>(seq),
}
};
template<typename Pred>
class last_or_default_impl_1
{
private:
const Pred& pred_;
private:
template<typename Seq>
auto riend = seq.rend();
auto rifound = std::find_if(seq.rbegin(), riend, pred_);
return rifound != riend ? *rifound
}
template<typename Seq>
auto icur = std::begin(seq);
auto iend = std::end(seq);
auto ifound = iend;
while (icur != iend) {
if (pred_(*icur)) {
ifound = icur;
}
++icur;
}
return ifound != iend ? *ifound
}
public:
explicit last_or_default_impl_1(const Pred& pred)
: pred_(pred) { }
template<typename Seq>
return impl(std::forward<Seq>(seq),
}
};
template<typename = void>
class max_impl_0
{
public:
template<typename Seq>
auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
auto iend = std::end(seq);
auto imax = std::max_element(std::begin(seq), iend);
if (imax == iend) {
}
return *imax;
}
};
template<typename Selector>
class max_impl_1
{
private:
const Selector& sel_;
public:
explicit max_impl_1(const Selector& sel)
: sel_(sel) { }
template<typename Seq>
auto operator()(Seq&& seq) -> typename std::decay<decltype(sel_(*std::begin(seq)))>::type {
auto icur = std::begin(seq);
auto iend = std::end(seq);
if (icur == iend) {
}
auto max_val = sel_(*icur);
while (++icur != iend) {
max_val =
std::max(max_val, sel_(*icur));
}
return max_val;
}
};
template<typename = void>
class min_impl_0
{
public:
template<typename Seq>
auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
auto iend = std::end(seq);
auto imin = std::min_element(std::begin(seq), iend);
if (imin == iend) {
}
return *imin;
}
};
template<typename Selector>
class min_impl_1
{
private:
const Selector& sel_;
public:
explicit min_impl_1(const Selector& sel)
: sel_(sel) { }
template<typename Seq>
auto operator()(Seq&& seq) -> typename std::decay<decltype(sel_(*std::begin(seq)))>::type {
auto icur = std::begin(seq);
auto iend = std::end(seq);
if (icur == iend) {
}
auto min_val = sel_(*icur);
while (++icur != iend) {
min_val =
std::min(min_val, sel_(*icur));
}
return min_val;
}
};
template<typename Pred>
class none_impl
{
private:
const Pred& pred_;
public:
explicit none_impl(const Pred& pred)
: pred_(pred) { }
template<typename Seq>
auto operator()(Seq&& seq) -> bool {
return std::none_of(std::begin(seq), std::end(seq), pred_);
}
};
template<typename KeySelector,
typename Pred,
bool Descending,
int _LessValue = Descending ? 1 : -1>
class order_by_comparator
{
private:
KeySelector key_sel_;
Pred pred_;
public:
order_by_comparator(KeySelector&& key_sel, Pred&& pred)
: key_sel_(std::forward<KeySelector>(key_sel)), pred_(std::forward<Pred>(pred)) { }
order_by_comparator(const order_by_comparator&) = delete;
order_by_comparator& operator=(const order_by_comparator&) = delete;
template<typename T1, typename T2>
int operator()(T1&& left, T2&& right) const {
decltype(key_sel_(left)) leftk = key_sel_(left);
decltype(key_sel_(right)) rightk = key_sel_(right);
int cmp;
if (pred_(leftk, rightk)) {
cmp = _LessValue;
} else if (pred_(rightk, leftk)) {
cmp = -_LessValue;
} else {
cmp = 0;
}
return cmp;
}
};
template<typename Cmp1, typename Cmp2>
class dual_order_by_comparator
{
private:
std::unique_ptr<Cmp1> upcmp1_;
std::unique_ptr<Cmp2> upcmp2_;
public:
dual_order_by_comparator(std::unique_ptr<Cmp1>&& upcmp1, std::unique_ptr<Cmp2>&& upcmp2)
: upcmp1_(std::move(upcmp1)), upcmp2_(std::move(upcmp2)) { }
dual_order_by_comparator(const dual_order_by_comparator&) = delete;
dual_order_by_comparator& operator=(const dual_order_by_comparator&) = delete;
template<typename T1, typename T2>
int operator()(T1&& left, T2&& right) const {
int cmp = (*upcmp1_)(left, right);
if (cmp == 0) {
cmp = (*upcmp2_)(left, right);
}
return cmp;
}
};
template<typename Cmp> class order_by_impl;
template<typename Seq, typename Cmp>
class order_by_impl_with_seq
{
template<typename> friend class order_by_impl;
private:
Seq seq_;
std::unique_ptr<Cmp> upcmp_;
bool init_called_ = false;
void init() {
std::vector<typename seq_traits<Seq>::pointer> ordered;
for (auto&& elem : seq_) {
ordered.push_back(std::addressof(robj));
}
std::stable_sort(ordered.begin(),
ordered.end(),
return (*upcmp_)(*pleft, *pright) < 0;
});
const std::size_t num_ordered = ordered.size();
enum_ = { make_deref_next_impl(std::move(ordered)),
[num_ordered]() -> std::size_t { return num_ordered; } };
init_called_ = true;
}
public:
order_by_impl_with_seq(Seq&& seq, std::unique_ptr<Cmp>&& upcmp)
: seq_(std::forward<Seq>(seq)), upcmp_(std::move(upcmp)) { }
order_by_impl_with_seq(const order_by_impl_with_seq&) = delete;
order_by_impl_with_seq(order_by_impl_with_seq&&) = default;
order_by_impl_with_seq& operator=(const order_by_impl_with_seq&) = delete;
order_by_impl_with_seq& operator=(order_by_impl_with_seq&&) = default;
iterator begin() const {
if (!init_called_) {
const_cast<order_by_impl_with_seq<Seq, Cmp>*>(this)->init();
}
return enum_.begin();
}
iterator end() const {
if (!init_called_) {
const_cast<order_by_impl_with_seq<Seq, Cmp>*>(this)->init();
}
return enum_.end();
}
iterator cbegin() const {
return begin();
}
iterator cend() const {
return end();
}
bool has_fast_size() const {
if (!init_called_) {
const_cast<order_by_impl_with_seq<Seq, Cmp>*>(this)->init();
}
return enum_.has_fast_size();
}
std::size_t size() const {
if (!init_called_) {
const_cast<order_by_impl_with_seq<Seq, Cmp>*>(this)->init();
}
return enum_.size();
}
};
template<typename Cmp>
class order_by_impl
{
private:
std::unique_ptr<Cmp> upcmp_;
public:
explicit order_by_impl(std::unique_ptr<Cmp>&& upcmp)
: upcmp_(std::move(upcmp)) { }
order_by_impl(const order_by_impl&) = delete;
order_by_impl(order_by_impl&&) = default;
order_by_impl& operator=(const order_by_impl&) = delete;
order_by_impl& operator=(order_by_impl&&) = default;
template<typename Seq>
auto operator()(Seq&& seq) -> order_by_impl_with_seq<Seq, Cmp> {
return order_by_impl_with_seq<Seq, Cmp>(std::forward<Seq>(seq), std::move(upcmp_));
}
template<typename ImplSeq, typename ImplCmp>
auto operator()(order_by_impl_with_seq<ImplSeq, ImplCmp>&& impl)
-> order_by_impl_with_seq<ImplSeq, dual_order_by_comparator<ImplCmp, Cmp>>
{
using dual_comparator = dual_order_by_comparator<ImplCmp, Cmp>;
auto new_upcmp = detail::make_unique<dual_comparator>(std::move(impl.upcmp_), std::move(upcmp_));
return order_by_impl_with_seq<ImplSeq, dual_comparator>(std::forward<ImplSeq>(impl.seq_), std::move(new_upcmp));
}
};
template<typename = void>
class reverse_impl
{
private:
template<typename Seq>
class next_impl_fast
{
private:
using reverse_iterator = typename std::decay<decltype(std::declval<Seq>().rbegin())>::type;
struct reverse_info {
Seq seq_;
reverse_iterator irend_;
explicit reverse_info(Seq&& seq)
: seq_(std::forward<Seq>(seq)),
irend_(seq_.rend()) { }
reverse_info(const reverse_info&) = delete;
reverse_info& operator=(const reverse_info&) = delete;
};
using reverse_info_sp = std::shared_ptr<reverse_info>;
reverse_info_sp spinfo_;
reverse_iterator ircur_;
public:
explicit next_impl_fast(Seq&& seq)
: spinfo_(std::make_shared<reverse_info>(std::forward<Seq>(seq))),
ircur_(spinfo_->seq_.rbegin()) { }
if (ircur_ != spinfo_->irend_) {
pobj = std::addressof(robj);
++ircur_;
}
return pobj;
}
};
template<typename Seq>
class next_impl_slow
{
private:
using pelems_v = std::vector<typename seq_traits<Seq>::pointer>;
using pelems_v_reverse_iterator = typename pelems_v::reverse_iterator;
struct reverse_info {
Seq seq_;
pelems_v vpelems_;
pelems_v_reverse_iterator virend_;
explicit reverse_info(Seq&& seq)
: seq_(std::forward<Seq>(seq))
{
for (auto&& elem : seq_) {
vpelems_.push_back(std::addressof(robj));
}
virend_ = vpelems_.rend();
}
reverse_info(const reverse_info&) = delete;
reverse_info& operator=(const reverse_info&) = delete;
};
using reverse_info_sp = std::shared_ptr<reverse_info>;
reverse_info_sp spinfo_;
pelems_v_reverse_iterator vircur_;
public:
explicit next_impl_slow(Seq&& seq)
: spinfo_(std::make_shared<reverse_info>(std::forward<Seq>(seq))),
vircur_(spinfo_->vpelems_.rbegin()) { }
if (vircur_ != spinfo_->virend_) {
pobj = *vircur_;
++vircur_;
}
return pobj;
}
std::size_t size() const {
return spinfo_->vpelems_.size();
}
};
template<typename Seq>
auto impl(Seq&& seq, std::bidirectional_iterator_tag)
{
siz);
}
template<typename Seq>
auto impl(Seq&& seq, std::input_iterator_tag)
{
next_impl_slow<Seq> next_impl(std::forward<Seq>(seq));
const std::size_t size = next_impl.size();
auto siz = [size]() -> std::size_t { return size; };
siz);
}
public:
template<typename Seq>
auto operator()(Seq&& seq)
{
return impl(std::forward<Seq>(seq),
}
};
template<typename Selector>
class select_impl
{
public:
template<typename Seq, typename CU, typename RU>
class next_impl
{
private:
using transformed_v = std::vector<RU>;
using transformed_l = std::forward_list<RU>;
using transformed_l_iterator = typename transformed_l::iterator;
struct select_info {
Seq seq_;
iterator_type icur_;
iterator_type iend_;
Selector sel_;
transformed_v vtransformed_;
transformed_l ltransformed_;
transformed_l_iterator llast_;
std::size_t lsize_;
bool use_vector_;
select_info(Seq&& seq, Selector&& sel)
: seq_(std::forward<Seq>(seq)),
icur_(std::begin(seq_)),
iend_(std::end(seq_)),
sel_(std::forward<Selector>(sel)),
vtransformed_(),
ltransformed_(),
llast_(ltransformed_.before_begin()),
lsize_(0),
select_info(const select_info&) = delete;
select_info& operator=(const select_info&) = delete;
auto get_next_in_vector(std::size_t& vncur) -> CU* {
while (vtransformed_.size() <= vncur && icur_ != iend_) {
vtransformed_.emplace_back(sel_(*icur_, vtransformed_.size()));
++icur_;
}
return vtransformed_.size() > vncur ? std::addressof(vtransformed_[vncur++])
: nullptr;
}
auto get_next_in_list(transformed_l_iterator& licur) -> CU* {
while (licur == llast_ && icur_ != iend_) {
llast_ = ltransformed_.emplace_after(llast_, sel_(*icur_, lsize_++));
++icur_;
}
return licur != llast_ ? std::addressof(*++licur)
: nullptr;
}
auto get_next(std::size_t& vncur, transformed_l_iterator& licur) -> CU* {
return use_vector_ ? get_next_in_vector(vncur)
: get_next_in_list(licur);
}
};
using select_info_sp = std::shared_ptr<select_info>;
select_info_sp spinfo_;
std::size_t vncur_;
transformed_l_iterator licur_;
public:
next_impl(Seq&& seq, Selector&& sel)
: spinfo_(std::make_shared<select_info>(std::forward<Seq>(seq),
std::forward<Selector>(sel))),
vncur_(0),
licur_(spinfo_->ltransformed_.before_begin()) { }
auto operator()() -> CU* {
return spinfo_->get_next(vncur_, licur_);
}
};
private:
Selector sel_;
public:
explicit select_impl(Selector&& sel)
: sel_(std::forward<Selector>(sel)) { }
template<typename Seq,
typename _SelectorRes = decltype(std::declval<Selector>()(std::declval<
typename seq_traits<Seq>::reference>(), std::declval<std::size_t>())),
auto operator()(Seq&& seq) -> enumerable<_CU> {
return enumerable<_CU>(next_impl<Seq, _CU, _RU>(std::forward<Seq>(seq), std::forward<Selector>(sel_)),
siz);
}
};
template<typename Selector>
class select_many_impl
{
public:
template<typename Seq, typename CU, typename RU>
class next_impl
{
private:
using transformed_l = std::forward_list<RU>;
using transformed_l_iterator = typename transformed_l::iterator;
struct select_info {
Seq seq_;
iterator_type icur_;
std::size_t idx_;
iterator_type iend_;
Selector sel_;
transformed_l ltransformed_;
transformed_l_iterator llast_;
select_info(Seq&& seq, Selector&& sel)
: seq_(std::forward<Seq>(seq)),
icur_(std::begin(seq_)),
idx_(0),
iend_(std::end(seq_)),
sel_(std::forward<Selector>(sel)),
ltransformed_(),
llast_(ltransformed_.before_begin()) { }
select_info(const select_info&) = delete;
select_info& operator=(const select_info&) = delete;
auto get_next(transformed_l_iterator& licur) -> CU* {
while (licur == llast_ && icur_ != iend_) {
auto new_elements = sel_(*icur_, idx_++);
llast_ = ltransformed_.insert_after(llast_, std::begin(new_elements), std::end(new_elements));
++icur_;
}
return licur != llast_ ? std::addressof(*++licur)
: nullptr;
}
};
using select_info_sp = std::shared_ptr<select_info>;
select_info_sp spinfo_;
transformed_l_iterator licur_;
public:
next_impl(Seq&& seq, Selector&& sel)
: spinfo_(std::make_shared<select_info>(std::forward<Seq>(seq),
std::forward<Selector>(sel))),
licur_(spinfo_->ltransformed_.before_begin()) { }
auto operator()() -> CU* {
return spinfo_->get_next(licur_);
}
};
private:
Selector sel_;
public:
explicit select_many_impl(Selector&& sel)
: sel_(std::forward<Selector>(sel)) { }
template<typename Seq,
auto operator()(Seq&& seq) -> enumerable<_CU> {
return next_impl<Seq, _CU, _RU>(std::forward<Seq>(seq), std::forward<Selector>(sel_));
}
};
template<typename Seq2>
class sequence_equal_impl_1
{
private:
const Seq2& seq2_;
public:
explicit sequence_equal_impl_1(const Seq2& seq2)
: seq2_(seq2) { }
template<typename Seq1>
auto operator()(Seq1&& seq1) -> bool {
auto icur1 = std::begin(seq1);
auto iend1 = std::end(seq1);
auto icur2 = std::begin(seq2_);
auto iend2 = std::end(seq2_);
bool is_equal = true;
for (; is_equal && icur1 != iend1 && icur2 != iend2; ++icur1, ++icur2) {
is_equal = *icur1 == *icur2;
}
return is_equal && icur1 == iend1 && icur2 == iend2;
}
};
template<typename Seq2, typename Pred>
class sequence_equal_impl_2
{
private:
const Seq2& seq2_;
const Pred& pred_;
public:
sequence_equal_impl_2(const Seq2& seq2, const Pred& pred)
: seq2_(seq2), pred_(pred) { }
template<typename Seq1>
auto operator()(Seq1&& seq1) -> bool {
auto icur1 = std::begin(seq1);
auto iend1 = std::end(seq1);
auto icur2 = std::begin(seq2_);
auto iend2 = std::end(seq2_);
bool is_equal = true;
for (; is_equal && icur1 != iend1 && icur2 != iend2; ++icur1, ++icur2) {
is_equal = pred_(*icur1, *icur2);
}
return is_equal && icur1 == iend1 && icur2 == iend2;
}
};
template<typename = void>
class single_impl_0
{
public:
template<typename Seq>
auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
auto ifirst = std::begin(seq);
auto iend = std::end(seq);
if (ifirst == iend) {
}
auto inext = ifirst;
++inext;
if (inext != iend) {
}
return *ifirst;
}
};
template<typename Pred>
class single_impl_1
{
private:
const Pred& pred_;
public:
explicit single_impl_1(const Pred& pred)
: pred_(pred) { }
template<typename Seq>
auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
auto ibeg = std::begin(seq);
auto iend = std::end(seq);
if (ibeg == iend) {
}
auto ifound = std::find_if(ibeg, iend, pred_);
if (ifound == iend) {
}
auto inext = ifound;
++inext;
auto ifoundagain = std::find_if(inext, iend, pred_);
if (ifoundagain != iend) {
}
return *ifound;
}
};
template<typename = void>
class single_or_default_impl_0
{
public:
template<typename Seq>
auto icur = std::begin(seq);
auto iend = std::end(seq);
if (icur != iend) {
auto inext = icur;
++inext;
if (inext != iend) {
icur = iend;
}
}
return icur != iend ? *icur
}
};
template<typename Pred>
class single_or_default_impl_1
{
private:
const Pred& pred_;
public:
explicit single_or_default_impl_1(const Pred& pred)
: pred_(pred) { }
template<typename Seq>
auto iend = std::end(seq);
auto ifound = std::find_if(std::begin(seq), iend, pred_);
if (ifound != iend) {
auto inext = ifound;
++inext;
auto ifoundagain = std::find_if(inext, iend, pred_);
if (ifoundagain != iend) {
ifound = iend;
}
}
return ifound != iend ? *ifound
}
};
template<typename = void>
class skip_n_pred
{
private:
std::size_t n_;
public:
explicit skip_n_pred(std::size_t n)
: n_(n) { }
template<typename T>
auto operator()(T&&, std::size_t idx) -> bool {
return idx < n_;
}
};
template<typename Pred>
class skip_impl
{
public:
template<typename Seq>
class next_impl
{
private:
struct skip_info {
Seq seq_;
iterator_type iend_;
Pred pred_;
skip_info(Seq&& seq, Pred&& pred)
: seq_(std::forward<Seq>(seq)),
iend_(std::end(seq_)),
pred_(std::forward<Pred>(pred)) { }
skip_info(const skip_info&) = delete;
skip_info& operator=(const skip_info&) = delete;
};
using skip_info_sp = std::shared_ptr<skip_info>;
skip_info_sp spinfo_;
iterator_type icur_;
bool init_called_ = false;
void init() {
icur_ = std::begin(spinfo_->seq_);
std::size_t n = 0;
while (icur_ != spinfo_->iend_ && spinfo_->pred_(*icur_, n++)) {
++icur_;
}
init_called_ = true;
}
public:
next_impl(Seq&& seq, Pred&& pred)
: spinfo_(std::make_shared<skip_info>(std::forward<Seq>(seq),
std::forward<Pred>(pred))) { }
if (!init_called_) {
init();
}
if (icur_ != spinfo_->iend_) {
pobj = std::addressof(robj);
++icur_;
}
return pobj;
}
};
private:
Pred pred_;
std::size_t n_;
public:
skip_impl(Pred&& pred, std::size_t n)
: pred_(std::forward<Pred>(pred)),
n_(n) { }
template<typename Seq>
auto operator()(Seq&& seq)
{
if (n_ != static_cast<std::size_t>(-1)) {
if (seq_siz != nullptr) {
const std::size_t seq_size = seq_siz();
const std::size_t size = seq_size > n_ ? seq_size - n_ : 0;
siz = [size]() -> std::size_t { return size; };
}
}
std::forward<Pred>(pred_)),
siz);
}
};
template<typename F>
class sum_impl
{
private:
const F& num_f_;
public:
explicit sum_impl(const F& num_f)
: num_f_(num_f) { }
template<typename Seq>
auto operator()(Seq&& seq) -> typename std::decay<decltype(num_f_(*std::begin(seq)))>::type {
auto it = std::begin(seq);
auto end = std::end(seq);
if (it == end) {
}
auto total = num_f_(*it);
for (++it; it != end; ++it) {
total += num_f_(*it);
}
return total;
}
};
template<typename Pred>
class take_impl
{
public:
template<typename Seq>
class next_impl
{
private:
struct take_info {
Seq seq_;
iterator_type iend_;
Pred pred_;
take_info(Seq&& seq, Pred&& pred)
: seq_(std::forward<Seq>(seq)),
iend_(std::end(seq_)),
pred_(std::forward<Pred>(pred)) { }
take_info(const take_info&) = delete;
take_info& operator=(const take_info&) = delete;
};
using take_info_sp = std::shared_ptr<take_info>;
take_info_sp spinfo_;
iterator_type icur_;
std::size_t n_ = 0;
bool done_ = false;
public:
next_impl(Seq&& seq, Pred&& pred)
: spinfo_(std::make_shared<take_info>(std::forward<Seq>(seq),
std::forward<Pred>(pred))),
icur_(std::begin(spinfo_->seq_)) { }
if (!done_) {
if (icur_ != spinfo_->iend_ && spinfo_->pred_(*icur_, n_++)) {
pobj = std::addressof(robj);
++icur_;
} else {
done_ = true;
}
}
return pobj;
}
};
private:
Pred pred_;
std::size_t n_;
public:
take_impl(Pred&& pred, std::size_t n)
: pred_(std::forward<Pred>(pred)),
n_(n) { }
template<typename Seq>
auto operator()(Seq&& seq)
{
if (n_ != static_cast<std::size_t>(-1)) {
if (seq_siz != nullptr) {
const std::size_t size =
std::min(n_, seq_siz());
siz = [size]() -> std::size_t { return size; };
}
}
std::forward<Pred>(pred_)),
siz);
}
};
template<typename Container>
class to_impl
{
public:
template<typename Seq>
auto operator()(Seq&& seq) -> Container {
return Container(std::begin(std::forward<Seq>(seq)), std::end(std::forward<Seq>(seq)));
}
};
template<typename = void>
class to_vector_impl
{
public:
template<typename Seq>
auto operator()(Seq&& seq) -> std::vector<typename seq_traits<Seq>::raw_value_type> {
std::vector<typename seq_traits<Seq>::raw_value_type> v;
v.insert(v.end(), std::begin(std::forward<Seq>(seq)), std::end(std::forward<Seq>(seq)));
return v;
}
};
template<typename Container, typename KeySelector>
class to_associative_impl_1
{
private:
const KeySelector& key_sel_;
public:
explicit to_associative_impl_1(const KeySelector& key_sel)
: key_sel_(key_sel) { }
template<typename Seq>
auto operator()(Seq&& seq) -> Container {
Container c;
for (auto&& elem : seq) {
auto key = key_sel_(elem);
auto emplace_res = c.emplace(key, elem);
if (!emplace_res.second) {
emplace_res.first->second = elem;
}
}
return c;
}
};
template<typename Container, typename KeySelector, typename ElementSelector>
class to_associative_impl_2
{
private:
const KeySelector& key_sel_;
const ElementSelector& elem_sel_;
public:
to_associative_impl_2(const KeySelector& key_sel, const ElementSelector& elem_sel)
: key_sel_(key_sel), elem_sel_(elem_sel) { }
template<typename Seq>
auto operator()(Seq&& seq) -> Container {
Container c;
for (auto&& elem : seq) {
auto key = key_sel_(elem);
auto mapped = elem_sel_(elem);
auto emplace_res = c.emplace(key, mapped);
if (!emplace_res.second) {
emplace_res.first->second = mapped;
}
}
return c;
}
};
template<typename KeySelector>
class to_map_impl_1
{
private:
const KeySelector& key_sel_;
public:
explicit to_map_impl_1(const KeySelector& key_sel)
: key_sel_(key_sel) { }
template<typename Seq>
auto operator()(Seq&& seq)
-> std::map<typename std::decay<decltype(key_sel_(*std::begin(seq)))>::type,
{
std::map<typename std::decay<decltype(key_sel_(*std::begin(seq)))>::type,
for (auto&& elem : seq) {
auto key = key_sel_(elem);
auto emplace_res = m.emplace(key, elem);
if (!emplace_res.second) {
emplace_res.first->second = elem;
}
}
return m;
}
};
template<typename KeySelector, typename ElementSelector>
class to_map_impl_2
{
private:
const KeySelector& key_sel_;
const ElementSelector& elem_sel_;
public:
to_map_impl_2(const KeySelector& key_sel, const ElementSelector& elem_sel)
: key_sel_(key_sel), elem_sel_(elem_sel) { }
template<typename Seq>
auto operator()(Seq&& seq)
-> std::map<typename std::decay<decltype(key_sel_(*std::begin(seq)))>::type,
typename std::decay<decltype(elem_sel_(*std::begin(seq)))>::type>
{
std::map<typename std::decay<decltype(key_sel_(*std::begin(seq)))>::type,
typename std::decay<decltype(elem_sel_(*std::begin(seq)))>::type> m;
for (auto&& elem : seq) {
auto key = key_sel_(elem);
auto mapped = elem_sel_(elem);
auto emplace_res = m.emplace(key, mapped);
if (!emplace_res.second) {
emplace_res.first->second = mapped;
}
}
return m;
}
};
template<typename Seq2, typename Pred>
class union_impl
{
public:
template<typename Seq1>
class next_impl
{
public:
using enum_type = typename std::conditional<std::is_const<typename seq_traits<Seq1>::value_type>::value ||
std::is_const<typename seq_traits<Seq2>::value_type>::value,
private:
using seen_elements_set = std::set<enum_ptr_type, deref_cmp<proxy_cmp<Pred>>>;
class union_info
{
private:
Seq1 seq1_;
first_iterator_type iend1_;
Seq2 seq2_;
second_iterator_type iend2_;
Pred pred_;
template<typename It>
auto get_next_in_seq(It& icur, const It& iend, seen_elements_set& seen) -> enum_ptr_type {
enum_ptr_type pobj = nullptr;
for (; pobj == nullptr && icur != iend; ++icur) {
enum_ref_type robjtmp = *icur;
auto pobjtmp = std::addressof(robjtmp);
if (seen.emplace(pobjtmp).second) {
pobj = pobjtmp;
}
}
return pobj;
}
public:
union_info(Seq1&& seq1, Seq2&& seq2, Pred&& pred)
: seq1_(std::forward<Seq1>(seq1)),
iend1_(std::end(seq1_)),
seq2_(std::forward<Seq2>(seq2)),
iend2_(std::end(seq2_)),
pred_(std::forward<Pred>(pred)) { }
union_info(const union_info&) = delete;
union_info& operator=(const union_info&) = delete;
first_iterator_type first_begin() {
return std::begin(seq1_);
}
second_iterator_type second_begin() {
return std::begin(seq2_);
}
seen_elements_set init_seen_elements() {
return seen_elements_set(deref_cmp<proxy_cmp<Pred>>(proxy_cmp<Pred>(pred_)));
}
auto get_next(first_iterator_type& icur1, second_iterator_type& icur2, seen_elements_set& seen) -> enum_ptr_type {
enum_ptr_type pobj = get_next_in_seq(icur1, iend1_, seen);
if (pobj == nullptr) {
pobj = get_next_in_seq(icur2, iend2_, seen);
}
return pobj;
}
};
using union_info_sp = std::shared_ptr<union_info>;
union_info_sp spinfo_;
first_iterator_type icur1_;
second_iterator_type icur2_;
seen_elements_set seen_;
public:
next_impl(Seq1&& seq1, Seq2&& seq2, Pred&& pred)
: spinfo_(std::make_shared<union_info>(std::forward<Seq1>(seq1),
std::forward<Seq2>(seq2),
std::forward<Pred>(pred))),
icur1_(spinfo_->first_begin()),
icur2_(spinfo_->second_begin()),
seen_(spinfo_->init_seen_elements()) { }
auto operator()() -> decltype(spinfo_->get_next(icur1_, icur2_, seen_)) {
return spinfo_->get_next(icur1_, icur2_, seen_);
}
};
private:
Seq2 seq2_;
Pred pred_;
public:
explicit union_impl(Seq2&& seq2, Pred&& pred)
: seq2_(std::forward<Seq2>(seq2)),
pred_(std::forward<Pred>(pred)) { }
union_impl(const union_impl&) = delete;
union_impl(union_impl&&) = default;
union_impl& operator=(const union_impl&) = delete;
union_impl& operator=(union_impl&&) = default;
template<typename Seq1>
auto operator()(Seq1&& seq1)
-> enumerable<typename next_impl<Seq1>::enum_type>
{
return next_impl<Seq1>(std::forward<Seq1>(seq1),
std::forward<Seq2>(seq2_),
std::forward<Pred>(pred_));
}
};
template<typename Pred>
class where_impl
{
public:
template<typename Seq>
class next_impl
{
private:
struct where_info {
Seq seq_;
iterator_type iend_;
Pred pred_;
where_info(Seq&& seq, Pred&& pred)
: seq_(std::forward<Seq>(seq)),
iend_(std::end(seq_)),
pred_(std::forward<Pred>(pred)) { }
where_info(const where_info&) = delete;
where_info& operator=(const where_info&) = delete;
};
using where_info_sp = std::shared_ptr<where_info>;
where_info_sp spinfo_;
iterator_type icur_;
std::size_t idx_;
public:
next_impl(Seq&& seq, Pred&& pred)
: spinfo_(std::make_shared<where_info>(std::forward<Seq>(seq),
std::forward<Pred>(pred))),
icur_(std::begin(spinfo_->seq_)), idx_(0) { }
for (; pobj == nullptr && icur_ != spinfo_->iend_; ++icur_, ++idx_) {
auto pobjtmp = std::addressof(robjtmp);
if (spinfo_->pred_(*pobjtmp, idx_)) {
pobj = pobjtmp;
}
}
return pobj;
}
};
private:
Pred pred_;
public:
explicit where_impl(Pred&& pred)
: pred_(std::forward<Pred>(pred)) { }
where_impl(const where_impl&) = delete;
where_impl(where_impl&&) = default;
where_impl& operator=(const where_impl&) = delete;
where_impl& operator=(where_impl&&) = default;
template<typename Seq>
auto operator()(Seq&& seq)
{
return next_impl<Seq>(std::forward<Seq>(seq), std::forward<Pred>(pred_));
}
};
template<typename Seq2, typename ResultSelector>
class zip_impl
{
private:
template<typename Seq1, typename CU, typename RU>
class next_impl
{
private:
using zipped_v = std::vector<RU>;
using zipped_l = std::forward_list<RU>;
using zipped_l_iterator = typename zipped_l::iterator;
struct zip_info {
Seq1 seq1_;
first_iterator_type icur1_;
first_iterator_type iend1_;
Seq2 seq2_;
second_iterator_type icur2_;
second_iterator_type iend2_;
ResultSelector result_sel_;
zipped_v vzipped_;
zipped_l lzipped_;
zipped_l_iterator llast_;
bool use_vector_;
zip_info(Seq1&& seq1, Seq2&& seq2, ResultSelector&& result_sel,
: seq1_(std::forward<Seq1>(seq1)),
icur1_(std::begin(seq1_)),
iend1_(std::end(seq1_)),
seq2_(std::forward<Seq2>(seq2)),
icur2_(std::begin(seq2_)),
iend2_(std::end(seq2_)),
result_sel_(std::forward<ResultSelector>(result_sel)),
vzipped_(),
lzipped_(),
llast_(lzipped_.before_begin()),
use_vector_(siz != nullptr)
{
if (siz != nullptr) {
vzipped_.reserve(siz());
}
}
zip_info(const zip_info&) = delete;
zip_info& operator=(const zip_info&) = delete;
auto get_next_in_vector(std::size_t& vncur) -> CU* {
while (vzipped_.size() <= vncur && icur1_ != iend1_ && icur2_ != iend2_) {
vzipped_.emplace_back(result_sel_(*icur1_, *icur2_));
++icur1_;
++icur2_;
}
return vzipped_.size() > vncur ? std::addressof(vzipped_[vncur++])
: nullptr;
}
auto get_next_in_list(zipped_l_iterator& licur) -> CU* {
while (licur == llast_ && icur1_ != iend1_ && icur2_ != iend2_) {
llast_ = lzipped_.emplace_after(llast_, result_sel_(*icur1_, *icur2_));
++icur1_;
++icur2_;
}
return licur != llast_ ? std::addressof(*++licur)
: nullptr;
}
auto get_next(std::size_t& vncur, zipped_l_iterator& licur) -> CU* {
return use_vector_ ? get_next_in_vector(vncur)
: get_next_in_list(licur);
}
};
using zip_info_sp = std::shared_ptr<zip_info>;
zip_info_sp spinfo_;
std::size_t vncur_;
zipped_l_iterator licur_;
public:
next_impl(Seq1&& seq1, Seq2&& seq2, ResultSelector&& result_sel,
: spinfo_(std::make_shared<zip_info>(std::forward<Seq1>(seq1),
std::forward<Seq2>(seq2),
std::forward<ResultSelector>(result_sel),
siz)),
vncur_(0),
licur_(spinfo_->lzipped_.before_begin()) { }
auto operator()() -> CU* {
return spinfo_->get_next(vncur_, licur_);
}
};
private:
Seq2 seq2_;
ResultSelector result_sel_;
public:
zip_impl(Seq2&& seq2, ResultSelector&& result_sel)
: seq2_(std::forward<Seq2>(seq2)),
result_sel_(std::forward<ResultSelector>(result_sel)) { }
zip_impl(const zip_impl&) = delete;
zip_impl(zip_impl&&) = default;
zip_impl& operator=(const zip_impl&) = delete;
zip_impl& operator=(zip_impl&&) = default;
template<typename Seq1,
auto operator()(Seq1&& seq1) -> enumerable<_CU> {
if (siz1 != nullptr && siz2 != nullptr) {
const std::size_t min_size =
std::min(siz1(), siz2());
siz = [min_size]() -> std::size_t { return min_size; };
}
return enumerable<_CU>(next_impl<Seq1, _CU, _RU>(std::forward<Seq1>(seq1),
std::forward<Seq2>(seq2_),
std::forward<ResultSelector>(result_sel_),
siz),
siz);
}
};
}
}
}
#endif // COVEO_LINQ_DETAIL_H