coveo::linq
Implementation of .NET-like LINQ operators in C++
linq_detail.h
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Implementation details of LINQ operators.
4  *
5  * This file contains implementation details for built-in LINQ operators.
6  * It should not be necessary to use this file directly when using the library.
7  * Code in the <tt>coveo::linq::detail</tt> namespace is subject to change
8  * in-between versions.
9  *
10  * @copyright 2016-2019, Coveo Solutions Inc.
11  * Distributed under the Apache License, Version 2.0 (see <a href="https://github.com/coveo/linq/blob/master/LICENSE">LICENSE</a>).
12  */
13 
14 #ifndef COVEO_LINQ_DETAIL_H
15 #define COVEO_LINQ_DETAIL_H
16 
17 #include <coveo/seq/detail/enumerable_detail.h>
18 #include <coveo/seq/sequence_util.h>
19 
20 #include <algorithm>
21 #include <cstddef>
22 #include <forward_list>
23 #include <functional>
24 #include <iterator>
25 #include <map>
26 #include <memory>
27 #include <set>
28 #include <tuple>
29 #include <type_traits>
30 #include <utility>
31 #include <vector>
32 
33 namespace coveo {
34 namespace linq {
35 namespace detail {
36 
37 /**
38  * @internal
39  * @brief Proxy comparator.
40  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
41  *
42  * Comparator that keeps a pointer to another comparator and uses it
43  * to implement <tt>operator()()</tt>. Allows instances of lambdas to be
44  * used as predicates for <tt>set</tt>s, for instance.
45  *
46  * @tparam Pred Predicate to proxy.
47  */
48 template<typename Pred>
49 class proxy_cmp
50 {
51 private:
52  const typename std::decay<Pred>::type* ppred_;
53 
54 public:
55  explicit proxy_cmp(const Pred& pred)
56  : ppred_(std::addressof(pred)) { }
57 
58  template<typename T, typename U>
59  auto operator()(T&& left, U&& right) const -> decltype((*ppred_)(std::forward<T>(left), std::forward<U>(right))) {
60  return (*ppred_)(std::forward<T>(left), std::forward<U>(right));
61  }
62 };
63 
64 /**
65  * @internal
66  * @brief Dereferencing comparator.
67  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
68  *
69  * Comparator that receives pointers to elements to compare,
70  * dereferences them and calls another predicate.
71  *
72  * @tparam Pred Predicate to call with dereferenced pointers.
73  */
74 template<typename Pred>
75 class deref_cmp
76 {
77 private:
78  Pred pred_;
79 
80 public:
81  explicit deref_cmp(Pred&& pred)
82  : pred_(std::forward<Pred>(pred)) { }
83 
84  template<typename T, typename U>
85  auto operator()(T* const pleft, U* const pright) const -> decltype(pred_(*pleft, *pright)) {
86  return pred_(*pleft, *pright);
87  }
88 };
89 
90 /**
91  * @internal
92  * @brief Indexless proxy selector.
93  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
94  *
95  * Selector that can be used with operators that pass an element
96  * and its index, when the index is not needed. Will simply drop
97  * the index and call another selector with the element.
98  *
99  * @tparam Selector Selector to call with element only.
100  */
101 template<typename Selector>
102 class indexless_selector_proxy
103 {
104 private:
105  Selector sel_; // Selector that doesn't care about index
106 
107 public:
108  explicit indexless_selector_proxy(Selector&& sel)
109  : sel_(std::forward<Selector>(sel)) { }
110 
111  template<typename T>
112  auto operator()(T&& element, std::size_t) -> decltype(sel_(std::forward<T>(element))) {
113  return sel_(std::forward<T>(element));
114  }
115 };
116 
117 /**
118  * @internal
119  * @brief Dereferencing next delegate implementation.
120  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
121  *
122  * Implementation of a <tt>coveo::enumerable::next_delegate</tt>
123  * that takes a sequence of pointers and returns references by
124  * dereferencing said pointers. Meant to be used to construct
125  * <tt>coveo::enumerable</tt>s.
126  *
127  * @tparam Seq Sequence containing pointers to wrap.
128  * @see coveo::linq::detail::make_deref_next_impl()
129  */
130 template<typename Seq>
131 class deref_next_impl
132 {
133 public:
134  using iterator_type = typename seq_traits<Seq>::iterator_type;
135 
136 private:
137  // Struct storing sequence and ending. Shared among delegates.
138  struct deref_info {
139  Seq seq_; // Sequence of pointers.
140  iterator_type iend_; // Iterator pointing at end of seq_.
141 
142  explicit deref_info(Seq&& seq)
143  : seq_(std::forward<Seq>(seq)),
144  iend_(std::end(seq_)) { }
145 
146  // Cannot copy/move, stored in a shared_ptr
147  deref_info(const deref_info&) = delete;
148  deref_info& operator=(const deref_info&) = delete;
149  };
150  using deref_info_sp = std::shared_ptr<deref_info>;
151 
152  deref_info_sp spinfo_; // Shared sequence info.
153  iterator_type icur_; // Iterator pointing at current element.
154 
155 public:
156  explicit deref_next_impl(Seq&& seq)
157  : spinfo_(std::make_shared<deref_info>(std::forward<Seq>(seq))),
158  icur_(std::begin(spinfo_->seq_)) { }
159 
160  auto operator()() -> typename seq_traits<Seq>::value_type {
161  typename seq_traits<Seq>::value_type pobj = nullptr;
162  if (icur_ != spinfo_->iend_) {
163  pobj = *icur_;
164  ++icur_;
165  }
166  return pobj;
167  }
168 };
169 
170 /// @cond
171 
172 /**
173  * @internal
174  * @brief Helper to create dereferencing next delegates.
175  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
176  *
177  * Helper function to create instances of <tt>coveo::linq::detail::deref_next_impl</tt>.
178  * Allows easier creation by deducing the sequence type.
179  *
180  * @tparam Seq Sequence containing pointers to wrap.
181  * @see coveo::linq::detail::deref_next_impl
182  */
183 template<typename Seq>
184 auto make_deref_next_impl(Seq&& seq) -> deref_next_impl<Seq> {
185  return deref_next_impl<Seq>(std::forward<Seq>(seq));
186 }
187 
188 /// @endcond
189 
190 /**
191  * @internal
192  * @brief Identity unary predicate.
193  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
194  *
195  * Transparent unary predictate that returns values unmodified.
196  */
197 template<typename = void>
198 struct identity {
199  template<typename T>
200  auto operator()(T&& obj) const -> decltype(std::forward<T>(obj)) {
201  return std::forward<T>(obj);
202  }
203 };
204 
205 /**
206  * @internal
207  * @brief Pair-creating binary predicate.
208  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
209  *
210  * Transparent binary predictate that returns pairs of its two arguments.
211  */
212 template<typename = void>
213 struct pair_of {
214  template<typename T, typename U>
215  auto operator()(T&& obj1, U&& obj2) const -> std::pair<T, U> {
216  return std::pair<T, U>(std::forward<T>(obj1), std::forward<U>(obj2));
217  }
218 };
219 
220 /**
221  * @internal
222  * @brief Less-than predicate.
223  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
224  *
225  * Transparent less-than binary predicate, like
226  * <tt>std::less</tt> from C++14.
227  */
228 template<typename = void>
229 struct less {
230  template<typename T, typename U>
231  auto operator()(T&& left, U&& right) const -> decltype(std::forward<T>(left) < std::forward<U>(right)) {
232  return std::forward<T>(left) < std::forward<U>(right);
233  }
234 };
235 
236 /**
237  * @internal
238  * @brief Greater-than predicate.
239  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
240  *
241  * Transparent greater-than binary predicate, like
242  * <tt>std::greater</tt> from C++14.
243  */
244 template<typename = void>
245 struct greater {
246  template<typename T, typename U>
247  auto operator()(T&& left, U&& right) const -> decltype(std::forward<T>(left) > std::forward<U>(right)) {
248  return std::forward<T>(left) > std::forward<U>(right);
249  }
250 };
251 
252 /// @cond
253 
254 /**
255  * @internal
256  * @brief Helper to create <tt>std::unique_ptr</tt>s.
257  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
258  *
259  * Creates an object and stores it in a <tt>std::unique_ptr</tt>.
260  * Like <tt>std::make_unique()</tt> from C++14.
261  *
262  * @tparam T Object to store in the @c unique_ptr.
263  * @tparam Args Arguments to forward to the constructor of @c T.
264  */
265 template<typename T, typename... Args>
266 auto make_unique(Args&&... args) -> std::unique_ptr<T> {
267  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
268 }
269 
270 /// @endcond
271 
272 /**
273  * @internal
274  * @brief <tt>coveo::linq::aggregate()</tt> implementation (1).
275  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
276  *
277  * Implementation of the <tt>coveo::linq::aggregate()</tt> LINQ operator.
278  * Version with a single argument (aggregate function).
279  *
280  * @tparam F Function to aggregate the values.
281  * @see coveo::linq::aggregate()
282  */
283 template<typename F>
284 class aggregate_impl_1
285 {
286 private:
287  const F& agg_f_;
288 
289 public:
290  explicit aggregate_impl_1(const F& agg_f)
291  : agg_f_(agg_f) { }
292 
293  template<typename Seq>
294  auto operator()(Seq&& seq) -> typename std::decay<decltype(*std::begin(seq))>::type {
295  auto it = std::begin(seq);
296  auto end = std::end(seq);
297  if (it == end) {
298  throw_linq_empty_sequence();
299  }
300  auto aggregate(*it);
301  for (++it; it != end; ++it) {
302  aggregate = agg_f_(aggregate, *it);
303  }
304  return aggregate;
305  }
306 };
307 
308 /**
309  * @internal
310  * @brief <tt>coveo::linq::aggregate()</tt> implementation (2).
311  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
312  *
313  * Implementation of the <tt>coveo::linq::aggregate()</tt> LINQ operator.
314  * Version with two arguments (initial value and aggregate function).
315  *
316  * @tparam Acc Type of aggregate value.
317  * @tparam F Function to aggregate the values.
318  * @see coveo::linq::aggregate()
319  */
320 template<typename Acc, typename F>
321 class aggregate_impl_2
322 {
323 private:
324  const Acc& seed_;
325  const F& agg_f_;
326 
327 public:
328  aggregate_impl_2(const Acc& seed, const F& agg_f)
329  : seed_(seed), agg_f_(agg_f) { }
330 
331  template<typename Seq>
332  auto operator()(Seq&& seq) -> Acc {
333  Acc aggregate(seed_);
334  for (auto&& element : seq) {
335  aggregate = agg_f_(aggregate, element);
336  }
337  return aggregate;
338  }
339 };
340 
341 /**
342  * @internal
343  * @brief <tt>coveo::linq::aggregate()</tt> implementation (3).
344  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
345  *
346  * Implementation of the <tt>coveo::linq::aggregate()</tt> LINQ operator.
347  * Version with three arguments (initial value, aggregate function and
348  * result function).
349  *
350  * @tparam Acc Type of aggregate value.
351  * @tparam F Function to aggregate the values.
352  * @tparam RF Function called to produce final result from aggregate.
353  * @see coveo::linq::aggregate()
354  */
355 template<typename Acc, typename F, typename RF>
356 class aggregate_impl_3 : public aggregate_impl_2<Acc, F>
357 {
358 private:
359  const RF& result_f_;
360 
361 public:
362  aggregate_impl_3(const Acc& seed, const F& agg_f, const RF& result_f)
363  : aggregate_impl_2<Acc, F>(seed, agg_f), result_f_(result_f) { }
364 
365  template<typename Seq>
366  auto operator()(Seq&& seq) -> decltype(result_f_(std::declval<Acc>())) {
367  return result_f_(aggregate_impl_2<Acc, F>::operator()(seq));
368  }
369 };
370 
371 /**
372  * @internal
373  * @brief <tt>coveo::linq::all()</tt> implementation.
374  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
375  *
376  * Implementation of the <tt>coveo::linq::all()</tt> LINQ operator.
377  *
378  * @tparam Pred Predicate used on sequence elements.
379  * @see coveo::linq::all()
380  */
381 template<typename Pred>
382 class all_impl
383 {
384 private:
385  const Pred& pred_;
386 
387 public:
388  explicit all_impl(const Pred& pred)
389  : pred_(pred) { }
390 
391  template<typename Seq>
392  auto operator()(Seq&& seq) -> bool {
393  return std::all_of(std::begin(seq), std::end(seq), pred_);
394  }
395 };
396 
397 /**
398  * @internal
399  * @brief <tt>coveo::linq::any()</tt> implementation (0).
400  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
401  *
402  * Implementation of the <tt>coveo::linq::any()</tt> LINQ operator.
403  * Version without argument.
404  *
405  * @see coveo::linq::any()
406  */
407 template<typename = void>
408 class any_impl_0
409 {
410 public:
411  template<typename Seq>
412  auto operator()(Seq&& seq) -> bool {
413  return std::begin(seq) != std::end(seq);
414  }
415 };
416 
417 /**
418  * @internal
419  * @brief <tt>coveo::linq::any()</tt> implementation (1).
420  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
421  *
422  * Implementation of the <tt>coveo::linq::any()</tt> LINQ operator.
423  * Version with predicate.
424  *
425  * @tparam Pred Predicate used on sequence elements.
426  * @see coveo::linq::any()
427  */
428 template<typename Pred>
429 class any_impl_1
430 {
431 private:
432  const Pred& pred_;
433 
434 public:
435  explicit any_impl_1(const Pred& pred)
436  : pred_(pred) { }
437 
438  template<typename Seq>
439  auto operator()(Seq&& seq) -> bool {
440  return std::any_of(std::begin(seq), std::end(seq), pred_);
441  }
442 };
443 
444 /**
445  * @internal
446  * @brief <tt>coveo::linq::average()</tt> implementation.
447  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
448  *
449  * Implementation of the <tt>coveo::linq::average()</tt> LINQ operator.
450  *
451  * @tparam F Function to get numeric value for each element.
452  * @see coveo::linq::average()
453  */
454 template<typename F>
455 class average_impl
456 {
457 private:
458  const F& num_f_;
459 
460 public:
461  explicit average_impl(const F& num_f)
462  : num_f_(num_f) { }
463 
464  template<typename Seq>
465  auto operator()(Seq&& seq)
466  -> typename std::decay<decltype(num_f_(*std::begin(seq)))>::type
467  {
468  auto it = std::begin(seq);
469  auto end = std::end(seq);
470  if (it == end) {
471  throw_linq_empty_sequence();
472  }
473  auto total = num_f_(*it);
474  decltype(total) count = 1;
475  for (++it; it != end; ++it) {
476  total += num_f_(*it);
477  ++count;
478  }
479  return total / count;
480  }
481 };
482 
483 /**
484  * @internal
485  * @brief Selector for <tt>coveo::linq::cast()</tt>.
486  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
487  *
488  * Selector used to implement the <tt>coveo::linq::cast()</tt>
489  * LINQ operator through <tt>coveo::linq::select()</tt>.
490  *
491  * @tparam U Type to cast the elements to.
492  * @see coveo::linq::cast()
493  */
494 template<typename U>
495 class cast_selector
496 {
497 public:
498  template<typename T>
499  auto operator()(T&& obj) const -> U {
500  return static_cast<U>(obj);
501  }
502 };
503 
504 /**
505  * @internal
506  * @brief <tt>coveo::linq::concat()</tt> implementation.
507  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
508  *
509  * Implementation of the <tt>coveo::linq::concat()</tt> LINQ operator.
510  *
511  * @tparam Seq2 Second sequence to concatenate (the first one was passed
512  * via the call to <tt>coveo::linq::from()</tt>).
513  * @see coveo::linq::concat()
514  */
515 template<typename Seq2>
516 class concat_impl
517 {
518 private:
519  // Implementation of next delegate that concatenates two sequences
520  template<typename Seq1>
521  class next_impl
522  {
523  public:
524  // Type of element returned by this next delegate. The elements will be const
525  // if at least one sequence is const.
526  using enum_type = typename std::conditional<std::is_const<typename seq_traits<Seq1>::value_type>::value ||
527  std::is_const<typename seq_traits<Seq2>::value_type>::value,
528  typename seq_traits<Seq1>::const_value_type,
529  typename seq_traits<Seq1>::value_type>::type;
530  using enum_pointer = typename seq_element_traits<enum_type>::pointer;
531  using enum_reference = typename seq_element_traits<enum_type>::reference;
532 
533  private:
534  // Type of iterators for both sequences
535  using first_iterator_type = typename seq_traits<Seq1>::iterator_type;
536  using second_iterator_type = typename seq_traits<Seq2>::iterator_type;
537 
538  // Information used to concatenate sequences. Shared among delegates.
539  class concat_info
540  {
541  private:
542  Seq1 seq1_; // First sequence to concatenate
543  first_iterator_type iend1_; // End of first sequence
544  Seq2 seq2_; // Second sequence to concatenate
545  second_iterator_type iend2_; // End of second sequence
546 
547  public:
548  concat_info(Seq1&& seq1, Seq2&& seq2)
549  : seq1_(std::forward<Seq1>(seq1)),
550  iend1_(std::end(seq1_)),
551  seq2_(std::forward<Seq2>(seq2)),
552  iend2_(std::end(seq2_)) { }
553 
554  // Cannot move/copy, stored in a shared_ptr
555  concat_info(const concat_info&) = delete;
556  concat_info& operator=(const concat_info&) = delete;
557 
558  first_iterator_type first_begin() {
559  return std::begin(seq1_);
560  }
561  second_iterator_type second_begin() {
562  return std::begin(seq2_);
563  }
564 
565  // Returns next element from one of the sequences or nullptr when done
566  auto get_next(first_iterator_type& icur1, second_iterator_type& icur2) -> enum_pointer {
567  // First return all elements from first sequence, then from second sequence.
568  enum_pointer pobj = nullptr;
569  if (icur1 != iend1_) {
570  enum_reference robj = *icur1;
571  pobj = std::addressof(robj);
572  ++icur1;
573  } else if (icur2 != iend2_) {
574  enum_reference robj = *icur2;
575  pobj = std::addressof(robj);
576  ++icur2;
577  }
578  return pobj;
579  }
580  };
581  using concat_info_sp = std::shared_ptr<concat_info>;
582 
583  concat_info_sp spinfo_; // Shared concat info
584  first_iterator_type icur1_; // Current position in first sequence
585  second_iterator_type icur2_; // Current position in second sequence
586 
587  public:
588  next_impl(Seq1&& seq1, Seq2&& seq2)
589  : spinfo_(std::make_shared<concat_info>(std::forward<Seq1>(seq1), std::forward<Seq2>(seq2))),
590  icur1_(spinfo_->first_begin()), icur2_(spinfo_->second_begin()) { }
591 
592  auto operator()() -> decltype(spinfo_->get_next(icur1_, icur2_)) {
593  return spinfo_->get_next(icur1_, icur2_);
594  }
595  };
596 
597 private:
598  Seq2 seq2_; // Second sequence (possibly a ref)
599 
600 public:
601  explicit concat_impl(Seq2&& seq2)
602  : seq2_(std::forward<Seq2>(seq2)) { }
603 
604  // Movable but not copyable
605  concat_impl(const concat_impl&) = delete;
606  concat_impl(concat_impl&&) = default;
607  concat_impl& operator=(const concat_impl&) = delete;
608  concat_impl& operator=(concat_impl&&) = default;
609 
610  template<typename Seq1>
611  auto operator()(Seq1&& seq1)
612  -> enumerable<typename next_impl<Seq1>::enum_type>
613  {
614  auto siz1 = try_get_size_delegate(seq1);
615  auto siz2 = try_get_size_delegate(seq2_);
616  typename enumerable<typename next_impl<Seq1>::enum_type>::size_delegate siz;
617  if (siz1 != nullptr && siz2 != nullptr) {
618  std::size_t size = siz1() + siz2();
619  siz = [size]() -> std::size_t { return size; };
620  }
621  return { next_impl<Seq1>(std::forward<Seq1>(seq1), std::forward<Seq2>(seq2_)),
622  siz };
623  }
624 };
625 
626 /**
627  * @internal
628  * @brief <tt>coveo::linq::contains()</tt> implementation (1).
629  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
630  *
631  * Implementation of the <tt>coveo::linq::contains()</tt> LINQ operator.
632  * Version with one argument (object to look for).
633  *
634  * @tparam T Type of object to look for.
635  * @see coveo::linq::contains()
636  */
637 template<typename T>
638 class contains_impl_1
639 {
640 private:
641  const T& obj_; // Object to look for.
642 
643 public:
644  explicit contains_impl_1(const T& obj)
645  : obj_(obj) { }
646 
647  template<typename Seq>
648  auto operator()(Seq&& seq) -> bool {
649  bool found = false;
650  for (auto&& element : seq) {
651  if (element == obj_) {
652  found = true;
653  break;
654  }
655  }
656  return found;
657  }
658 };
659 
660 /**
661  * @internal
662  * @brief <tt>coveo::linq::contains()</tt> implementation (2).
663  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
664  *
665  * Implementation of the <tt>coveo::linq::contains()</tt> LINQ operator.
666  * Version with two arguments (object to look for and predicate).
667  *
668  * @tparam T Type of object to look for.
669  * @tparam Pred Predicate used to compare elements.
670  * @see coveo::linq::contains()
671  */
672 template<typename T, typename Pred>
673 class contains_impl_2
674 {
675 private:
676  const T& obj_; // Object to look for.
677  const Pred& pred_; // Predicate used to compare objects.
678 
679 public:
680  contains_impl_2(const T& obj, const Pred& pred)
681  : obj_(obj), pred_(pred) { }
682 
683  template<typename Seq>
684  auto operator()(Seq&& seq) -> bool {
685  bool found = false;
686  for (auto&& element : seq) {
687  if (pred_(element, obj_)) {
688  found = true;
689  break;
690  }
691  }
692  return found;
693  }
694 };
695 
696 /**
697  * @internal
698  * @brief <tt>coveo::linq::count()</tt> implementation (0).
699  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
700  *
701  * Implementation of the <tt>coveo::linq::count()</tt> LINQ operator.
702  * Version without argument.
703  *
704  * @see coveo::linq::count()
705  */
706 template<typename = void>
707 class count_impl_0
708 {
709 private:
710  // Used if sequence has size() method
711  template<typename Seq,
712  typename = typename std::enable_if<coveo::detail::has_size_const_method<typename std::decay<Seq>::type>::value, void>::type>
713  auto impl(Seq&& seq) -> std::size_t {
714  return seq.size();
715  }
716 
717  // Used otherwise (no choice but to use distance)
718  template<typename Seq,
719  typename _V = typename std::enable_if<!coveo::detail::has_size_const_method<typename std::decay<Seq>::type>::value, void*>::type>
720  auto impl(Seq&& seq, _V = nullptr) -> std::size_t {
721  return static_cast<std::size_t>(std::distance(std::begin(seq), std::end(seq)));
722  }
723 
724 public:
725  template<typename Seq>
726  auto operator()(Seq&& seq) -> std::size_t {
727  return impl(std::forward<Seq>(seq));
728  }
729 };
730 
731 /**
732  * @internal
733  * @brief <tt>coveo::linq::count()</tt> implementation (1).
734  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
735  *
736  * Implementation of the <tt>coveo::linq::count()</tt> LINQ operator.
737  * Version with predicate.
738  *
739  * @tparam Pred Predicate used on elements.
740  * @see coveo::linq::count()
741  */
742 template<typename Pred>
743 class count_impl_1
744 {
745 private:
746  const Pred& pred_; // Predicate to satisfy.
747 
748 public:
749  explicit count_impl_1(const Pred& pred)
750  : pred_(pred) { }
751 
752  template<typename Seq>
753  auto operator()(Seq&& seq) -> std::size_t {
754  return static_cast<std::size_t>(std::count_if(std::begin(seq), std::end(seq), pred_));
755  }
756 };
757 
758 /**
759  * @internal
760  * @brief <tt>coveo::linq::default_if_empty()</tt> implementation (0).
761  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
762  *
763  * Implementation of the <tt>coveo::linq::default_if_empty()</tt> LINQ operator.
764  * Version without argument.
765  *
766  * @see coveo::linq::default_if_empty()
767  */
768 template<typename = void>
769 class default_if_empty_impl_0
770 {
771 public:
772  template<typename Seq>
773  auto operator()(Seq&& seq)
774  -> enumerable<typename seq_traits<Seq>::const_value_type>
775  {
776  enumerable<typename seq_traits<Seq>::const_value_type> e;
777  if (any_impl_0<>()(std::forward<Seq>(seq))) {
778  e = enumerate_container(std::forward<Seq>(seq));
779  } else {
780  e = enumerate_one(typename seq_traits<Seq>::raw_value_type());
781  }
782  return e;
783  }
784 };
785 
786 /**
787  * @internal
788  * @brief <tt>coveo::linq::default_if_empty()</tt> implementation (1).
789  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
790  *
791  * Implementation of the <tt>coveo::linq::default_if_empty()</tt> LINQ operator.
792  * Version with one argument (default value).
793  *
794  * @tparam T Type of default value.
795  * @see coveo::linq::default_if_empty()
796  */
797 template<typename T>
798 class default_if_empty_impl_1
799 {
800 private:
801  const T& obj_; // Object to use to create default value if empty.
802 
803 public:
804  explicit default_if_empty_impl_1(const T& obj)
805  : obj_(obj) { }
806 
807  template<typename Seq>
808  auto operator()(Seq&& seq)
809  -> enumerable<typename seq_traits<Seq>::const_value_type>
810  {
811  enumerable<typename seq_traits<Seq>::const_value_type> e;
812  if (any_impl_0<>()(std::forward<Seq>(seq))) {
813  e = enumerate_container(std::forward<Seq>(seq));
814  } else {
815  e = enumerate_one(typename seq_traits<Seq>::raw_value_type(obj_));
816  }
817  return e;
818  }
819 };
820 
821 /**
822  * @internal
823  * @brief <tt>coveo::linq::distinct()</tt> implementation.
824  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
825  *
826  * Implementation of the <tt>coveo::linq::distinct()</tt> LINQ operator.
827  *
828  * @tparam Pred Predicate used to compare elements.
829  * @see coveo::linq::distinct()
830  */
831 template<typename Pred>
832 class distinct_impl
833 {
834 private:
835  // Implementation of next delegate that filters duplicate elements
836  template<typename Seq>
837  class next_impl
838  {
839  private:
840  // Type of iterator for the sequence
841  using iterator_type = typename seq_traits<Seq>::iterator_type;
842 
843  // Set storing pointers to seen elements
844  using seen_elements_set = std::set<typename seq_traits<Seq>::const_pointer, deref_cmp<proxy_cmp<Pred>>>;
845 
846  // Info used to produce distinct elements. Shared among delegates.
847  class distinct_info
848  {
849  private:
850  Seq seq_; // Sequence being iterated
851  iterator_type iend_; // Iterator pointing at end of sequence
852  Pred pred_; // Predicate ordering the elements
853 
854  public:
855  distinct_info(Seq&& seq, Pred&& pred)
856  : seq_(std::forward<Seq>(seq)),
857  iend_(std::end(seq_)),
858  pred_(std::forward<Pred>(pred)) { }
859 
860  // Cannot copy/move, stored in a shared_ptr
861  distinct_info(const distinct_info&) = delete;
862  distinct_info& operator=(const distinct_info&) = delete;
863 
864  iterator_type seq_begin() {
865  return std::begin(seq_);
866  }
867  seen_elements_set init_seen_elements() {
868  return seen_elements_set(deref_cmp<proxy_cmp<Pred>>(proxy_cmp<Pred>(pred_)));
869  }
870 
871  // Returns next distinct element or nullptr when done
872  auto get_next(iterator_type& icur, seen_elements_set& seen)
873  -> typename seq_traits<Seq>::pointer
874  {
875  typename seq_traits<Seq>::pointer pobj = nullptr;
876  for (; pobj == nullptr && icur != iend_; ++icur) {
877  typename seq_traits<Seq>::reference robjtmp = *icur;
878  auto pobjtmp = std::addressof(robjtmp);
879  if (seen.emplace(pobjtmp).second) {
880  // Not seen yet, return this element.
881  pobj = pobjtmp;
882  }
883  }
884  return pobj;
885  }
886  };
887  using distinct_info_sp = std::shared_ptr<distinct_info>;
888 
889  distinct_info_sp spinfo_; // Shared info
890  iterator_type icur_; // Iterator pointing at current element
891  seen_elements_set seen_; // Set of seen elements
892 
893  public:
894  next_impl(Seq&& seq, Pred&& pred)
895  : spinfo_(std::make_shared<distinct_info>(std::forward<Seq>(seq), std::forward<Pred>(pred))),
896  icur_(spinfo_->seq_begin()), seen_(spinfo_->init_seen_elements()) { }
897 
898  auto operator()() -> decltype(spinfo_->get_next(icur_, seen_)) {
899  return spinfo_->get_next(icur_, seen_);
900  }
901  };
902 
903 private:
904  Pred pred_; // Predicate used to compare elements
905 
906 public:
907  explicit distinct_impl(Pred&& pred)
908  : pred_(std::forward<Pred>(pred)) { }
909 
910  // Movable but not copyable
911  distinct_impl(const distinct_impl&) = delete;
912  distinct_impl(distinct_impl&&) = default;
913  distinct_impl& operator=(const distinct_impl&) = delete;
914  distinct_impl& operator=(distinct_impl&&) = default;
915 
916  template<typename Seq>
917  auto operator()(Seq&& seq)
918  -> enumerable<typename seq_traits<Seq>::value_type>
919  {
920  return next_impl<Seq>(std::forward<Seq>(seq), std::forward<Pred>(pred_));
921  }
922 };
923 
924 /**
925  * @internal
926  * @brief <tt>coveo::linq::element_at()</tt> implementation.
927  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
928  *
929  * Implementation of the <tt>coveo::linq::element_at()</tt> LINQ operator.
930  *
931  * @see coveo::linq::element_at()
932  */
933 template<typename = void>
934 class element_at_impl
935 {
936 private:
937  std::size_t n_; // Index of element to fetch.
938 
939 private:
940  // If we have random-access iterators, we can perform fast computations
941  template<typename Seq>
942  auto impl(Seq&& seq, std::random_access_iterator_tag) -> decltype(*std::begin(seq)) {
943  auto icur = std::begin(seq);
944  auto iend = std::end(seq);
945  if (static_cast<std::size_t>(iend - icur) <= n_) {
946  throw_linq_out_of_range();
947  }
948  icur += n_;
949  return *icur;
950  }
951 
952  // Otherwise, we can only move by hand
953  template<typename Seq>
954  auto impl(Seq&& seq, std::input_iterator_tag) -> decltype(*std::begin(seq)) {
955  auto icur = std::begin(seq);
956  auto iend = std::end(seq);
957  for (std::size_t i = 0; i < n_ && icur != iend; ++i, ++icur) {
958  }
959  if (icur == iend) {
960  throw_linq_out_of_range();
961  }
962  return *icur;
963  }
964 
965 public:
966  explicit element_at_impl(std::size_t n)
967  : n_(n) { }
968 
969  template<typename Seq>
970  auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
971  return impl(std::forward<Seq>(seq),
972  typename std::iterator_traits<typename seq_traits<Seq>::iterator_type>::iterator_category());
973  }
974 };
975 
976 /**
977  * @internal
978  * @brief <tt>coveo::linq::element_at_or_default()</tt> implementation.
979  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
980  *
981  * Implementation of the <tt>coveo::linq::element_at_or_default()</tt> LINQ operator.
982  *
983  * @see coveo::linq::element_at_or_default()
984  */
985 template<typename = void>
986 class element_at_or_default_impl
987 {
988 private:
989  std::size_t n_; // Index of element to fetch.
990 
991 private:
992  // If we have random-access iterators, we can perform fast computations
993  template<typename Seq>
994  auto impl(Seq&& seq, std::random_access_iterator_tag) -> typename seq_traits<Seq>::raw_value_type {
995  auto icur = std::begin(seq);
996  auto iend = std::end(seq);
997  return static_cast<std::size_t>(iend - icur) > n_ ? *(icur + n_)
998  : typename seq_traits<Seq>::raw_value_type();
999  }
1000 
1001  // Otherwise, we can only move by hand
1002  template<typename Seq>
1003  auto impl(Seq&& seq, std::input_iterator_tag) -> typename seq_traits<Seq>::raw_value_type {
1004  auto icur = std::begin(seq);
1005  auto iend = std::end(seq);
1006  for (std::size_t i = 0; i < n_ && icur != iend; ++i, ++icur) {
1007  }
1008  return icur != iend ? *icur
1009  : typename seq_traits<Seq>::raw_value_type();
1010  }
1011 
1012 public:
1013  element_at_or_default_impl(std::size_t n)
1014  : n_(n) { }
1015 
1016  template<typename Seq>
1017  auto operator()(Seq&& seq) -> typename seq_traits<Seq>::raw_value_type {
1018  return impl(std::forward<Seq>(seq),
1019  typename std::iterator_traits<typename seq_traits<Seq>::iterator_type>::iterator_category());
1020  }
1021 };
1022 
1023 /**
1024  * @internal
1025  * @brief <tt>coveo::linq::except()</tt> implementation.
1026  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
1027  *
1028  * Implementation of the <tt>coveo::linq::except()</tt> LINQ operator.
1029  *
1030  * @tparam Seq2 Sequence to except (e.g. substract) from the first.
1031  * @tparam Pred Predicate used to compare elements.
1032  * @see coveo::linq::except()
1033  */
1034 template<typename Seq2, typename Pred>
1035 class except_impl
1036 {
1037 private:
1038  // Implementation of next delegate that filters out elements in the second sequence
1039  template<typename Seq1>
1040  class next_impl
1041  {
1042  private:
1043  // Vector of pointers to elements in the second sequence. Used to filter them out.
1044  using elements_to_filter_v = std::vector<typename seq_traits<Seq2>::const_pointer>;
1045 
1046  // Type of iterator for the first sequence.
1047  using first_iterator_type = typename seq_traits<Seq1>::iterator_type;
1048 
1049  // Bean storing info about elements to filter out. Shared among delegate instances.
1050  class filter_info
1051  {
1052  private:
1053  Seq1 seq1_; // Sequence of elements to scan and return.
1054  first_iterator_type iend1_; // End of seq1_.
1055  Seq2 seq2_; // Sequence of elements to filter out.
1056  deref_cmp<Pred> pred_; // Predicate used to sort and search through v_to_filter_.
1057  elements_to_filter_v v_to_filter_; // Elements to filter out. Late-initialized.
1058  bool init_called_ = false; // Init flag for v_to_filter_.
1059 
1060  void init() {
1061  try_reserve(v_to_filter_, seq2_);
1062  auto icur2 = std::begin(seq2_);
1063  auto iend2 = std::end(seq2_);
1064  for (; icur2 != iend2; ++icur2) {
1065  typename seq_traits<Seq2>::const_reference robjtmp = *icur2;
1066  v_to_filter_.emplace_back(std::addressof(robjtmp));
1067  }
1068  std::sort(v_to_filter_.begin(), v_to_filter_.end(), pred_);
1069  init_called_ = true;
1070  }
1071 
1072  public:
1073  filter_info(Seq1&& seq1, Seq2&& seq2, Pred&& pred)
1074  : seq1_(std::forward<Seq1>(seq1)), iend1_(std::end(seq1_)),
1075  seq2_(std::forward<Seq2>(seq2)), pred_(std::forward<Pred>(pred)) { }
1076 
1077  // No move or copy, it's stored in a shared_ptr
1078  filter_info(const filter_info&) = delete;
1079  filter_info& operator=(const filter_info&) = delete;
1080 
1081  first_iterator_type first_begin() {
1082  return std::begin(seq1_);
1083  }
1084 
1085  bool filtered(const typename seq_traits<Seq1>::pointer pobj) {
1086  if (!init_called_) {
1087  // Init elements to filter on first call
1088  init();
1089  }
1090  return std::binary_search(v_to_filter_.cbegin(), v_to_filter_.cend(), pobj, pred_);
1091  }
1092 
1093  // Returns next non-filtered element or nullptr when done
1094  auto get_next(first_iterator_type& icur1) -> typename seq_traits<Seq1>::pointer {
1095  typename seq_traits<Seq1>::pointer pobj = nullptr;
1096  for (; pobj == nullptr && icur1 != iend1_; ++icur1) {
1097  typename seq_traits<Seq1>::reference robjtmp = *icur1;
1098  auto pobjtmp = std::addressof(robjtmp);
1099  if (!filtered(pobjtmp)) {
1100  pobj = pobjtmp;
1101  }
1102  }
1103  return pobj;
1104  }
1105  };
1106  using filter_info_sp = std::shared_ptr<filter_info>;
1107 
1108  filter_info_sp spfilter_; // Bean containing filter info
1109  first_iterator_type icur_; // Current position in first sequence
1110 
1111  public:
1112  next_impl(Seq1&& seq1, Seq2&& seq2, Pred&& pred)
1113  : spfilter_(std::make_shared<filter_info>(std::forward<Seq1>(seq1),
1114  std::forward<Seq2>(seq2),
1115  std::forward<Pred>(pred))),
1116  icur_(spfilter_->first_begin()) { }
1117 
1118  auto operator()() -> decltype(spfilter_->get_next(icur_)) {
1119  return spfilter_->get_next(icur_);
1120  }
1121  };
1122 
1123 private:
1124  Seq2 seq2_; // Sequence of elements to filter out
1125  Pred pred_; // Predicate used to compare elements
1126 
1127 public:
1128  except_impl(Seq2&& seq2, Pred&& pred)
1129  : seq2_(std::forward<Seq2>(seq2)), pred_(std::forward<Pred>(pred)) { }
1130 
1131  // Movable but not copyable
1132  except_impl(const except_impl&) = delete;
1133  except_impl(except_impl&&) = default;
1134  except_impl& operator=(const except_impl&) = delete;
1135  except_impl& operator=(except_impl&&) = default;
1136 
1137  template<typename Seq1>
1138  auto operator()(Seq1&& seq1)
1139  -> enumerable<typename seq_traits<Seq1>::value_type>
1140  {
1141  return next_impl<Seq1>(std::forward<Seq1>(seq1),
1142  std::forward<Seq2>(seq2_),
1143  std::forward<Pred>(pred_));
1144  }
1145 };
1146 
1147 /**
1148  * @internal
1149  * @brief <tt>coveo::linq::first()</tt> implementation (0).
1150  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
1151  *
1152  * Implementation of the <tt>coveo::linq::first()</tt> LINQ operator.
1153  * Version without argument.
1154  *
1155  * @see coveo::linq::first()
1156  */
1157 template<typename = void>
1158 class first_impl_0
1159 {
1160 public:
1161  template<typename Seq>
1162  auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
1163  auto icur = std::begin(seq);
1164  if (icur == std::end(seq)) {
1165  throw_linq_empty_sequence();
1166  }
1167  return *icur;
1168  }
1169 };
1170 
1171 /**
1172  * @internal
1173  * @brief <tt>coveo::linq::first()</tt> implementation (1).
1174  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
1175  *
1176  * Implementation of the <tt>coveo::linq::first()</tt> LINQ operator.
1177  * Version with predicate.
1178  *
1179  * @tparam Pred Predicate used to locate element.
1180  * @see coveo::linq::contains()
1181  */
1182 template<typename Pred>
1183 class first_impl_1
1184 {
1185 private:
1186  const Pred& pred_; // Predicate to satisfy.
1187 
1188 public:
1189  explicit first_impl_1(const Pred& pred)
1190  : pred_(pred) { }
1191 
1192  template<typename Seq>
1193  auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
1194  auto icur = std::begin(seq);
1195  auto iend = std::end(seq);
1196  if (icur == iend) {
1197  throw_linq_empty_sequence();
1198  }
1199  auto ifound = std::find_if(icur, iend, pred_);
1200  if (ifound == iend) {
1201  throw_linq_out_of_range();
1202  }
1203  return *ifound;
1204  }
1205 };
1206 
1207 /**
1208  * @internal
1209  * @brief <tt>coveo::linq::first_or_default()</tt> implementation (0).
1210  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
1211  *
1212  * Implementation of the <tt>coveo::linq::first_or_default()</tt> LINQ operator.
1213  * Version without argument.
1214  *
1215  * @see coveo::linq::first_or_default()
1216  */
1217 template<typename = void>
1218 class first_or_default_impl_0
1219 {
1220 public:
1221  template<typename Seq>
1222  auto operator()(Seq&& seq) -> typename seq_traits<Seq>::raw_value_type {
1223  auto icur = std::begin(seq);
1224  return icur != std::end(seq) ? *icur
1225  : typename seq_traits<Seq>::raw_value_type();
1226  }
1227 };
1228 
1229 /**
1230  * @internal
1231  * @brief <tt>coveo::linq::first_or_default()</tt> implementation (1).
1232  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
1233  *
1234  * Implementation of the <tt>coveo::linq::first_or_default()</tt> LINQ operator.
1235  * Version with predicate.
1236  *
1237  * @tparam Pred Predicate used to locate element.
1238  * @see coveo::linq::first_or_default()
1239  */
1240 template<typename Pred>
1241 class first_or_default_impl_1
1242 {
1243 private:
1244  const Pred& pred_; // Predicate to satisfy.
1245 
1246 public:
1247  explicit first_or_default_impl_1(const Pred& pred)
1248  : pred_(pred) { }
1249 
1250  template<typename Seq>
1251  auto operator()(Seq&& seq) -> typename seq_traits<Seq>::raw_value_type {
1252  auto iend = std::end(seq);
1253  auto ifound = std::find_if(std::begin(seq), iend, pred_);
1254  return ifound != iend ? *ifound
1255  : typename seq_traits<Seq>::raw_value_type();
1256  }
1257 };
1258 
1259 /**
1260  * @internal
1261  * @brief <tt>coveo::linq::group_by()</tt> et al implementation.
1262  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
1263  *
1264  * Implementation of the <tt>coveo::linq::group_by()</tt>,
1265  * <tt>coveo::linq::group_values_by()</tt>, <tt>coveo::linq::group_by_and_fold()</tt>
1266  * and <tt>coveo::linq::group_values_by_and_fold</tt> LINQ operators.
1267  *
1268  * @tparam KeySelector Selector used to obtain keys for each element.
1269  * @tparam ValueSelector Selector used to obtain values for each element.
1270  * @tparam ResultSelector Selector used to produce the final results from
1271  * elements' keys and corresponding values.
1272  * @tparam Pred Predicate used to compare keys.
1273  * @see coveo::linq::group_by()
1274  * @see coveo::linq::group_values_by()
1275  * @see coveo::linq::group_by_and_fold()
1276  * @see coveo::linq::group_values_by_and_fold()
1277  */
1278 template<typename KeySelector,
1279  typename ValueSelector,
1280  typename ResultSelector,
1281  typename Pred>
1282 class group_by_impl
1283 {
1284 private:
1285  // Implementation of next delegate that returns group information
1286  template<typename Seq>
1287  class next_impl
1288  {
1289  public:
1290  // Key and value types returned by selectors.
1291  using key = decltype(std::declval<KeySelector>()(std::declval<typename seq_traits<Seq>::reference>()));
1292  using value = decltype(std::declval<ValueSelector>()(std::declval<typename seq_traits<Seq>::reference>()));
1293 
1294  // Vector of values sharing a common key.
1295  using value_v = std::vector<typename std::decay<value>::type>;
1296  using values = decltype(enumerate_container(std::declval<value_v&&>()));
1297 
1298  // Map that stores keys and their corresponding values.
1299  using values_by_key_m = std::map<typename std::decay<key>::type, value_v, proxy_cmp<Pred>>;
1300 
1301  // Result returned by result selector.
1302  using result = decltype(std::declval<ResultSelector>()(std::declval<key>(), std::declval<values>()));
1303 
1304  // Vector of results returned by this next delegate.
1305  using result_v = std::vector<typename std::decay<result>::type>;
1306 
1307  private:
1308  // Bean storing group information. Shared among delegates in a shared_ptr.
1309  class groups_info
1310  {
1311  private:
1312  Seq seq_; // Sequence containing the elements
1313  KeySelector key_sel_; // Returns keys for elements
1314  ValueSelector value_sel_; // Returns values for elements
1315  ResultSelector result_sel_; // Converts groups into end results
1316  Pred pred_; // Compares keys
1317  result_v results_; // Vector of end results
1318  bool init_called_ = false; // Whether results_ has been initialized
1319 
1320  void init() {
1321  // First build map of groups
1322  values_by_key_m groups{proxy_cmp<Pred>(pred_)};
1323  for (auto&& obj : seq_) {
1324  groups[key_sel_(obj)].emplace_back(value_sel_(obj));
1325  }
1326 
1327  // Now build vector of results
1328  // Note that since we no longer need the map afterwards, we can actually move
1329  // the vectors stored as map values into the results vector.
1330  results_.reserve(groups.size());
1331  for (auto&& group_pair : groups) {
1332  results_.emplace_back(result_sel_(group_pair.first,
1333  enumerate_container(std::move(group_pair.second))));
1334  }
1335 
1336  init_called_ = true;
1337  }
1338 
1339  public:
1340  groups_info(Seq&& seq, KeySelector&& key_sel, ValueSelector&& value_sel,
1341  ResultSelector&& result_sel, Pred&& pred)
1342  : seq_(std::forward<Seq>(seq)),
1343  key_sel_(std::forward<KeySelector>(key_sel)),
1344  value_sel_(std::forward<ValueSelector>(value_sel)),
1345  result_sel_(std::forward<ResultSelector>(result_sel)),
1346  pred_(std::forward<Pred>(pred)) { }
1347 
1348  // Not copyable/movable, stored in a shared_ptr
1349  groups_info(const groups_info&) = delete;
1350  groups_info& operator=(const groups_info&) = delete;
1351 
1352  const result_v& get_results() {
1353  if (!init_called_) {
1354  init();
1355  }
1356  return results_;
1357  }
1358  };
1359  using groups_info_sp = std::shared_ptr<groups_info>;
1360 
1361  groups_info_sp spgroups_; // Information about groups
1362  typename result_v::const_iterator icurr_{}; // Iterator pointing at current result.
1363  typename result_v::const_iterator iendr_{}; // Iterator pointing at end of result vector.
1364  bool init_called_ = false; // Whether icurr_ and iendr_ have been initialized
1365 
1366  void init() {
1367  const auto& results = spgroups_->get_results();
1368  icurr_ = std::begin(results);
1369  iendr_ = std::end(results);
1370  init_called_ = true;
1371  }
1372 
1373  public:
1374  next_impl(Seq&& seq, KeySelector&& key_sel, ValueSelector&& value_sel,
1375  ResultSelector&& result_sel, Pred&& pred)
1376  : spgroups_(std::make_shared<groups_info>(std::forward<Seq>(seq),
1377  std::forward<KeySelector>(key_sel),
1378  std::forward<ValueSelector>(value_sel),
1379  std::forward<ResultSelector>(result_sel),
1380  std::forward<Pred>(pred))) { }
1381 
1382  auto operator()() -> typename seq_traits<result_v>::const_pointer {
1383  // Init iterators on first call
1384  if (!init_called_) {
1385  init();
1386  }
1387  typename seq_traits<result_v>::const_pointer pobj = nullptr;
1388  if (icurr_ != iendr_) {
1389  typename seq_traits<result_v>::const_reference robj = *icurr_;
1390  pobj = std::addressof(robj);
1391  ++icurr_;
1392  }
1393  return pobj;
1394  }
1395  };
1396 
1397 private:
1398  KeySelector key_sel_; // Selector that provides keys for each element
1399  ValueSelector value_sel_; // Selector that provides values for each element
1400  ResultSelector result_sel_; // Selector that converts each group into a final result
1401  Pred pred_; // Predicate used to compare keys
1402 
1403 public:
1404  group_by_impl(KeySelector&& key_sel, ValueSelector&& value_sel,
1405  ResultSelector&& result_sel, Pred&& pred)
1406  : key_sel_(std::forward<KeySelector>(key_sel)),
1407  value_sel_(std::forward<ValueSelector>(value_sel)),
1408  result_sel_(std::forward<ResultSelector>(result_sel)),
1409  pred_(std::forward<Pred>(pred)) { }
1410 
1411  // Movable but not copyable
1412  group_by_impl(const group_by_impl&) = delete;
1413  group_by_impl(group_by_impl&&) = default;
1414  group_by_impl& operator=(const group_by_impl&) = delete;
1415  group_by_impl& operator=(group_by_impl&&) = default;
1416 
1417  template<typename Seq>
1418  auto operator()(Seq&& seq)
1419  -> enumerable<typename seq_traits<typename next_impl<Seq>::result_v>::const_value_type>
1420  {
1421  return next_impl<Seq>(std::forward<Seq>(seq),
1422  std::forward<KeySelector>(key_sel_),
1423  std::forward<ValueSelector>(value_sel_),
1424  std::forward<ResultSelector>(result_sel_),
1425  std::forward<Pred>(pred_));
1426  }
1427 };
1428 
1429 /**
1430  * @internal
1431  * @brief <tt>coveo::linq::group_join()</tt> implementation.
1432  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
1433  *
1434  * Implementation of the <tt>coveo::linq::group_join()</tt> LINQ operator.
1435  *
1436  * @tparam InnerSeq Inner sequence to join (the outer sequence will have
1437  * been provided via the call to <tt>coveo::linq::from()</tt>).
1438  * @tparam OuterKeySelector Selector used to fetch keys from elements
1439  * in the outer sequence.
1440  * @tparam InnerKeySelector Selector used to fetch keys from elements
1441  * in the inner sequence.
1442  * @tparam ResultSelector Selector used to produce final results from
1443  * elements in outer sequence and corresponding
1444  * group of elements in inner sequence.
1445  * @tparam Pred Predicate used to compare keys.
1446  * @see coveo::linq::group_join()
1447  */
1448 template<typename InnerSeq,
1449  typename OuterKeySelector,
1450  typename InnerKeySelector,
1451  typename ResultSelector,
1452  typename Pred>
1453 class group_join_impl
1454 {
1455 private:
1456  // Implementation of next delegate that returns final results
1457  template<typename OuterSeq>
1458  class next_impl
1459  {
1460  public:
1461  // Key returned by key selectors.
1462  using key = decltype(std::declval<OuterKeySelector>()(std::declval<typename seq_traits<OuterSeq>::reference>()));
1463 
1464  // Group of pointers to elements from the inner sequence that share a common key.
1465  using inner_element_v = std::vector<typename seq_traits<InnerSeq>::pointer>;
1466  using inner_elements = enumerable<typename seq_traits<InnerSeq>::const_value_type>;
1467 
1468  // Result returned by result selector.
1469  using result = decltype(std::declval<ResultSelector>()(std::declval<typename seq_traits<OuterSeq>::reference>(),
1470  std::declval<inner_elements>()));
1471 
1472  // Vector of results returned by this next delegate.
1473  using result_v = std::vector<typename std::decay<result>::type>;
1474 
1475  private:
1476  // Bean storing groups information. Shared among delegates in a shared_ptr.
1477  class groups_info
1478  {
1479  private:
1480  OuterSeq outer_seq_; // Outer sequence.
1481  InnerSeq inner_seq_; // Inner sequence from which to create groups.
1482  OuterKeySelector outer_key_sel_; // Key selector for outer sequence.
1483  InnerKeySelector inner_key_sel_; // Key selector for inner sequence.
1484  ResultSelector result_sel_; // Selector converting groups into final results.
1485  Pred pred_; // Predicate used to compare keys.
1486  result_v results_; // Vector of final results.
1487  bool init_called_ = false; // Whether results_ has been initialized.
1488 
1489  void init() {
1490  // Build map of groups of elements from inner sequence.
1491  using groups_m = std::map<typename std::decay<key>::type, inner_element_v, proxy_cmp<Pred>>;
1492  groups_m keyed_inner_elems{proxy_cmp<Pred>(pred_)};
1493  for (auto&& inner_elem : inner_seq_) {
1494  typename seq_traits<InnerSeq>::reference robj = inner_elem;
1495  keyed_inner_elems[inner_key_sel_(inner_elem)].emplace_back(std::addressof(robj));
1496  }
1497 
1498  // Iterate outer sequence and build final results by matching the elements with
1499  // the groups we built earlier.
1500  try_reserve(results_, outer_seq_);
1501  const auto iendki = keyed_inner_elems.end();
1502  for (auto&& outer_elem : outer_seq_) {
1503  const key outer_key = outer_key_sel_(outer_elem);
1504  const auto icurki = keyed_inner_elems.find(outer_key);
1505  inner_elements inner_elems;
1506  if (icurki != iendki) {
1507  const std::size_t inner_size = icurki->second.size();
1508  inner_elems = inner_elements(make_deref_next_impl(icurki->second),
1509  [inner_size]() -> std::size_t { return inner_size; });
1510  }
1511  results_.emplace_back(result_sel_(outer_elem, inner_elems));
1512  }
1513 
1514  init_called_ = true;
1515  }
1516 
1517  public:
1518  groups_info(OuterSeq&& outer_seq, InnerSeq&& inner_seq,
1519  OuterKeySelector&& outer_key_sel, InnerKeySelector&& inner_key_sel,
1520  ResultSelector&& result_sel, Pred&& pred)
1521  : outer_seq_(std::forward<OuterSeq>(outer_seq)),
1522  inner_seq_(std::forward<InnerSeq>(inner_seq)),
1523  outer_key_sel_(std::forward<OuterKeySelector>(outer_key_sel)),
1524  inner_key_sel_(std::forward<InnerKeySelector>(inner_key_sel)),
1525  result_sel_(std::forward<ResultSelector>(result_sel)),
1526  pred_(std::forward<Pred>(pred)) { }
1527 
1528  // Not copyable/movable, stored in a shared_ptr
1529  groups_info(const groups_info&) = delete;
1530  groups_info& operator=(const groups_info&) = delete;
1531 
1532  const result_v& get_results() {
1533  if (!init_called_) {
1534  init();
1535  }
1536  return results_;
1537  }
1538  };
1539  using groups_info_sp = std::shared_ptr<groups_info>;
1540 
1541  groups_info_sp spgroups_; // Information about groups and results
1542  typename result_v::const_iterator icurr_{}; // Iterator pointing at current result.
1543  typename result_v::const_iterator iendr_{}; // Iterator pointing at end of result vector.
1544  bool init_called_ = false; // Whether icurr_/iendr_ have been initialized.
1545 
1546  void init() {
1547  const auto& results = spgroups_->get_results();
1548  icurr_ = std::begin(results);
1549  iendr_ = std::end(results);
1550  init_called_ = true;
1551  }
1552 
1553  public:
1554  next_impl(OuterSeq&& outer_seq, InnerSeq&& inner_seq,
1555  OuterKeySelector&& outer_key_sel, InnerKeySelector&& inner_key_sel,
1556  ResultSelector&& result_sel, Pred&& pred)
1557  : spgroups_(std::make_shared<groups_info>(std::forward<OuterSeq>(outer_seq),
1558  std::forward<InnerSeq>(inner_seq),
1559  std::forward<OuterKeySelector>(outer_key_sel),
1560  std::forward<InnerKeySelector>(inner_key_sel),
1561  std::forward<ResultSelector>(result_sel),
1562  std::forward<Pred>(pred))) { }
1563 
1564  auto operator()() -> typename seq_traits<result_v>::const_pointer {
1565  // Init iterators on first call
1566  if (!init_called_) {
1567  init();
1568  }
1569  typename seq_traits<result_v>::const_pointer pobj = nullptr;
1570  if (icurr_ != iendr_) {
1571  typename seq_traits<result_v>::const_reference robj = *icurr_;
1572  pobj = std::addressof(robj);
1573  ++icurr_;
1574  }
1575  return pobj;
1576  }
1577  };
1578 
1579 private:
1580  InnerSeq inner_seq_; // Inner sequence whose elements to group with outer elements with matching keys
1581  OuterKeySelector outer_key_sel_; // Selector to get keys from elements in the outer sequence
1582  InnerKeySelector inner_key_sel_; // Selector to get keys from elements in the inner sequence
1583  ResultSelector result_sel_; // Selector to convert groups into final results
1584  Pred pred_; // Predicate used to compare keys
1585 
1586 public:
1587  group_join_impl(InnerSeq&& inner_seq,
1588  OuterKeySelector&& outer_key_sel,
1589  InnerKeySelector&& inner_key_sel,
1590  ResultSelector&& result_sel,
1591  Pred&& pred)
1592  : inner_seq_(std::forward<InnerSeq>(inner_seq)),
1593  outer_key_sel_(std::forward<OuterKeySelector>(outer_key_sel)),
1594  inner_key_sel_(std::forward<InnerKeySelector>(inner_key_sel)),
1595  result_sel_(std::forward<ResultSelector>(result_sel)),
1596  pred_(std::forward<Pred>(pred)) { }
1597 
1598  // Movable but not copyable
1599  group_join_impl(const group_join_impl&) = delete;
1600  group_join_impl(group_join_impl&&) = default;
1601  group_join_impl& operator=(const group_join_impl&) = delete;
1602  group_join_impl& operator=(group_join_impl&&) = default;
1603 
1604  template<typename OuterSeq>
1605  auto operator()(OuterSeq&& outer_seq)
1606  -> enumerable<typename seq_traits<typename next_impl<OuterSeq>::result_v>::const_value_type>
1607  {
1608  return next_impl<OuterSeq>(std::forward<OuterSeq>(outer_seq),
1609  std::forward<InnerSeq>(inner_seq_),
1610  std::forward<OuterKeySelector>(outer_key_sel_),
1611  std::forward<InnerKeySelector>(inner_key_sel_),
1612  std::forward<ResultSelector>(result_sel_),
1613  std::forward<Pred>(pred_));
1614  }
1615 };
1616 
1617 /**
1618  * @internal
1619  * @brief <tt>coveo::linq::intersect()</tt> implementation.
1620  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
1621  *
1622  * Implementation of the <tt>coveo::linq::intersect()</tt> LINQ operator.
1623  *
1624  * @tparam Seq2 Second sequence to intersect (the first one will have been
1625  * provided via the call to <tt>coveo::linq::from()</tt>).
1626  * @tparam Pred Predicate used to compare elements.
1627  * @see coveo::linq::intersect()
1628  */
1629 template<typename Seq2, typename Pred>
1630 class intersect_impl
1631 {
1632 public:
1633  // Implementation of next delegate that performs intersection
1634  template<typename Seq1>
1635  class next_impl
1636  {
1637  private:
1638  // Vector storing pointers to the elements of second sequence.
1639  using seq2_element_v = std::vector<typename seq_traits<Seq2>::pointer>;
1640 
1641  // Type of iterators for the sequences.
1642  using first_iterator_type = typename seq_traits<Seq1>::iterator_type;
1643 
1644  // Information about intersection. Shared among delegates through smart_ptr.
1645  class intersect_info
1646  {
1647  private:
1648  Seq1 seq1_; // First sequence to intersect.
1649  first_iterator_type iend1_; // Iterator pointing at end of first sequence.
1650  Seq2 seq2_; // Second sequence to intersect.
1651  deref_cmp<Pred> pred_; // Predicate used to sort and search through v_in_seq2_.
1652  seq2_element_v v_in_seq2_; // Vector of elements from second sequence.
1653  bool init_called_ = false; // Whether v_in_seq2_ has been initialized.
1654 
1655  void init() {
1656  // Add all elements from second sequence to a vector and sort it.
1657  try_reserve(v_in_seq2_, seq2_);
1658  auto icur2 = std::begin(seq2_);
1659  auto iend2 = std::end(seq2_);
1660  for (; icur2 != iend2; ++icur2) {
1661  typename seq_traits<Seq2>::reference robjtmp = *icur2;
1662  v_in_seq2_.emplace_back(std::addressof(robjtmp));
1663  }
1664  std::sort(v_in_seq2_.begin(), v_in_seq2_.end(), pred_);
1665  init_called_ = true;
1666  }
1667 
1668  public:
1669  intersect_info(Seq1&& seq1, Seq2&& seq2, Pred&& pred)
1670  : seq1_(std::forward<Seq1>(seq1)),
1671  iend1_(std::end(seq1_)),
1672  seq2_(std::forward<Seq2>(seq2)),
1673  pred_(std::forward<Pred>(pred)) { }
1674 
1675  // Not copyable/movable, stored in a shared_ptr
1676  intersect_info(const intersect_info&) = delete;
1677  intersect_info& operator=(const intersect_info&) = delete;
1678 
1679  first_iterator_type first_begin() {
1680  return std::begin(seq1_);
1681  }
1682 
1683  bool is_in_seq2(const typename seq_traits<Seq1>::pointer pobj) {
1684  if (!init_called_) {
1685  init();
1686  }
1687  return std::binary_search(v_in_seq2_.cbegin(), v_in_seq2_.cend(), pobj, pred_);
1688  }
1689 
1690  // Returns next element that is both in first and second sequence or nullptr when done
1691  auto get_next(first_iterator_type& icur1) -> typename seq_traits<Seq1>::pointer {
1692  typename seq_traits<Seq1>::pointer pobj = nullptr;
1693  for (; pobj == nullptr && icur1 != iend1_; ++icur1) {
1694  typename seq_traits<Seq1>::reference robjtmp = *icur1;
1695  auto pobjtmp = std::addressof(robjtmp);
1696  if (is_in_seq2(pobjtmp)) {
1697  pobj = pobjtmp;
1698  }
1699  }
1700  return pobj;
1701  }
1702  };
1703  using intersect_info_sp = std::shared_ptr<intersect_info>;
1704 
1705  intersect_info_sp spint_info_; // Intersection information.
1706  first_iterator_type icur_; // Current position in first sequence.
1707 
1708  public:
1709  next_impl(Seq1&& seq1, Seq2&& seq2, Pred&& pred)
1710  : spint_info_(std::make_shared<intersect_info>(std::forward<Seq1>(seq1),
1711  std::forward<Seq2>(seq2),
1712  std::forward<Pred>(pred))),
1713  icur_(spint_info_->first_begin()) { }
1714 
1715  auto operator()() -> decltype(spint_info_->get_next(icur_)) {
1716  return spint_info_->get_next(icur_);
1717  }
1718  };
1719 
1720 private:
1721  Seq2 seq2_; // Second sequence to intersect.
1722  Pred pred_; // Predicate used to compare elements.
1723 
1724 public:
1725  intersect_impl(Seq2&& seq2, Pred&& pred)
1726  : seq2_(std::forward<Seq2>(seq2)),
1727  pred_(std::forward<Pred>(pred)) { }
1728 
1729  // Movable but not copyable
1730  intersect_impl(const intersect_impl&) = delete;
1731  intersect_impl(intersect_impl&&) = default;
1732  intersect_impl& operator=(const intersect_impl&) = delete;
1733  intersect_impl& operator=(intersect_impl&&) = default;
1734 
1735  template<typename Seq1>
1736  auto operator()(Seq1&& seq1)
1737  -> enumerable<typename seq_traits<Seq1>::value_type>
1738  {
1739  return next_impl<Seq1>(std::forward<Seq1>(seq1),
1740  std::forward<Seq2>(seq2_),
1741  std::forward<Pred>(pred_));
1742  }
1743 };
1744 
1745 /**
1746  * @internal
1747  * @brief <tt>coveo::linq::join()</tt> implementation.
1748  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
1749  *
1750  * Implementation of the <tt>coveo::linq::join()</tt> LINQ operator.
1751  *
1752  * @tparam InnerSeq Inner sequence to join (the outer sequence will have been
1753  * provided by the call to <tt>coveo::linq::from()</tt>).
1754  * @tparam OuterKeySelector Selector used to fetch keys from elements
1755  * in the outer sequence.
1756  * @tparam InnerKeySelector Selector used to fetch keys from elements
1757  * in the inner sequence.
1758  * @tparam ResultSelector Selector used to produce final results from
1759  * elements from outer and inner sequence with
1760  * matching keys.
1761  * @tparam Pred Predicate used to compare keys.
1762  * @see coveo::linq::join()
1763  */
1764 template<typename InnerSeq,
1765  typename OuterKeySelector,
1766  typename InnerKeySelector,
1767  typename ResultSelector,
1768  typename Pred>
1769 class join_impl
1770 {
1771 private:
1772  // Implementation of next delegate that performs join
1773  template<typename OuterSeq>
1774  class next_impl
1775  {
1776  public:
1777  // Key returned by key selectors.
1778  using key = decltype(std::declval<OuterKeySelector>()(std::declval<typename seq_traits<OuterSeq>::reference>()));
1779 
1780  // Group of pointers to elements from the inner sequence that share a common key.
1781  using inner_element_v = std::vector<typename seq_traits<InnerSeq>::pointer>;
1782 
1783  // Result returned by result selector.
1784  using result = decltype(std::declval<ResultSelector>()(std::declval<typename seq_traits<OuterSeq>::reference>(),
1785  std::declval<typename seq_traits<InnerSeq>::reference>()));
1786 
1787  // Vector of results returned by this next delegate.
1788  using result_v = std::vector<typename std::decay<result>::type>;
1789 
1790  private:
1791  // Bean storing join information. Shared among delegates in a shared_ptr.
1792  class join_info
1793  {
1794  private:
1795  OuterSeq outer_seq_; // Outer sequence.
1796  InnerSeq inner_seq_; // Inner sequence to join with outer sequence.
1797  OuterKeySelector outer_key_sel_; // Key selector for outer sequence.
1798  InnerKeySelector inner_key_sel_; // Key selector for inner sequence.
1799  ResultSelector result_sel_; // Selector converting joined elements into final results.
1800  Pred pred_; // Predicate used to compare keys.
1801  result_v results_; // Vector of final results.
1802  bool init_called_ = false; // Whether results_ has been initialized.
1803 
1804  void init() {
1805  // Build map of groups of elements from inner sequence.
1806  using groups_m = std::map<typename std::decay<key>::type, inner_element_v, proxy_cmp<Pred>>;
1807  groups_m keyed_inner_elems{proxy_cmp<Pred>(pred_)};
1808  for (auto&& inner_elem : inner_seq_) {
1809  typename seq_traits<InnerSeq>::reference robj = inner_elem;
1810  keyed_inner_elems[inner_key_sel_(inner_elem)].emplace_back(std::addressof(robj));
1811  }
1812 
1813  // Iterate outer sequence and build final results by joining the elements with
1814  // those in the groups we built earlier.
1815  try_reserve(results_, inner_seq_);
1816  const auto iendki = keyed_inner_elems.end();
1817  for (auto&& outer_elem : outer_seq_) {
1818  const key outer_key = outer_key_sel_(outer_elem);
1819  const auto icurki = keyed_inner_elems.find(outer_key);
1820  if (icurki != iendki) {
1821  for (auto* pinner_elem : icurki->second) {
1822  results_.emplace_back(result_sel_(outer_elem, *pinner_elem));
1823  }
1824  }
1825  }
1826 
1827  init_called_ = true;
1828  }
1829 
1830  public:
1831  join_info(OuterSeq&& outer_seq, InnerSeq&& inner_seq,
1832  OuterKeySelector&& outer_key_sel, InnerKeySelector&& inner_key_sel,
1833  ResultSelector&& result_sel, Pred&& pred)
1834  : outer_seq_(std::forward<OuterSeq>(outer_seq)),
1835  inner_seq_(std::forward<InnerSeq>(inner_seq)),
1836  outer_key_sel_(std::forward<OuterKeySelector>(outer_key_sel)),
1837  inner_key_sel_(std::forward<InnerKeySelector>(inner_key_sel)),
1838  result_sel_(std::forward<ResultSelector>(result_sel)),
1839  pred_(std::forward<Pred>(pred)) { }
1840 
1841  // Not copyable/movable, stored in a shared_ptr
1842  join_info(const join_info&) = delete;
1843  join_info& operator=(const join_info&) = delete;
1844 
1845  const result_v& get_results() {
1846  if (!init_called_) {
1847  init();
1848  }
1849  return results_;
1850  }
1851  };
1852  using join_info_sp = std::shared_ptr<join_info>;
1853 
1854  join_info_sp spjoin_info_; // Information about joined elements and results
1855  typename result_v::const_iterator icurr_{}; // Iterator pointing at current result.
1856  typename result_v::const_iterator iendr_{}; // Iterator pointing at end of result vector.
1857  bool init_called_ = false; // Whether icurr_/iendr_ have been initialized.
1858 
1859  void init() {
1860  const auto& results = spjoin_info_->get_results();
1861  icurr_ = std::begin(results);
1862  iendr_ = std::end(results);
1863  init_called_ = true;
1864  }
1865 
1866  public:
1867  next_impl(OuterSeq&& outer_seq, InnerSeq&& inner_seq,
1868  OuterKeySelector&& outer_key_sel, InnerKeySelector&& inner_key_sel,
1869  ResultSelector&& result_sel, Pred&& pred)
1870  : spjoin_info_(std::make_shared<join_info>(std::forward<OuterSeq>(outer_seq),
1871  std::forward<InnerSeq>(inner_seq),
1872  std::forward<OuterKeySelector>(outer_key_sel),
1873  std::forward<InnerKeySelector>(inner_key_sel),
1874  std::forward<ResultSelector>(result_sel),
1875  std::forward<Pred>(pred))) { }
1876 
1877  auto operator()() -> typename seq_traits<result_v>::const_pointer {
1878  // Init iterators on first call
1879  if (!init_called_) {
1880  init();
1881  }
1882  typename seq_traits<result_v>::const_pointer pobj = nullptr;
1883  if (icurr_ != iendr_) {
1884  typename seq_traits<result_v>::const_reference robj = *icurr_;
1885  pobj = std::addressof(robj);
1886  ++icurr_;
1887  }
1888  return pobj;
1889  }
1890  };
1891 
1892 private:
1893  InnerSeq inner_seq_; // Inner sequence to join.
1894  OuterKeySelector outer_key_sel_; // Fetches keys for elements of outer sequence.
1895  InnerKeySelector inner_key_sel_; // Fetches keys for elements of inner sequence.
1896  ResultSelector result_sel_; // Creates results from joined elements.
1897  Pred pred_; // Predicate to compare keys.
1898 
1899 public:
1900  join_impl(InnerSeq&& inner_seq,
1901  OuterKeySelector&& outer_key_sel,
1902  InnerKeySelector&& inner_key_sel,
1903  ResultSelector&& result_sel,
1904  Pred&& pred)
1905  : inner_seq_(std::forward<InnerSeq>(inner_seq)),
1906  outer_key_sel_(std::forward<OuterKeySelector>(outer_key_sel)),
1907  inner_key_sel_(std::forward<InnerKeySelector>(inner_key_sel)),
1908  result_sel_(std::forward<ResultSelector>(result_sel)),
1909  pred_(std::forward<Pred>(pred)) { }
1910 
1911  // Movable but not copyable
1912  join_impl(const join_impl&) = delete;
1913  join_impl(join_impl&&) = default;
1914  join_impl& operator=(const join_impl&) = delete;
1915  join_impl& operator=(join_impl&&) = default;
1916 
1917  template<typename OuterSeq>
1918  auto operator()(OuterSeq&& outer_seq)
1919  -> enumerable<typename seq_traits<typename next_impl<OuterSeq>::result_v>::const_value_type>
1920  {
1921  return next_impl<OuterSeq>(std::forward<OuterSeq>(outer_seq),
1922  std::forward<InnerSeq>(inner_seq_),
1923  std::forward<OuterKeySelector>(outer_key_sel_),
1924  std::forward<InnerKeySelector>(inner_key_sel_),
1925  std::forward<ResultSelector>(result_sel_),
1926  std::forward<Pred>(pred_));
1927  }
1928 };
1929 
1930 /**
1931  * @internal
1932  * @brief <tt>coveo::linq::last()</tt> implementation (0).
1933  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
1934  *
1935  * Implementation of the <tt>coveo::linq::last()</tt> LINQ operator.
1936  * Version without argument.
1937  *
1938  * @see coveo::linq::last()
1939  */
1940 template<typename = void>
1941 class last_impl_0
1942 {
1943 private:
1944  // If we have bidi iterators, we can simply use rbegin
1945  template<typename Seq>
1946  auto impl(Seq&& seq, std::bidirectional_iterator_tag) -> decltype(*std::begin(seq)) {
1947  auto ricur = seq.rbegin();
1948  if (ricur == seq.rend()) {
1949  throw_linq_empty_sequence();
1950  }
1951  return *ricur;
1952  }
1953 
1954  // Otherwise we'll have to be creative
1955  template<typename Seq>
1956  auto impl(Seq&& seq, std::input_iterator_tag) -> decltype(*std::begin(seq)) {
1957  auto icur = std::begin(seq);
1958  auto iend = std::end(seq);
1959  if (icur == iend) {
1960  throw_linq_empty_sequence();
1961  }
1962  decltype(icur) iprev;
1963  while (icur != iend) {
1964  iprev = icur;
1965  ++icur;
1966  }
1967  return *iprev;
1968  }
1969 
1970 public:
1971  template<typename Seq>
1972  auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
1973  return impl(std::forward<Seq>(seq),
1974  typename std::iterator_traits<typename seq_traits<Seq>::iterator_type>::iterator_category());
1975  }
1976 };
1977 
1978 /**
1979  * @internal
1980  * @brief <tt>coveo::linq::last()</tt> implementation (1).
1981  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
1982  *
1983  * Implementation of the <tt>coveo::linq::last()</tt> LINQ operator.
1984  * Version with predicate.
1985  *
1986  * @tparam Pred Predicate to satisfy.
1987  * @see coveo::linq::last()
1988  */
1989 template<typename Pred>
1990 class last_impl_1
1991 {
1992 private:
1993  const Pred& pred_; // Predicate to satisfy
1994 
1995 private:
1996  // If we have bidi iterators, we can simply use rbegin
1997  template<typename Seq>
1998  auto impl(Seq&& seq, std::bidirectional_iterator_tag) -> decltype(*std::begin(seq)) {
1999  auto ricur = seq.rbegin();
2000  auto riend = seq.rend();
2001  if (ricur == riend) {
2002  throw_linq_empty_sequence();
2003  }
2004  auto rifound = std::find_if(ricur, riend, pred_);
2005  if (rifound == riend) {
2006  throw_linq_out_of_range();
2007  }
2008  return *rifound;
2009  }
2010 
2011  // Otherwise we'll have to be creative
2012  template<typename Seq>
2013  auto impl(Seq&& seq, std::input_iterator_tag) -> decltype(*std::begin(seq)) {
2014  auto icur = std::begin(seq);
2015  auto iend = std::end(seq);
2016  if (icur == iend) {
2017  throw_linq_empty_sequence();
2018  }
2019  auto ifound = iend;
2020  while (icur != iend) {
2021  if (pred_(*icur)) {
2022  ifound = icur;
2023  }
2024  ++icur;
2025  }
2026  if (ifound == iend) {
2027  throw_linq_out_of_range();
2028  }
2029  return *ifound;
2030  }
2031 
2032 public:
2033  explicit last_impl_1(const Pred& pred)
2034  : pred_(pred) { }
2035 
2036  template<typename Seq>
2037  auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
2038  return impl(std::forward<Seq>(seq),
2039  typename std::iterator_traits<typename seq_traits<Seq>::iterator_type>::iterator_category());
2040  }
2041 };
2042 
2043 /**
2044  * @internal
2045  * @brief <tt>coveo::linq::last_or_default()</tt> implementation (0).
2046  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2047  *
2048  * Implementation of the <tt>coveo::linq::last_or_default()</tt> LINQ operator.
2049  * Version without argument.
2050  *
2051  * @see coveo::linq::last_or_default()
2052  */
2053 template<typename = void>
2054 class last_or_default_impl_0
2055 {
2056 private:
2057  // If we have bidi iterators, we can simply use rbegin
2058  template<typename Seq>
2059  auto impl(Seq&& seq, std::bidirectional_iterator_tag) -> typename seq_traits<Seq>::raw_value_type {
2060  auto ricur = seq.rbegin();
2061  return ricur != seq.rend() ? *ricur
2062  : typename seq_traits<Seq>::raw_value_type();
2063  }
2064 
2065  // Otherwise we'll have to be creative
2066  template<typename Seq>
2067  auto impl(Seq&& seq, std::input_iterator_tag) -> typename seq_traits<Seq>::raw_value_type {
2068  auto icur = std::begin(seq);
2069  auto iend = std::end(seq);
2070  auto iprev = iend;
2071  while (icur != iend) {
2072  iprev = icur;
2073  ++icur;
2074  }
2075  return iprev != iend ? *iprev
2076  : typename seq_traits<Seq>::raw_value_type();
2077  }
2078 
2079 public:
2080  template<typename Seq>
2081  auto operator()(Seq&& seq) -> typename seq_traits<Seq>::raw_value_type {
2082  return impl(std::forward<Seq>(seq),
2083  typename std::iterator_traits<typename seq_traits<Seq>::iterator_type>::iterator_category());
2084  }
2085 };
2086 
2087 /**
2088  * @internal
2089  * @brief <tt>coveo::linq::last_or_default()</tt> implementation (1).
2090  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2091  *
2092  * Implementation of the <tt>coveo::linq::last_or_default()</tt> LINQ operator.
2093  * Version with predicate.
2094  *
2095  * @tparam Pred Predicate to satisfy.
2096  * @see coveo::linq::last_or_default()
2097  */
2098 template<typename Pred>
2099 class last_or_default_impl_1
2100 {
2101 private:
2102  const Pred& pred_; // Predicate to satisfy
2103 
2104 private:
2105  // If we have bidi iterators, we can simply use rbegin
2106  template<typename Seq>
2107  auto impl(Seq&& seq, std::bidirectional_iterator_tag) -> typename seq_traits<Seq>::raw_value_type {
2108  auto riend = seq.rend();
2109  auto rifound = std::find_if(seq.rbegin(), riend, pred_);
2110  return rifound != riend ? *rifound
2111  : typename seq_traits<Seq>::raw_value_type();
2112  }
2113 
2114  // Otherwise we'll have to be creative
2115  template<typename Seq>
2116  auto impl(Seq&& seq, std::input_iterator_tag) -> typename seq_traits<Seq>::raw_value_type {
2117  auto icur = std::begin(seq);
2118  auto iend = std::end(seq);
2119  auto ifound = iend;
2120  while (icur != iend) {
2121  if (pred_(*icur)) {
2122  ifound = icur;
2123  }
2124  ++icur;
2125  }
2126  return ifound != iend ? *ifound
2127  : typename seq_traits<Seq>::raw_value_type();
2128  }
2129 
2130 public:
2131  explicit last_or_default_impl_1(const Pred& pred)
2132  : pred_(pred) { }
2133 
2134  template<typename Seq>
2135  auto operator()(Seq&& seq) -> typename seq_traits<Seq>::raw_value_type {
2136  return impl(std::forward<Seq>(seq),
2137  typename std::iterator_traits<typename seq_traits<Seq>::iterator_type>::iterator_category());
2138  }
2139 };
2140 
2141 /**
2142  * @internal
2143  * @brief <tt>coveo::linq::max()</tt> implementation (0).
2144  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2145  *
2146  * Implementation of the <tt>coveo::linq::max()</tt> LINQ operator.
2147  * Version without argument.
2148  *
2149  * @see coveo::linq::max()
2150  */
2151 template<typename = void>
2152 class max_impl_0
2153 {
2154 public:
2155  template<typename Seq>
2156  auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
2157  auto iend = std::end(seq);
2158  auto imax = std::max_element(std::begin(seq), iend);
2159  if (imax == iend) {
2160  throw_linq_empty_sequence();
2161  }
2162  return *imax;
2163  }
2164 };
2165 
2166 /**
2167  * @internal
2168  * @brief <tt>coveo::linq::max()</tt> implementation (1).
2169  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2170  *
2171  * Implementation of the <tt>coveo::linq::max()</tt> LINQ operator.
2172  * Version with value selector.
2173  *
2174  * @tparam Selector Selector used to fetch values from sequence elements.
2175  * @see coveo::linq::max()
2176  */
2177 template<typename Selector>
2178 class max_impl_1
2179 {
2180 private:
2181  const Selector& sel_;
2182 
2183 public:
2184  explicit max_impl_1(const Selector& sel)
2185  : sel_(sel) { }
2186 
2187  template<typename Seq>
2188  auto operator()(Seq&& seq) -> typename std::decay<decltype(sel_(*std::begin(seq)))>::type {
2189  auto icur = std::begin(seq);
2190  auto iend = std::end(seq);
2191  if (icur == iend) {
2192  throw_linq_empty_sequence();
2193  }
2194  auto max_val = sel_(*icur);
2195  while (++icur != iend) {
2196  max_val = std::max(max_val, sel_(*icur));
2197  }
2198  return max_val;
2199  }
2200 };
2201 
2202 /**
2203  * @internal
2204  * @brief <tt>coveo::linq::min()</tt> implementation (0).
2205  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2206  *
2207  * Implementation of the <tt>coveo::linq::min()</tt> LINQ operator.
2208  * Version without argument.
2209  *
2210  * @see coveo::linq::min()
2211  */
2212 template<typename = void>
2213 class min_impl_0
2214 {
2215 public:
2216  template<typename Seq>
2217  auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
2218  auto iend = std::end(seq);
2219  auto imin = std::min_element(std::begin(seq), iend);
2220  if (imin == iend) {
2221  throw_linq_empty_sequence();
2222  }
2223  return *imin;
2224  }
2225 };
2226 
2227 /**
2228  * @internal
2229  * @brief <tt>coveo::linq::min()</tt> implementation (1).
2230  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2231  *
2232  * Implementation of the <tt>coveo::linq::min()</tt> LINQ operator.
2233  * Version with value selector.
2234  *
2235  * @tparam Selector Selector used to fetch values from sequence elements.
2236  * @see coveo::linq::min()
2237  */
2238 template<typename Selector>
2239 class min_impl_1
2240 {
2241 private:
2242  const Selector& sel_; // Selector used to fetch values from sequence elements.
2243 
2244 public:
2245  explicit min_impl_1(const Selector& sel)
2246  : sel_(sel) { }
2247 
2248  template<typename Seq>
2249  auto operator()(Seq&& seq) -> typename std::decay<decltype(sel_(*std::begin(seq)))>::type {
2250  auto icur = std::begin(seq);
2251  auto iend = std::end(seq);
2252  if (icur == iend) {
2253  throw_linq_empty_sequence();
2254  }
2255  auto min_val = sel_(*icur);
2256  while (++icur != iend) {
2257  min_val = std::min(min_val, sel_(*icur));
2258  }
2259  return min_val;
2260  }
2261 };
2262 
2263 /**
2264  * @internal
2265  * @brief <tt>coveo::linq::none()</tt> implementation.
2266  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2267  *
2268  * Implementation of the <tt>coveo::linq::none()</tt> LINQ operator.
2269  *
2270  * @see coveo::linq::none()
2271  */
2272 template<typename Pred>
2273 class none_impl
2274 {
2275 private:
2276  const Pred& pred_; // Predicate to satisfy.
2277 
2278 public:
2279  explicit none_impl(const Pred& pred)
2280  : pred_(pred) { }
2281 
2282  template<typename Seq>
2283  auto operator()(Seq&& seq) -> bool {
2284  return std::none_of(std::begin(seq), std::end(seq), pred_);
2285  }
2286 };
2287 
2288 /**
2289  * @internal
2290  * @brief <tt>coveo::linq::order_by()</tt> internal comparator.
2291  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2292  *
2293  * Comparator of sequence elements used by <tt>coveo::linq::order_by()</tt> et al.
2294  * Fetches keys from sequence elements then compares them with a predicate.
2295  * Its <tt>operator()()</tt> returns an @c int that represents the relationship
2296  * between the elements (negative values mean left is before right, etc.)
2297  *
2298  * @tparam KeySelector Selector used to fetch keys from sequence elements.
2299  * @tparam Pred Predicate used to compare the keys.
2300  * @tparam Descending Whether we should order ascending or descending.
2301  * @tparam _LessValue Value to use to compute ordering. Set automatically
2302  * from the value of @c Descending.
2303  * @see coveo::linq::order_by()
2304  * @see coveo::linq::order_by_descending()
2305  * @see coveo::linq::then_by()
2306  * @see coveo::linq::then_by_descending()
2307  * @see coveo::linq::detail::dual_order_by_comparator
2308  * @see coveo::linq::detail::order_by_impl
2309  * @see coveo::linq::detail::order_by_impl_with_seq
2310  */
2311 template<typename KeySelector,
2312  typename Pred,
2313  bool Descending,
2314  int _LessValue = Descending ? 1 : -1>
2315 class order_by_comparator
2316 {
2317 private:
2318  KeySelector key_sel_; // Key selector used to fetch keys from elements.
2319  Pred pred_; // Predicate used to compare keys.
2320 
2321 public:
2322  order_by_comparator(KeySelector&& key_sel, Pred&& pred)
2323  : key_sel_(std::forward<KeySelector>(key_sel)), pred_(std::forward<Pred>(pred)) { }
2324 
2325  // Cannot copy/move, stored in a unique_ptr
2326  order_by_comparator(const order_by_comparator&) = delete;
2327  order_by_comparator& operator=(const order_by_comparator&) = delete;
2328 
2329  // Compares two values, returning relative position of the two in an ordered sequence.
2330  template<typename T1, typename T2>
2331  int operator()(T1&& left, T2&& right) const {
2332  decltype(key_sel_(left)) leftk = key_sel_(left);
2333  decltype(key_sel_(right)) rightk = key_sel_(right);
2334  int cmp;
2335  if (pred_(leftk, rightk)) {
2336  cmp = _LessValue;
2337  } else if (pred_(rightk, leftk)) {
2338  cmp = -_LessValue;
2339  } else {
2340  // Keys are equal.
2341  cmp = 0;
2342  }
2343  return cmp;
2344  }
2345 };
2346 
2347 /**
2348  * @internal
2349  * @brief <tt>coveo::linq::order_by()</tt> internal dual comparator.
2350  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2351  *
2352  * Dual comparator used by <tt>coveo::linq::order_by()</tt> et al. Chains
2353  * two comparators together: when <tt>operator()()</tt> is called, the
2354  * first comparator is used; if it returns 0, the second one is used.
2355  *
2356  * @tparam Cmp1 First comparator to chain.
2357  * @tparam Cmp2 Second comparator to chain.
2358  * @see coveo::linq::order_by()
2359  * @see coveo::linq::order_by_descending()
2360  * @see coveo::linq::then_by()
2361  * @see coveo::linq::then_by_descending()
2362  * @see coveo::linq::detail::order_by_comparator
2363  * @see coveo::linq::detail::order_by_impl
2364  * @see coveo::linq::detail::order_by_impl_with_seq
2365  */
2366 template<typename Cmp1, typename Cmp2>
2367 class dual_order_by_comparator
2368 {
2369 private:
2370  std::unique_ptr<Cmp1> upcmp1_;
2371  std::unique_ptr<Cmp2> upcmp2_;
2372 
2373 public:
2374  dual_order_by_comparator(std::unique_ptr<Cmp1>&& upcmp1, std::unique_ptr<Cmp2>&& upcmp2)
2375  : upcmp1_(std::move(upcmp1)), upcmp2_(std::move(upcmp2)) { }
2376 
2377  // Cannot copy/move, stored in a unique_ptr
2378  dual_order_by_comparator(const dual_order_by_comparator&) = delete;
2379  dual_order_by_comparator& operator=(const dual_order_by_comparator&) = delete;
2380 
2381  // Compares two values by calling first then second comparator.
2382  template<typename T1, typename T2>
2383  int operator()(T1&& left, T2&& right) const {
2384  int cmp = (*upcmp1_)(left, right);
2385  if (cmp == 0) {
2386  cmp = (*upcmp2_)(left, right);
2387  }
2388  return cmp;
2389  }
2390 };
2391 
2392 /// @cond
2393 
2394 // Forward declaration to declare friendship
2395 template<typename Cmp> class order_by_impl;
2396 
2397 /// @endcond
2398 
2399 /**
2400  * @internal
2401  * @brief <tt>coveo::linq::order_by()</tt> et al implementation.
2402  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2403  *
2404  * "Second" implementation of the <tt>coveo::linq::order_by()</tt>,
2405  * <tt>coveo::linq::order_by_descending()</tt>, <tt>coveo::linq::then_by()</tt>
2406  * and <tt>coveo::linq::then_by_descending()</tt> LINQ operators.
2407  * This is the implementation that has both a comparator and a sequence.
2408  * It is the final form when the operator is fully applied.
2409  *
2410  * Contrarily to all other LINQ operation implementations, this
2411  * implementation cannot return a <tt>coveo::enumerable</tt>, because
2412  * we need to keep our identity to allow chaining. Thus, we implement
2413  * an @c enumerable "interface" manually by fronting the same methods.
2414  *
2415  * @tparam Seq Sequence to order.
2416  * @tparam Cmp Comparator used to order sequence elements.
2417  * @see coveo::linq::order_by()
2418  * @see coveo::linq::order_by_descending()
2419  * @see coveo::linq::then_by()
2420  * @see coveo::linq::then_by_descending()
2421  * @see coveo::linq::detail::order_by_impl
2422  */
2423 template<typename Seq, typename Cmp>
2424 class order_by_impl_with_seq
2425 {
2426  // We need this friendship so that it can "steal" our internals.
2427  template<typename> friend class order_by_impl;
2428 
2429 private:
2430  Seq seq_; // Sequence we're ordering.
2431  std::unique_ptr<Cmp> upcmp_; // Comparator used to order a sequence.
2432  enumerable<typename seq_traits<Seq>::value_type> enum_; // Enumerator of ordered elements.
2433  bool init_called_ = false; // Whether enum_ has been initialized.
2434 
2435  // Called to initialize enum_ before using it.
2436  void init() {
2437  std::vector<typename seq_traits<Seq>::pointer> ordered;
2438  try_reserve(ordered, seq_);
2439  for (auto&& elem : seq_) {
2440  typename seq_traits<Seq>::reference robj = elem;
2441  ordered.push_back(std::addressof(robj));
2442  }
2443  std::stable_sort(ordered.begin(),
2444  ordered.end(),
2445  [this](typename seq_traits<Seq>::pointer pleft,
2446  typename seq_traits<Seq>::pointer pright) {
2447  return (*upcmp_)(*pleft, *pright) < 0;
2448  });
2449  const std::size_t num_ordered = ordered.size();
2450  enum_ = { make_deref_next_impl(std::move(ordered)),
2451  [num_ordered]() -> std::size_t { return num_ordered; } };
2452  init_called_ = true;
2453  }
2454 
2455 public:
2456  // Type of iterators used for the ordered sequence.
2457  using iterator = typename enumerable<typename seq_traits<Seq>::value_type>::iterator;
2458  using const_iterator = typename enumerable<typename seq_traits<Seq>::value_type>::const_iterator;
2459 
2460  // Constructor called by the impl without sequence.
2461  order_by_impl_with_seq(Seq&& seq, std::unique_ptr<Cmp>&& upcmp)
2462  : seq_(std::forward<Seq>(seq)), upcmp_(std::move(upcmp)) { }
2463 
2464  // Movable but not copyable
2465  order_by_impl_with_seq(const order_by_impl_with_seq&) = delete;
2466  order_by_impl_with_seq(order_by_impl_with_seq&&) = default;
2467  order_by_impl_with_seq& operator=(const order_by_impl_with_seq&) = delete;
2468  order_by_impl_with_seq& operator=(order_by_impl_with_seq&&) = default;
2469 
2470  // Support for ordered sequence.
2471  iterator begin() const {
2472  if (!init_called_) {
2473  const_cast<order_by_impl_with_seq<Seq, Cmp>*>(this)->init();
2474  }
2475  return enum_.begin();
2476  }
2477  iterator end() const {
2478  if (!init_called_) {
2479  const_cast<order_by_impl_with_seq<Seq, Cmp>*>(this)->init();
2480  }
2481  return enum_.end();
2482  }
2483  iterator cbegin() const {
2484  return begin();
2485  }
2486  iterator cend() const {
2487  return end();
2488  }
2489 
2490  // Support for sequence size (a bit like the enumerable API)
2491  bool has_fast_size() const {
2492  if (!init_called_) {
2493  const_cast<order_by_impl_with_seq<Seq, Cmp>*>(this)->init();
2494  }
2495  return enum_.has_fast_size();
2496  }
2497  std::size_t size() const {
2498  if (!init_called_) {
2499  const_cast<order_by_impl_with_seq<Seq, Cmp>*>(this)->init();
2500  }
2501  return enum_.size();
2502  }
2503 };
2504 
2505 /**
2506  * @internal
2507  * @brief <tt>coveo::linq::order_by()</tt> et al implementation.
2508  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2509  *
2510  * "First" implementation of the <tt>coveo::linq::order_by()</tt>,
2511  * <tt>coveo::linq::order_by_descending()</tt>, <tt>coveo::linq::then_by()</tt>
2512  * and <tt>coveo::linq::then_by_descending()</tt> LINQ operators.
2513  * This is the implementation with a comparator only; it is returned by
2514  * the operator helper methods. It supports two operations: either being
2515  * applied to a sequence, in which case it produces the "second" implementation
2516  * (see <tt>coveo::linq::detail::order_by_impl_with_seq</tt>), or being
2517  * applied to an @c order_by_impl_with_seq, in which case we chain the
2518  * comparators.
2519  *
2520  * @tparam Cmp Comparator used to order sequence elements.
2521  * @see coveo::linq::order_by()
2522  * @see coveo::linq::order_by_descending()
2523  * @see coveo::linq::then_by()
2524  * @see coveo::linq::then_by_descending()
2525  * @see coveo::linq::detail::order_by_impl_with_seq
2526  * @see coveo::linq::detail::order_by_comparator
2527  * @see coveo::linq::detail::dual_order_by_comparator
2528  */
2529 template<typename Cmp>
2530 class order_by_impl
2531 {
2532 private:
2533  std::unique_ptr<Cmp> upcmp_; // Comparator used to order a sequence.
2534 
2535 public:
2536  explicit order_by_impl(std::unique_ptr<Cmp>&& upcmp)
2537  : upcmp_(std::move(upcmp)) { }
2538 
2539  // Movable by not copyable
2540  order_by_impl(const order_by_impl&) = delete;
2541  order_by_impl(order_by_impl&&) = default;
2542  order_by_impl& operator=(const order_by_impl&) = delete;
2543  order_by_impl& operator=(order_by_impl&&) = default;
2544 
2545  // When applied to a sequence, produces a different object.
2546  template<typename Seq>
2547  auto operator()(Seq&& seq) -> order_by_impl_with_seq<Seq, Cmp> {
2548  return order_by_impl_with_seq<Seq, Cmp>(std::forward<Seq>(seq), std::move(upcmp_));
2549  }
2550 
2551  // When applied to an impl with sequence, merges the two and chains the comparators.
2552  template<typename ImplSeq, typename ImplCmp>
2553  auto operator()(order_by_impl_with_seq<ImplSeq, ImplCmp>&& impl)
2554  -> order_by_impl_with_seq<ImplSeq, dual_order_by_comparator<ImplCmp, Cmp>>
2555  {
2556  using dual_comparator = dual_order_by_comparator<ImplCmp, Cmp>;
2557  auto new_upcmp = detail::make_unique<dual_comparator>(std::move(impl.upcmp_), std::move(upcmp_));
2558  return order_by_impl_with_seq<ImplSeq, dual_comparator>(std::forward<ImplSeq>(impl.seq_), std::move(new_upcmp));
2559  }
2560 };
2561 
2562 /**
2563  * @internal
2564  * @brief <tt>coveo::linq::reverse()</tt> implementation.
2565  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2566  *
2567  * Implementation of the <tt>coveo::linq::reverse()</tt> LINQ operator.
2568  *
2569  * @see coveo::linq::reverse()
2570  */
2571 template<typename = void>
2572 class reverse_impl
2573 {
2574 private:
2575  // next impl when we can use reverse iterators
2576  template<typename Seq>
2577  class next_impl_fast
2578  {
2579  private:
2580  // Iterator used to go backward in sequence.
2581  using reverse_iterator = typename std::decay<decltype(std::declval<Seq>().rbegin())>::type;
2582 
2583  // Bean containing info shared among delegates
2584  struct reverse_info {
2585  Seq seq_; // Sequence we're iterating.
2586  reverse_iterator irend_; // End of reversed seq_.
2587 
2588  explicit reverse_info(Seq&& seq)
2589  : seq_(std::forward<Seq>(seq)),
2590  irend_(seq_.rend()) { }
2591 
2592  // Cannot copy/move, stored in a shared_ptr.
2593  reverse_info(const reverse_info&) = delete;
2594  reverse_info& operator=(const reverse_info&) = delete;
2595  };
2596  using reverse_info_sp = std::shared_ptr<reverse_info>;
2597 
2598  reverse_info_sp spinfo_; // Shared info with sequence.
2599  reverse_iterator ircur_; // Current point in reverse sequence.
2600 
2601  public:
2602  explicit next_impl_fast(Seq&& seq)
2603  : spinfo_(std::make_shared<reverse_info>(std::forward<Seq>(seq))),
2604  ircur_(spinfo_->seq_.rbegin()) { }
2605 
2606  auto operator()() -> typename seq_traits<Seq>::pointer {
2607  typename seq_traits<Seq>::pointer pobj = nullptr;
2608  if (ircur_ != spinfo_->irend_) {
2609  typename seq_traits<Seq>::reference robj = *ircur_;
2610  pobj = std::addressof(robj);
2611  ++ircur_;
2612  }
2613  return pobj;
2614  }
2615  };
2616 
2617  // next impl when we don't have reverse iterators natively
2618  template<typename Seq>
2619  class next_impl_slow
2620  {
2621  private:
2622  // Vector storing pointers of elements from sequence.
2623  using pelems_v = std::vector<typename seq_traits<Seq>::pointer>;
2624  using pelems_v_reverse_iterator = typename pelems_v::reverse_iterator;
2625 
2626  // Bean containing info shared among delegates
2627  struct reverse_info {
2628  Seq seq_; // Sequence containing the elements.
2629  pelems_v vpelems_; // Vector of pointers to the elements.
2630  pelems_v_reverse_iterator virend_; // Iterator pointing at end of vpelems_.
2631 
2632  explicit reverse_info(Seq&& seq)
2633  : seq_(std::forward<Seq>(seq))
2634  {
2635  // Build vector of pointers to sequence elements.
2636  try_reserve(vpelems_, seq_);
2637  for (auto&& elem : seq_) {
2638  typename seq_traits<Seq>::reference robj = elem;
2639  vpelems_.push_back(std::addressof(robj));
2640  }
2641 
2642  // Init end iterator.
2643  virend_ = vpelems_.rend();
2644  }
2645 
2646  // Cannot copy/move, stored in a shared_ptr.
2647  reverse_info(const reverse_info&) = delete;
2648  reverse_info& operator=(const reverse_info&) = delete;
2649  };
2650  using reverse_info_sp = std::shared_ptr<reverse_info>;
2651 
2652  reverse_info_sp spinfo_; // Bean storing sequence and vector of pointers.
2653  pelems_v_reverse_iterator vircur_; // Iterator pointing at current pointer to element.
2654 
2655  public:
2656  explicit next_impl_slow(Seq&& seq)
2657  : spinfo_(std::make_shared<reverse_info>(std::forward<Seq>(seq))),
2658  vircur_(spinfo_->vpelems_.rbegin()) { }
2659 
2660  auto operator()() -> typename seq_traits<Seq>::pointer {
2661  typename seq_traits<Seq>::pointer pobj = nullptr;
2662  if (vircur_ != spinfo_->virend_) {
2663  pobj = *vircur_;
2664  ++vircur_;
2665  }
2666  return pobj;
2667  }
2668 
2669  // To be able to build a proper size delegate
2670  std::size_t size() const {
2671  return spinfo_->vpelems_.size();
2672  }
2673  };
2674 
2675  // If we have bidi iterators, we can simply use rbegin
2676  template<typename Seq>
2677  auto impl(Seq&& seq, std::bidirectional_iterator_tag)
2678  -> enumerable<typename seq_traits<Seq>::value_type>
2679  {
2680  auto siz = try_get_size_delegate(seq);
2681  return enumerable<typename seq_traits<Seq>::value_type>(next_impl_fast<Seq>(std::forward<Seq>(seq)),
2682  siz);
2683  }
2684 
2685  // Otherwise we'll have to be creative
2686  template<typename Seq>
2687  auto impl(Seq&& seq, std::input_iterator_tag)
2688  -> enumerable<typename seq_traits<Seq>::value_type>
2689  {
2690  next_impl_slow<Seq> next_impl(std::forward<Seq>(seq));
2691  const std::size_t size = next_impl.size();
2692  auto siz = [size]() -> std::size_t { return size; };
2693  return enumerable<typename seq_traits<Seq>::value_type>(std::move(next_impl),
2694  siz);
2695  }
2696 
2697 public:
2698  template<typename Seq>
2699  auto operator()(Seq&& seq)
2700  -> enumerable<typename seq_traits<Seq>::value_type>
2701  {
2702  return impl(std::forward<Seq>(seq),
2703  typename std::iterator_traits<typename seq_traits<Seq>::iterator_type>::iterator_category());
2704  }
2705 };
2706 
2707 /**
2708  * @internal
2709  * @brief <tt>coveo::linq::select()</tt> et al implementation.
2710  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2711  *
2712  * Implementation of the <tt>coveo::linq::select()</tt> and
2713  * <tt>coveo::linq::select_with_index()</tt> LINQ operators.
2714  *
2715  * @tparam Selector Selector to transform sequence elements.
2716  * @see coveo::linq::select()
2717  * @see coveo::linq::select_with_index()
2718  */
2719 template<typename Selector>
2720 class select_impl
2721 {
2722 public:
2723  // Next delegate implementation for select operator
2724  template<typename Seq, typename CU, typename RU>
2725  class next_impl
2726  {
2727  private:
2728  // Iterator used by the sequence.
2729  using iterator_type = typename seq_traits<Seq>::iterator_type;
2730 
2731  // Containers storing transformed elements.
2732  using transformed_v = std::vector<RU>;
2733  using transformed_l = std::forward_list<RU>;
2734  using transformed_l_iterator = typename transformed_l::iterator;
2735 
2736  // Bean storing info about elements. Shared among delegates.
2737  struct select_info {
2738  Seq seq_; // Sequence being transformed.
2739  iterator_type icur_; // Iterator pointing at current element in seq_.
2740  iterator_type iend_; // Iterator pointing at end of seq_.
2741  Selector sel_; // Selector transforming the elements.
2742  transformed_v vtransformed_; // Vector of transformed elements.
2743  transformed_l ltransformed_; // List of transformed elements.
2744  transformed_l_iterator llast_; // Iterator pointing to last element in ltransformed_ (before end()).
2745  std::size_t lsize_; // Number of elements in ltransformed_.
2746  bool use_vector_; // Whether we use ltransformed_ (false) or vtransformed_ (true).
2747 
2748  select_info(Seq&& seq, Selector&& sel)
2749  : seq_(std::forward<Seq>(seq)),
2750  icur_(std::begin(seq_)),
2751  iend_(std::end(seq_)),
2752  sel_(std::forward<Selector>(sel)),
2753  vtransformed_(),
2754  ltransformed_(),
2755  llast_(ltransformed_.before_begin()),
2756  lsize_(0),
2757  use_vector_(try_reserve(vtransformed_, seq_)) { }
2758 
2759  // Cannot copy/move, stored in a shared_ptr
2760  select_info(const select_info&) = delete;
2761  select_info& operator=(const select_info&) = delete;
2762 
2763  auto get_next_in_vector(std::size_t& vncur) -> CU* {
2764  while (vtransformed_.size() <= vncur && icur_ != iend_) {
2765  vtransformed_.emplace_back(sel_(*icur_, vtransformed_.size()));
2766  ++icur_;
2767  }
2768  return vtransformed_.size() > vncur ? std::addressof(vtransformed_[vncur++])
2769  : nullptr;
2770  }
2771 
2772  auto get_next_in_list(transformed_l_iterator& licur) -> CU* {
2773  while (licur == llast_ && icur_ != iend_) {
2774  llast_ = ltransformed_.emplace_after(llast_, sel_(*icur_, lsize_++));
2775  ++icur_;
2776  }
2777  return licur != llast_ ? std::addressof(*++licur)
2778  : nullptr;
2779  }
2780 
2781  auto get_next(std::size_t& vncur, transformed_l_iterator& licur) -> CU* {
2782  return use_vector_ ? get_next_in_vector(vncur)
2783  : get_next_in_list(licur);
2784  }
2785  };
2786  using select_info_sp = std::shared_ptr<select_info>;
2787 
2788  select_info_sp spinfo_; // Shared information about elements.
2789  std::size_t vncur_; // Index of current element (if in vector).
2790  transformed_l_iterator licur_; // Iterator pointing at current element (if in list).
2791 
2792  public:
2793  next_impl(Seq&& seq, Selector&& sel)
2794  : spinfo_(std::make_shared<select_info>(std::forward<Seq>(seq),
2795  std::forward<Selector>(sel))),
2796  vncur_(0),
2797  licur_(spinfo_->ltransformed_.before_begin()) { }
2798 
2799  auto operator()() -> CU* {
2800  return spinfo_->get_next(vncur_, licur_);
2801  }
2802  };
2803 
2804 private:
2805  Selector sel_; // Selector used to transform elements.
2806 
2807 public:
2808  explicit select_impl(Selector&& sel)
2809  : sel_(std::forward<Selector>(sel)) { }
2810 
2811  template<typename Seq,
2812  typename _SelectorRes = decltype(std::declval<Selector>()(std::declval<typename seq_traits<Seq>::reference>(), std::declval<std::size_t>())),
2813  typename _CU = typename seq_element_traits<_SelectorRes>::const_value_type,
2814  typename _RU = typename seq_element_traits<_SelectorRes>::raw_value_type>
2815  auto operator()(Seq&& seq) -> enumerable<_CU> {
2816  auto siz = try_get_size_delegate(seq);
2817  return enumerable<_CU>(next_impl<Seq, _CU, _RU>(std::forward<Seq>(seq), std::forward<Selector>(sel_)),
2818  siz);
2819  }
2820 };
2821 
2822 /**
2823  * @internal
2824  * @brief <tt>coveo::linq::select_many()</tt> et al implementation.
2825  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2826  *
2827  * Implementation of the <tt>coveo::linq::select_many()</tt> and
2828  * <tt>coveo::linq::select_many_with_index</tt> LINQ operators.
2829  *
2830  * @tparam Selector Selector used to transform sequence elements.
2831  * @see coveo::linq::select_many()
2832  * @see coveo::linq::select_many_with_index()
2833  */
2834 template<typename Selector>
2835 class select_many_impl
2836 {
2837 public:
2838  // Next delegate implementation for select_many operator
2839  template<typename Seq, typename CU, typename RU>
2840  class next_impl
2841  {
2842  private:
2843  // Iterator used by the sequence.
2844  using iterator_type = typename seq_traits<Seq>::iterator_type;
2845 
2846  // List storing transformed elements.
2847  using transformed_l = std::forward_list<RU>;
2848  using transformed_l_iterator = typename transformed_l::iterator;
2849 
2850  // Bean storing info about elements. Shared among delegates.
2851  struct select_info {
2852  Seq seq_; // Sequence being transformed.
2853  iterator_type icur_; // Iterator pointing at current element in seq_.
2854  std::size_t idx_; // Index of current element in seq_.
2855  iterator_type iend_; // Iterator pointing at end of seq_.
2856  Selector sel_; // Selector transforming the elements.
2857  transformed_l ltransformed_; // List of transformed elements.
2858  transformed_l_iterator llast_; // Iterator pointing to last element in ltransformed_ (before end()).
2859 
2860  select_info(Seq&& seq, Selector&& sel)
2861  : seq_(std::forward<Seq>(seq)),
2862  icur_(std::begin(seq_)),
2863  idx_(0),
2864  iend_(std::end(seq_)),
2865  sel_(std::forward<Selector>(sel)),
2866  ltransformed_(),
2867  llast_(ltransformed_.before_begin()) { }
2868 
2869  // Cannot copy/move, stored in a shared_ptr
2870  select_info(const select_info&) = delete;
2871  select_info& operator=(const select_info&) = delete;
2872 
2873  auto get_next(transformed_l_iterator& licur) -> CU* {
2874  while (licur == llast_ && icur_ != iend_) {
2875  auto new_elements = sel_(*icur_, idx_++);
2876  llast_ = ltransformed_.insert_after(llast_, std::begin(new_elements), std::end(new_elements));
2877  ++icur_;
2878  }
2879  return licur != llast_ ? std::addressof(*++licur)
2880  : nullptr;
2881  }
2882  };
2883  using select_info_sp = std::shared_ptr<select_info>;
2884 
2885  select_info_sp spinfo_; // Shared information about elements.
2886  transformed_l_iterator licur_; // Iterator pointing at current element.
2887 
2888  public:
2889  next_impl(Seq&& seq, Selector&& sel)
2890  : spinfo_(std::make_shared<select_info>(std::forward<Seq>(seq),
2891  std::forward<Selector>(sel))),
2892  licur_(spinfo_->ltransformed_.before_begin()) { }
2893 
2894  auto operator()() -> CU* {
2895  return spinfo_->get_next(licur_);
2896  }
2897  };
2898 
2899 private:
2900  Selector sel_; // Selector used to transform elements.
2901 
2902 public:
2903  explicit select_many_impl(Selector&& sel)
2904  : sel_(std::forward<Selector>(sel)) { }
2905 
2906  template<typename Seq,
2907  typename _SelectorSeqRes = decltype(std::declval<Selector>()(std::declval<typename seq_traits<Seq>::const_reference>(), std::declval<std::size_t>())),
2908  typename _CU = typename seq_traits<_SelectorSeqRes>::const_value_type,
2909  typename _RU = typename seq_traits<_SelectorSeqRes>::raw_value_type>
2910  auto operator()(Seq&& seq) -> enumerable<_CU> {
2911  return next_impl<Seq, _CU, _RU>(std::forward<Seq>(seq), std::forward<Selector>(sel_));
2912  }
2913 };
2914 
2915 /**
2916  * @internal
2917  * @brief <tt>coveo::linq::sequence_equal()</tt> implementation (1).
2918  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2919  *
2920  * Implementation of the <tt>coveo::linq::sequence_equal()</tt> LINQ operator.
2921  * Version with one argument (second sequence).
2922  *
2923  * @tparam Seq2 Second sequence to compare. The first one will have been
2924  * provided in the call to <tt>coveo::linq::from()</tt>.
2925  * @see coveo::linq::sequence_equal()
2926  */
2927 template<typename Seq2>
2928 class sequence_equal_impl_1
2929 {
2930 private:
2931  const Seq2& seq2_; // Second sequence to compare.
2932 
2933 public:
2934  explicit sequence_equal_impl_1(const Seq2& seq2)
2935  : seq2_(seq2) { }
2936 
2937  template<typename Seq1>
2938  auto operator()(Seq1&& seq1) -> bool {
2939  auto icur1 = std::begin(seq1);
2940  auto iend1 = std::end(seq1);
2941  auto icur2 = std::begin(seq2_);
2942  auto iend2 = std::end(seq2_);
2943  bool is_equal = true;
2944  for (; is_equal && icur1 != iend1 && icur2 != iend2; ++icur1, ++icur2) {
2945  is_equal = *icur1 == *icur2;
2946  }
2947  return is_equal && icur1 == iend1 && icur2 == iend2;
2948  }
2949 };
2950 
2951 /**
2952  * @internal
2953  * @brief <tt>coveo::linq::sequence_equal()</tt> implementation (2).
2954  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2955  *
2956  * Implementation of the <tt>coveo::linq::sequence_equal()</tt> LINQ operator.
2957  * Version with two arguments (second sequence and predicate).
2958  *
2959  * @tparam Seq2 Second sequence to compare. The first one will have been
2960  * provided in the call to <tt>coveo::linq::from()</tt>.
2961  * @tparam Pred Predicate used to compare sequence elements.
2962  * @see coveo::linq::sequence_equal()
2963  */
2964 template<typename Seq2, typename Pred>
2965 class sequence_equal_impl_2
2966 {
2967 private:
2968  const Seq2& seq2_; // Second sequence to compare.
2969  const Pred& pred_; // Equality predicate.
2970 
2971 public:
2972  sequence_equal_impl_2(const Seq2& seq2, const Pred& pred)
2973  : seq2_(seq2), pred_(pred) { }
2974 
2975  template<typename Seq1>
2976  auto operator()(Seq1&& seq1) -> bool {
2977  auto icur1 = std::begin(seq1);
2978  auto iend1 = std::end(seq1);
2979  auto icur2 = std::begin(seq2_);
2980  auto iend2 = std::end(seq2_);
2981  bool is_equal = true;
2982  for (; is_equal && icur1 != iend1 && icur2 != iend2; ++icur1, ++icur2) {
2983  is_equal = pred_(*icur1, *icur2);
2984  }
2985  return is_equal && icur1 == iend1 && icur2 == iend2;
2986  }
2987 };
2988 
2989 /**
2990  * @internal
2991  * @brief <tt>coveo::linq::single()</tt> implementation (0).
2992  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
2993  *
2994  * Implementation of the <tt>coveo::linq::single()</tt> LINQ operator.
2995  * Version without argument.
2996  *
2997  * @see coveo::linq::single()
2998  */
2999 template<typename = void>
3000 class single_impl_0
3001 {
3002 public:
3003  template<typename Seq>
3004  auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
3005  auto ifirst = std::begin(seq);
3006  auto iend = std::end(seq);
3007  if (ifirst == iend) {
3008  throw_linq_empty_sequence();
3009  }
3010  auto inext = ifirst;
3011  ++inext;
3012  if (inext != iend) {
3013  throw_linq_out_of_range();
3014  }
3015  return *ifirst;
3016  }
3017 };
3018 
3019 /**
3020  * @internal
3021  * @brief <tt>coveo::linq::single()</tt> implementation (1).
3022  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3023  *
3024  * Implementation of the <tt>coveo::linq::single()</tt> LINQ operator.
3025  * Version with predicate.
3026  *
3027  * @tparam Predicate to satisfy.
3028  * @see coveo::linq::single()
3029  */
3030 template<typename Pred>
3031 class single_impl_1
3032 {
3033 private:
3034  const Pred& pred_; // Predicate to satisfy.
3035 
3036 public:
3037  explicit single_impl_1(const Pred& pred)
3038  : pred_(pred) { }
3039 
3040  template<typename Seq>
3041  auto operator()(Seq&& seq) -> decltype(*std::begin(seq)) {
3042  auto ibeg = std::begin(seq);
3043  auto iend = std::end(seq);
3044  if (ibeg == iend) {
3045  throw_linq_empty_sequence();
3046  }
3047  auto ifound = std::find_if(ibeg, iend, pred_);
3048  if (ifound == iend) {
3049  throw_linq_out_of_range();
3050  }
3051  auto inext = ifound;
3052  ++inext;
3053  auto ifoundagain = std::find_if(inext, iend, pred_);
3054  if (ifoundagain != iend) {
3055  throw_linq_out_of_range();
3056  }
3057  return *ifound;
3058  }
3059 };
3060 
3061 /**
3062  * @internal
3063  * @brief <tt>coveo::linq::single_or_default()</tt> implementation (0).
3064  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3065  *
3066  * Implementation of the <tt>coveo::linq::single_or_default()</tt> LINQ operator.
3067  * Version without argument.
3068  *
3069  * @see coveo::linq::single_or_default()
3070  */
3071 template<typename = void>
3072 class single_or_default_impl_0
3073 {
3074 public:
3075  template<typename Seq>
3076  auto operator()(Seq&& seq) -> typename seq_traits<Seq>::raw_value_type {
3077  auto icur = std::begin(seq);
3078  auto iend = std::end(seq);
3079  if (icur != iend) {
3080  auto inext = icur;
3081  ++inext;
3082  if (inext != iend) {
3083  icur = iend;
3084  }
3085  }
3086  return icur != iend ? *icur
3087  : typename seq_traits<Seq>::raw_value_type();
3088  }
3089 };
3090 
3091 /**
3092  * @internal
3093  * @brief <tt>coveo::linq::single_or_default()</tt> implementation (1).
3094  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3095  *
3096  * Implementation of the <tt>coveo::linq::single_or_default()</tt> LINQ operator.
3097  * Version with predicate.
3098  *
3099  * @tparam Pred Predicate to satisfy.
3100  * @see coveo::linq::single_or_default()
3101  */
3102 template<typename Pred>
3103 class single_or_default_impl_1
3104 {
3105 private:
3106  const Pred& pred_; // Predicate to satisfy.
3107 
3108 public:
3109  explicit single_or_default_impl_1(const Pred& pred)
3110  : pred_(pred) { }
3111 
3112  template<typename Seq>
3113  auto operator()(Seq&& seq) -> typename seq_traits<Seq>::raw_value_type {
3114  auto iend = std::end(seq);
3115  auto ifound = std::find_if(std::begin(seq), iend, pred_);
3116  if (ifound != iend) {
3117  auto inext = ifound;
3118  ++inext;
3119  auto ifoundagain = std::find_if(inext, iend, pred_);
3120  if (ifoundagain != iend) {
3121  ifound = iend;
3122  }
3123  }
3124  return ifound != iend ? *ifound
3125  : typename seq_traits<Seq>::raw_value_type();
3126  }
3127 };
3128 
3129 /**
3130  * @internal
3131  * @brief <tt>coveo::linq::skip()</tt> internal predicate.
3132  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3133  *
3134  * Predicate used by the implementation of the <tt>coveo::linq::skip()</tt>
3135  * LINQ operator. Simply skips N elements.
3136  *
3137  * @see coveo::linq::skip()
3138  * @see coveo::linq::detail::skip_impl
3139  */
3140 template<typename = void>
3141 class skip_n_pred
3142 {
3143 private:
3144  std::size_t n_; // Number of elements to skip.
3145 
3146 public:
3147  explicit skip_n_pred(std::size_t n)
3148  : n_(n) { }
3149 
3150  template<typename T>
3151  auto operator()(T&&, std::size_t idx) -> bool {
3152  return idx < n_;
3153  }
3154 };
3155 
3156 /**
3157  * @internal
3158  * @brief <tt>coveo::linq::skip()</tt> et al implementation.
3159  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3160  *
3161  * Implementation of the <tt>coveo::linq::skip()</tt>,
3162  * <tt>coveo::linq::skip_while()</tt> and
3163  * <tt>coveo::linq::skip_while_with_index()</tt> LINQ operators.
3164  *
3165  * @tparam Pred Predicate used to skip elements.
3166  * @see coveo::linq::skip()
3167  * @see coveo::linq::skip_while()
3168  * @see coveo::linq::skip_while_with_index()
3169  */
3170 template<typename Pred>
3171 class skip_impl
3172 {
3173 public:
3174  // Next delegate implementation for skip operators
3175  template<typename Seq>
3176  class next_impl
3177  {
3178  private:
3179  // Iterator for the sequence type.
3180  using iterator_type = typename seq_traits<Seq>::iterator_type;
3181 
3182  // Bean containing info to share among delegates
3183  struct skip_info {
3184  Seq seq_; // Sequence to skip elements from
3185  iterator_type iend_; // Iterator pointing at end of sequence
3186  Pred pred_; // Predicate to satisfy to skip elements
3187 
3188  skip_info(Seq&& seq, Pred&& pred)
3189  : seq_(std::forward<Seq>(seq)),
3190  iend_(std::end(seq_)),
3191  pred_(std::forward<Pred>(pred)) { }
3192 
3193  // Cannot copy/move, stored in a shared_ptr
3194  skip_info(const skip_info&) = delete;
3195  skip_info& operator=(const skip_info&) = delete;
3196  };
3197  using skip_info_sp = std::shared_ptr<skip_info>;
3198 
3199  skip_info_sp spinfo_; // Pointer to shared info
3200  iterator_type icur_; // Iterator pointing at current element
3201  bool init_called_ = false; // Whether icur_ has been initialized
3202 
3203  void init() {
3204  icur_ = std::begin(spinfo_->seq_);
3205  std::size_t n = 0;
3206  while (icur_ != spinfo_->iend_ && spinfo_->pred_(*icur_, n++)) {
3207  ++icur_;
3208  }
3209  init_called_ = true;
3210  }
3211 
3212  public:
3213  next_impl(Seq&& seq, Pred&& pred)
3214  : spinfo_(std::make_shared<skip_info>(std::forward<Seq>(seq),
3215  std::forward<Pred>(pred))) { }
3216 
3217  auto operator()() -> typename seq_traits<Seq>::pointer {
3218  // Init starting point on first call
3219  if (!init_called_) {
3220  init();
3221  }
3222  typename seq_traits<Seq>::pointer pobj = nullptr;
3223  if (icur_ != spinfo_->iend_) {
3224  typename seq_traits<Seq>::reference robj = *icur_;
3225  pobj = std::addressof(robj);
3226  ++icur_;
3227  }
3228  return pobj;
3229  }
3230  };
3231 
3232 private:
3233  Pred pred_; // Predicate to satisfy to skip.
3234  std::size_t n_; // How many items to skip, if known (otherwise -1).
3235 
3236 public:
3237  skip_impl(Pred&& pred, std::size_t n)
3238  : pred_(std::forward<Pred>(pred)),
3239  n_(n) { }
3240 
3241  template<typename Seq>
3242  auto operator()(Seq&& seq)
3243  -> enumerable<typename seq_traits<Seq>::value_type>
3244  {
3245  typename enumerable<typename seq_traits<Seq>::value_type>::size_delegate siz;
3246  if (n_ != static_cast<std::size_t>(-1)) {
3247  auto seq_siz = try_get_size_delegate(seq);
3248  if (seq_siz != nullptr) {
3249  const std::size_t seq_size = seq_siz();
3250  const std::size_t size = seq_size > n_ ? seq_size - n_ : 0;
3251  siz = [size]() -> std::size_t { return size; };
3252  }
3253  }
3254  return enumerable<typename seq_traits<Seq>::value_type>(next_impl<Seq>(std::forward<Seq>(seq),
3255  std::forward<Pred>(pred_)),
3256  siz);
3257  }
3258 };
3259 
3260 /**
3261  * @internal
3262  * @brief <tt>coveo::linq::sum()</tt> implementation.
3263  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3264  *
3265  * Implementation of the <tt>coveo::linq::sum()</tt> LINQ operator.
3266  *
3267  * @tparam F Function to fetch values from sequence elements.
3268  * @see coveo::linq::sum()
3269  */
3270 template<typename F>
3271 class sum_impl
3272 {
3273 private:
3274  const F& num_f_;
3275 
3276 public:
3277  explicit sum_impl(const F& num_f)
3278  : num_f_(num_f) { }
3279 
3280  template<typename Seq>
3281  auto operator()(Seq&& seq) -> typename std::decay<decltype(num_f_(*std::begin(seq)))>::type {
3282  auto it = std::begin(seq);
3283  auto end = std::end(seq);
3284  if (it == end) {
3285  throw_linq_empty_sequence();
3286  }
3287  auto total = num_f_(*it);
3288  for (++it; it != end; ++it) {
3289  total += num_f_(*it);
3290  }
3291  return total;
3292  }
3293 };
3294 
3295 /**
3296  * @internal
3297  * @brief <tt>coveo::linq::take()</tt> et al implementation.
3298  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3299  *
3300  * Implementation of the <tt>coveo::linq::take()</tt>,
3301  * <tt>coveo::linq::take_while()</tt> and
3302  * <tt>coveo::linq::take_while_with_index()</tt> LINQ operators.
3303  *
3304  * @tparam Pred Predicate used to take elements.
3305  * @see coveo::linq::take()
3306  * @see coveo::linq::take_while()
3307  * @see coveo::linq::take_while_with_index()
3308  */
3309 template<typename Pred>
3310 class take_impl
3311 {
3312 public:
3313  // Next delegate implementation for take operators
3314  template<typename Seq>
3315  class next_impl
3316  {
3317  private:
3318  // Iterator for the sequence type.
3319  using iterator_type = typename seq_traits<Seq>::iterator_type;
3320 
3321  // Bean containing info to share among delegates
3322  struct take_info {
3323  Seq seq_; // Sequence to take elements from
3324  iterator_type iend_; // Iterator pointing at end of sequence
3325  Pred pred_; // Predicate to satisfy to take elements
3326 
3327  take_info(Seq&& seq, Pred&& pred)
3328  : seq_(std::forward<Seq>(seq)),
3329  iend_(std::end(seq_)),
3330  pred_(std::forward<Pred>(pred)) { }
3331 
3332  // Cannot copy/move, stored in a shared_ptr
3333  take_info(const take_info&) = delete;
3334  take_info& operator=(const take_info&) = delete;
3335  };
3336  using take_info_sp = std::shared_ptr<take_info>;
3337 
3338  take_info_sp spinfo_; // Pointer to shared info
3339  iterator_type icur_; // Iterator pointing at current element
3340  std::size_t n_ = 0; // Index of current element
3341  bool done_ = false; // Whether we're done taking elements
3342 
3343  public:
3344  next_impl(Seq&& seq, Pred&& pred)
3345  : spinfo_(std::make_shared<take_info>(std::forward<Seq>(seq),
3346  std::forward<Pred>(pred))),
3347  icur_(std::begin(spinfo_->seq_)) { }
3348 
3349  auto operator()() -> typename seq_traits<Seq>::pointer {
3350  typename seq_traits<Seq>::pointer pobj = nullptr;
3351  if (!done_) {
3352  if (icur_ != spinfo_->iend_ && spinfo_->pred_(*icur_, n_++)) {
3353  typename seq_traits<Seq>::reference robj = *icur_;
3354  pobj = std::addressof(robj);
3355  ++icur_;
3356  } else {
3357  done_ = true;
3358  }
3359  }
3360  return pobj;
3361  }
3362  };
3363 
3364 private:
3365  Pred pred_; // Predicate to satisfy to skip.
3366  std::size_t n_; // How many items to take, if known (otherwise -1).
3367 
3368 public:
3369  take_impl(Pred&& pred, std::size_t n)
3370  : pred_(std::forward<Pred>(pred)),
3371  n_(n) { }
3372 
3373  template<typename Seq>
3374  auto operator()(Seq&& seq)
3375  -> enumerable<typename seq_traits<Seq>::value_type>
3376  {
3377  typename enumerable<typename seq_traits<Seq>::value_type>::size_delegate siz;
3378  if (n_ != static_cast<std::size_t>(-1)) {
3379  auto seq_siz = try_get_size_delegate(seq);
3380  if (seq_siz != nullptr) {
3381  const std::size_t size = std::min(n_, seq_siz());
3382  siz = [size]() -> std::size_t { return size; };
3383  }
3384  }
3385  return enumerable<typename seq_traits<Seq>::value_type>(next_impl<Seq>(std::forward<Seq>(seq),
3386  std::forward<Pred>(pred_)),
3387  siz);
3388  }
3389 };
3390 
3391 /**
3392  * @internal
3393  * @brief <tt>coveo::linq::to()</tt> implementation.
3394  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3395  *
3396  * Implementation of the <tt>coveo::linq::to()</tt> LINQ operator.
3397  *
3398  * @tparam Container Type of container to return.
3399  * @see coveo::linq::to()
3400  */
3401 template<typename Container>
3402 class to_impl
3403 {
3404 public:
3405  template<typename Seq>
3406  auto operator()(Seq&& seq) -> Container {
3407  return Container(std::begin(std::forward<Seq>(seq)), std::end(std::forward<Seq>(seq)));
3408  }
3409 };
3410 
3411 /**
3412  * @internal
3413  * @brief <tt>coveo::linq::to_vector()</tt> implementation.
3414  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3415  *
3416  * Implementation of the <tt>coveo::linq::to_vector()</tt> LINQ operator.
3417  *
3418  * @see coveo::linq::to_vector()
3419  */
3420 template<typename = void>
3421 class to_vector_impl
3422 {
3423 public:
3424  template<typename Seq>
3425  auto operator()(Seq&& seq) -> std::vector<typename seq_traits<Seq>::raw_value_type> {
3426  std::vector<typename seq_traits<Seq>::raw_value_type> v;
3427  try_reserve(v, seq);
3428  v.insert(v.end(), std::begin(std::forward<Seq>(seq)), std::end(std::forward<Seq>(seq)));
3429  return v;
3430  }
3431 };
3432 
3433 /**
3434  * @internal
3435  * @brief <tt>coveo::linq::to_associative()</tt> implementation (1).
3436  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3437  *
3438  * Implementation of the <tt>coveo::linq::to_associative()</tt> LINQ operator.
3439  * Version with one argument (key selector).
3440  *
3441  * @tparam Container Type of container to return.
3442  * @tparam KeySelector Selector used to fetch keys from sequence elements.
3443  * @see coveo::linq::to_associative()
3444  */
3445 template<typename Container, typename KeySelector>
3446 class to_associative_impl_1
3447 {
3448 private:
3449  const KeySelector& key_sel_; // Selector to fetch keys for sequence elements.
3450 
3451 public:
3452  explicit to_associative_impl_1(const KeySelector& key_sel)
3453  : key_sel_(key_sel) { }
3454 
3455  template<typename Seq>
3456  auto operator()(Seq&& seq) -> Container {
3457  Container c;
3458  for (auto&& elem : seq) {
3459  auto key = key_sel_(elem);
3460  auto emplace_res = c.emplace(key, elem);
3461  if (!emplace_res.second) {
3462  emplace_res.first->second = elem;
3463  }
3464  }
3465  return c;
3466  }
3467 };
3468 
3469 /**
3470  * @internal
3471  * @brief <tt>coveo::linq::to_associative()</tt> implementation (2).
3472  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3473  *
3474  * Implementation of the <tt>coveo::linq::to_associative()</tt> LINQ operator.
3475  * Version with two arguments (key and element selectors).
3476  *
3477  * @tparam Container Type of container to return.
3478  * @tparam KeySelector Selector used to fetch keys from sequence elements.
3479  * @tparam ElementSelector Selector used to fetch values from sequence elements.
3480  * @see coveo::linq::to_associative()
3481  */
3482 template<typename Container, typename KeySelector, typename ElementSelector>
3483 class to_associative_impl_2
3484 {
3485 private:
3486  const KeySelector& key_sel_; // Selector to fetch keys for sequence elements.
3487  const ElementSelector& elem_sel_; // Selector to fetch values for sequence elements.
3488 
3489 public:
3490  to_associative_impl_2(const KeySelector& key_sel, const ElementSelector& elem_sel)
3491  : key_sel_(key_sel), elem_sel_(elem_sel) { }
3492 
3493  template<typename Seq>
3494  auto operator()(Seq&& seq) -> Container {
3495  Container c;
3496  for (auto&& elem : seq) {
3497  auto key = key_sel_(elem);
3498  auto mapped = elem_sel_(elem);
3499  auto emplace_res = c.emplace(key, mapped);
3500  if (!emplace_res.second) {
3501  emplace_res.first->second = mapped;
3502  }
3503  }
3504  return c;
3505  }
3506 };
3507 
3508 /**
3509  * @internal
3510  * @brief <tt>coveo::linq::to_map()</tt> implementation (1).
3511  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3512  *
3513  * Implementation of the <tt>coveo::linq::to_map()</tt> LINQ operator.
3514  * Version with one argument (key selector).
3515  *
3516  * @tparam KeySelector Selector used to fetch keys from sequence elements.
3517  * @see coveo::linq::to_map()
3518  */
3519 template<typename KeySelector>
3520 class to_map_impl_1
3521 {
3522 private:
3523  const KeySelector& key_sel_; // Selector to fetch keys for sequence elements.
3524 
3525 public:
3526  explicit to_map_impl_1(const KeySelector& key_sel)
3527  : key_sel_(key_sel) { }
3528 
3529  template<typename Seq>
3530  auto operator()(Seq&& seq)
3531  -> std::map<typename std::decay<decltype(key_sel_(*std::begin(seq)))>::type,
3532  typename seq_traits<Seq>::raw_value_type>
3533  {
3534  std::map<typename std::decay<decltype(key_sel_(*std::begin(seq)))>::type,
3535  typename seq_traits<Seq>::raw_value_type> m;
3536  for (auto&& elem : seq) {
3537  auto key = key_sel_(elem);
3538  auto emplace_res = m.emplace(key, elem);
3539  if (!emplace_res.second) {
3540  emplace_res.first->second = elem;
3541  }
3542  }
3543  return m;
3544  }
3545 };
3546 
3547 /**
3548  * @internal
3549  * @brief <tt>coveo::linq::to_map()</tt> implementation (2).
3550  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3551  *
3552  * Implementation of the <tt>coveo::linq::to_map()</tt> LINQ operator.
3553  * Version with two arguments (key and element selectors).
3554  *
3555  * @tparam KeySelector Selector used to fetch keys from sequence elements.
3556  * @tparam ElementSelector Selector used to fetch values from sequence elements.
3557  * @see coveo::linq::to_map()
3558  */
3559 template<typename KeySelector, typename ElementSelector>
3560 class to_map_impl_2
3561 {
3562 private:
3563  const KeySelector& key_sel_; // Selector to fetch keys for sequence elements.
3564  const ElementSelector& elem_sel_; // Selector to fetch values for sequence elements.
3565 
3566 public:
3567  to_map_impl_2(const KeySelector& key_sel, const ElementSelector& elem_sel)
3568  : key_sel_(key_sel), elem_sel_(elem_sel) { }
3569 
3570  template<typename Seq>
3571  auto operator()(Seq&& seq)
3572  -> std::map<typename std::decay<decltype(key_sel_(*std::begin(seq)))>::type,
3573  typename std::decay<decltype(elem_sel_(*std::begin(seq)))>::type>
3574  {
3575  std::map<typename std::decay<decltype(key_sel_(*std::begin(seq)))>::type,
3576  typename std::decay<decltype(elem_sel_(*std::begin(seq)))>::type> m;
3577  for (auto&& elem : seq) {
3578  auto key = key_sel_(elem);
3579  auto mapped = elem_sel_(elem);
3580  auto emplace_res = m.emplace(key, mapped);
3581  if (!emplace_res.second) {
3582  emplace_res.first->second = mapped;
3583  }
3584  }
3585  return m;
3586  }
3587 };
3588 
3589 /**
3590  * @internal
3591  * @brief <tt>coveo::linq::union_with()</tt> implementation.
3592  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3593  *
3594  * Implementation of the <tt>coveo::linq::union_with()</tt> LINQ operator.
3595  *
3596  * @tparam Seq2 Second sequence to union. The first sequence will have been
3597  * provided by the call to <tt>coveo::linq::from()</tt>.
3598  * @see coveo::linq::union_with()
3599  */
3600 template<typename Seq2, typename Pred>
3601 class union_impl
3602 {
3603 public:
3604  // Implementation of next delegate that filters duplicate elements
3605  template<typename Seq1>
3606  class next_impl
3607  {
3608  public:
3609  // Type of element returned by this next delegate. The elements will be const
3610  // if at least one sequence is const.
3611  using enum_type = typename std::conditional<std::is_const<typename seq_traits<Seq1>::value_type>::value ||
3612  std::is_const<typename seq_traits<Seq2>::value_type>::value,
3613  typename seq_traits<Seq1>::const_value_type,
3614  typename seq_traits<Seq1>::value_type>::type;
3615  using enum_ptr_type = typename seq_element_traits<enum_type>::pointer;
3616  using enum_ref_type = typename seq_element_traits<enum_type>::reference;
3617 
3618  private:
3619  // Type of iterator for the sequences
3620  using first_iterator_type = typename seq_traits<Seq1>::iterator_type;
3621  using second_iterator_type = typename seq_traits<Seq2>::iterator_type;
3622 
3623  // Set storing pointers to seen elements
3624  using seen_elements_set = std::set<enum_ptr_type, deref_cmp<proxy_cmp<Pred>>>;
3625 
3626  // Info used to produce distinct elements. Shared among delegates.
3627  class union_info
3628  {
3629  private:
3630  Seq1 seq1_; // First sequence being iterated
3631  first_iterator_type iend1_; // Iterator pointing at end of first sequence
3632  Seq2 seq2_; // Second sequence being iterated
3633  second_iterator_type iend2_; // Iterator pointing at end of second sequence
3634  Pred pred_; // Predicate ordering the elements
3635 
3636  template<typename It>
3637  auto get_next_in_seq(It& icur, const It& iend, seen_elements_set& seen) -> enum_ptr_type {
3638  enum_ptr_type pobj = nullptr;
3639  for (; pobj == nullptr && icur != iend; ++icur) {
3640  enum_ref_type robjtmp = *icur;
3641  auto pobjtmp = std::addressof(robjtmp);
3642  if (seen.emplace(pobjtmp).second) {
3643  // Not seen yet, return this element.
3644  pobj = pobjtmp;
3645  }
3646  }
3647  return pobj;
3648  }
3649 
3650  public:
3651  union_info(Seq1&& seq1, Seq2&& seq2, Pred&& pred)
3652  : seq1_(std::forward<Seq1>(seq1)),
3653  iend1_(std::end(seq1_)),
3654  seq2_(std::forward<Seq2>(seq2)),
3655  iend2_(std::end(seq2_)),
3656  pred_(std::forward<Pred>(pred)) { }
3657 
3658  // Cannot copy/move, stored in a shared_ptr
3659  union_info(const union_info&) = delete;
3660  union_info& operator=(const union_info&) = delete;
3661 
3662  first_iterator_type first_begin() {
3663  return std::begin(seq1_);
3664  }
3665  second_iterator_type second_begin() {
3666  return std::begin(seq2_);
3667  }
3668  seen_elements_set init_seen_elements() {
3669  return seen_elements_set(deref_cmp<proxy_cmp<Pred>>(proxy_cmp<Pred>(pred_)));
3670  }
3671 
3672  // Returns next distinct element in either sequence or nullptr when done
3673  auto get_next(first_iterator_type& icur1, second_iterator_type& icur2, seen_elements_set& seen) -> enum_ptr_type {
3674  // First look for an element in first sequence
3675  enum_ptr_type pobj = get_next_in_seq(icur1, iend1_, seen);
3676 
3677  // If we did not find an element in first sequence, try in second sequence
3678  if (pobj == nullptr) {
3679  pobj = get_next_in_seq(icur2, iend2_, seen);
3680  }
3681 
3682  return pobj;
3683  }
3684  };
3685  using union_info_sp = std::shared_ptr<union_info>;
3686 
3687  union_info_sp spinfo_; // Shared info
3688  first_iterator_type icur1_; // Iterator pointing at current element in first sequence
3689  second_iterator_type icur2_; // Iterator pointing at current element in second sequence
3690  seen_elements_set seen_; // Set of seen elements
3691 
3692  public:
3693  next_impl(Seq1&& seq1, Seq2&& seq2, Pred&& pred)
3694  : spinfo_(std::make_shared<union_info>(std::forward<Seq1>(seq1),
3695  std::forward<Seq2>(seq2),
3696  std::forward<Pred>(pred))),
3697  icur1_(spinfo_->first_begin()),
3698  icur2_(spinfo_->second_begin()),
3699  seen_(spinfo_->init_seen_elements()) { }
3700 
3701  auto operator()() -> decltype(spinfo_->get_next(icur1_, icur2_, seen_)) {
3702  return spinfo_->get_next(icur1_, icur2_, seen_);
3703  }
3704  };
3705 
3706 private:
3707  Seq2 seq2_; // Second sequence to union.
3708  Pred pred_; // Predicate used to compare elements
3709 
3710 public:
3711  explicit union_impl(Seq2&& seq2, Pred&& pred)
3712  : seq2_(std::forward<Seq2>(seq2)),
3713  pred_(std::forward<Pred>(pred)) { }
3714 
3715  // Movable but not copyable
3716  union_impl(const union_impl&) = delete;
3717  union_impl(union_impl&&) = default;
3718  union_impl& operator=(const union_impl&) = delete;
3719  union_impl& operator=(union_impl&&) = default;
3720 
3721  template<typename Seq1>
3722  auto operator()(Seq1&& seq1)
3723  -> enumerable<typename next_impl<Seq1>::enum_type>
3724  {
3725  return next_impl<Seq1>(std::forward<Seq1>(seq1),
3726  std::forward<Seq2>(seq2_),
3727  std::forward<Pred>(pred_));
3728  }
3729 };
3730 
3731 /**
3732  * @internal
3733  * @brief <tt>coveo::linq::where()</tt> et al implementation.
3734  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3735  *
3736  * Implementation of the <tt>coveo::linq::where()</tt> and
3737  * <tt>coveo::linq::where_with_index()</tt> LINQ operators.
3738  *
3739  * @tparam Pred Predicate used to filter elements.
3740  * @see coveo::linq::where()
3741  * @see coveo::linq::where_with_index()
3742  */
3743 template<typename Pred>
3744 class where_impl
3745 {
3746 public:
3747  // Implementation of next delegate for where/where_with_index operators.
3748  template<typename Seq>
3749  class next_impl
3750  {
3751  private:
3752  // Iterator for the sequence.
3753  using iterator_type = typename seq_traits<Seq>::iterator_type;
3754 
3755  // Bean storing info shared among delegates.
3756  struct where_info {
3757  Seq seq_; // Sequence being iterated.
3758  iterator_type iend_; // Iterator pointing at end of seq_
3759  Pred pred_; // Predicate to satisfy
3760 
3761  where_info(Seq&& seq, Pred&& pred)
3762  : seq_(std::forward<Seq>(seq)),
3763  iend_(std::end(seq_)),
3764  pred_(std::forward<Pred>(pred)) { }
3765 
3766  // Cannot copy/move, stored in a shared_ptr
3767  where_info(const where_info&) = delete;
3768  where_info& operator=(const where_info&) = delete;
3769  };
3770  using where_info_sp = std::shared_ptr<where_info>;
3771 
3772  where_info_sp spinfo_; // Shared info containing sequence and predicate.
3773  iterator_type icur_; // Pointer at current element.
3774  std::size_t idx_; // Index of current element.
3775 
3776  public:
3777  next_impl(Seq&& seq, Pred&& pred)
3778  : spinfo_(std::make_shared<where_info>(std::forward<Seq>(seq),
3779  std::forward<Pred>(pred))),
3780  icur_(std::begin(spinfo_->seq_)), idx_(0) { }
3781 
3782  auto operator()() -> typename seq_traits<Seq>::pointer {
3783  typename seq_traits<Seq>::pointer pobj = nullptr;
3784  for (; pobj == nullptr && icur_ != spinfo_->iend_; ++icur_, ++idx_) {
3785  typename seq_traits<Seq>::reference robjtmp = *icur_;
3786  auto pobjtmp = std::addressof(robjtmp);
3787  if (spinfo_->pred_(*pobjtmp, idx_)) {
3788  // This element satistifies the predicate, return it.
3789  pobj = pobjtmp;
3790  }
3791  }
3792  return pobj;
3793  }
3794  };
3795 
3796 private:
3797  Pred pred_; // Predicate to satisfy.
3798 
3799 public:
3800  explicit where_impl(Pred&& pred)
3801  : pred_(std::forward<Pred>(pred)) { }
3802 
3803  // Movable but not copyable
3804  where_impl(const where_impl&) = delete;
3805  where_impl(where_impl&&) = default;
3806  where_impl& operator=(const where_impl&) = delete;
3807  where_impl& operator=(where_impl&&) = default;
3808 
3809  template<typename Seq>
3810  auto operator()(Seq&& seq)
3811  -> enumerable<typename seq_traits<Seq>::value_type>
3812  {
3813  return next_impl<Seq>(std::forward<Seq>(seq), std::forward<Pred>(pred_));
3814  }
3815 };
3816 
3817 /**
3818  * @internal
3819  * @brief <tt>coveo::linq::zip()</tt> implementation.
3820  * @headerfile linq_detail.h <coveo/linq/detail/linq_detail.h>
3821  *
3822  * Implementation of the <tt>coveo::linq::zip()</tt> LINQ operator.
3823  *
3824  * @tparam Seq2 Second sequence to zip together. The first sequence will
3825  * have been provided by the call to <tt>coveo::linq::from()</tt>.
3826  * @tparam ResultSelector Selector used to "zip" two sequence elements.
3827  * @see coveo::linq::zip()
3828  */
3829 template<typename Seq2, typename ResultSelector>
3830 class zip_impl
3831 {
3832 private:
3833  // Implementation of next delegate for this operator.
3834  template<typename Seq1, typename CU, typename RU>
3835  class next_impl
3836  {
3837  private:
3838  // Iterator types for the sequences.
3839  using first_iterator_type = typename seq_traits<Seq1>::iterator_type;
3840  using second_iterator_type = typename seq_traits<Seq2>::iterator_type;
3841 
3842  // Containers storing zipped elements.
3843  using zipped_v = std::vector<RU>;
3844  using zipped_l = std::forward_list<RU>;
3845  using zipped_l_iterator = typename zipped_l::iterator;
3846 
3847  // Bean storing info shared among delegates.
3848  struct zip_info {
3849  Seq1 seq1_; // First sequence to zip.
3850  first_iterator_type icur1_; // Iterator pointing at current element of seq1_.
3851  first_iterator_type iend1_; // Iterator pointing at end of seq1_.
3852  Seq2 seq2_; // Second sequence to zip.
3853  second_iterator_type icur2_; // Iterator pointing at current element of seq2_.
3854  second_iterator_type iend2_; // Iterator pointing at end of seq2_.
3855  ResultSelector result_sel_; // Selector producing the results.
3856  zipped_v vzipped_; // Vector of zipped elements.
3857  zipped_l lzipped_; // List of zipped elements.
3858  zipped_l_iterator llast_; // Iterator pointing to last element in lzipped_ (before end()).
3859  bool use_vector_; // Whether we use lzipped_ (false) or vzipped_ (true).
3860 
3861  zip_info(Seq1&& seq1, Seq2&& seq2, ResultSelector&& result_sel,
3862  const typename enumerable<CU>::size_delegate& siz)
3863  : seq1_(std::forward<Seq1>(seq1)),
3864  icur1_(std::begin(seq1_)),
3865  iend1_(std::end(seq1_)),
3866  seq2_(std::forward<Seq2>(seq2)),
3867  icur2_(std::begin(seq2_)),
3868  iend2_(std::end(seq2_)),
3869  result_sel_(std::forward<ResultSelector>(result_sel)),
3870  vzipped_(),
3871  lzipped_(),
3872  llast_(lzipped_.before_begin()),
3873  use_vector_(siz != nullptr)
3874  {
3875  if (siz != nullptr) {
3876  vzipped_.reserve(siz());
3877  }
3878  }
3879 
3880  // Cannot copy/move, stored in a shared_ptr
3881  zip_info(const zip_info&) = delete;
3882  zip_info& operator=(const zip_info&) = delete;
3883 
3884  auto get_next_in_vector(std::size_t& vncur) -> CU* {
3885  while (vzipped_.size() <= vncur && icur1_ != iend1_ && icur2_ != iend2_) {
3886  vzipped_.emplace_back(result_sel_(*icur1_, *icur2_));
3887  ++icur1_;
3888  ++icur2_;
3889  }
3890  return vzipped_.size() > vncur ? std::addressof(vzipped_[vncur++])
3891  : nullptr;
3892  }
3893 
3894  auto get_next_in_list(zipped_l_iterator& licur) -> CU* {
3895  while (licur == llast_ && icur1_ != iend1_ && icur2_ != iend2_) {
3896  llast_ = lzipped_.emplace_after(llast_, result_sel_(*icur1_, *icur2_));
3897  ++icur1_;
3898  ++icur2_;
3899  }
3900  return licur != llast_ ? std::addressof(*++licur)
3901  : nullptr;
3902  }
3903 
3904  auto get_next(std::size_t& vncur, zipped_l_iterator& licur) -> CU* {
3905  return use_vector_ ? get_next_in_vector(vncur)
3906  : get_next_in_list(licur);
3907  }
3908  };
3909  using zip_info_sp = std::shared_ptr<zip_info>;
3910 
3911  zip_info_sp spinfo_; // Bean containing shared info.
3912  std::size_t vncur_; // Index of current element (if in vector).
3913  zipped_l_iterator licur_; // Iterator pointing at current element (if in list).
3914 
3915  public:
3916  next_impl(Seq1&& seq1, Seq2&& seq2, ResultSelector&& result_sel,
3917  const typename enumerable<CU>::size_delegate& siz)
3918  : spinfo_(std::make_shared<zip_info>(std::forward<Seq1>(seq1),
3919  std::forward<Seq2>(seq2),
3920  std::forward<ResultSelector>(result_sel),
3921  siz)),
3922  vncur_(0),
3923  licur_(spinfo_->lzipped_.before_begin()) { }
3924 
3925  auto operator()() -> CU* {
3926  return spinfo_->get_next(vncur_, licur_);
3927  }
3928  };
3929 
3930 private:
3931  Seq2 seq2_; // Second sequence to zip.
3932  ResultSelector result_sel_; // Selector producing the results.
3933 
3934 public:
3935  zip_impl(Seq2&& seq2, ResultSelector&& result_sel)
3936  : seq2_(std::forward<Seq2>(seq2)),
3937  result_sel_(std::forward<ResultSelector>(result_sel)) { }
3938 
3939  // Movable but not copyable
3940  zip_impl(const zip_impl&) = delete;
3941  zip_impl(zip_impl&&) = default;
3942  zip_impl& operator=(const zip_impl&) = delete;
3943  zip_impl& operator=(zip_impl&&) = default;
3944 
3945  template<typename Seq1,
3946  typename _SelectorRes = decltype(std::declval<ResultSelector>()(std::declval<typename seq_traits<Seq1>::reference>(),
3947  std::declval<typename seq_traits<Seq2>::reference>())),
3948  typename _CU = typename seq_element_traits<_SelectorRes>::const_value_type,
3949  typename _RU = typename seq_element_traits<_SelectorRes>::raw_value_type>
3950  auto operator()(Seq1&& seq1) -> enumerable<_CU> {
3951  auto siz1 = try_get_size_delegate(seq1);
3952  auto siz2 = try_get_size_delegate(seq2_);
3953  typename enumerable<_CU>::size_delegate siz;
3954  if (siz1 != nullptr && siz2 != nullptr) {
3955  const std::size_t min_size = std::min(siz1(), siz2());
3956  siz = [min_size]() -> std::size_t { return min_size; };
3957  }
3958  return enumerable<_CU>(next_impl<Seq1, _CU, _RU>(std::forward<Seq1>(seq1),
3959  std::forward<Seq2>(seq2_),
3960  std::forward<ResultSelector>(result_sel_),
3961  siz),
3962  siz);
3963  }
3964 };
3965 
3966 } // detail
3967 } // linq
3968 } // coveo
3969 
3970 #endif // COVEO_LINQ_DETAIL_H
Traits class for a sequence.
Definition: sequence_util.h:113
Type-erased sequence wrapper.
Definition: enumerable.h:62
Traits class for elements in a sequence.
Definition: sequence_util.h:40