coveo::linq
Implementation of .NET-like LINQ operators in C++
enumerable.h
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief C++ implementation of .NET's IEnumerable-like data structure.
4  *
5  * This file contains the definition of <tt>coveo::enumerable</tt>, which
6  * is a wrapper for a sequence similar to .NET's <tt>IEnumerable&lt;T&gt;</tt>.
7  * Also includes helper methods and functions to create <tt>enumerable</tt>s
8  * from single values, containers, etc.
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_ENUMERABLE_H
15 #define COVEO_ENUMERABLE_H
16 
17 #include "coveo/seq/sequence_util.h"
18 #include <coveo/seq/detail/enumerable_detail.h>
19 
20 #include <cstddef>
21 #include <iterator>
22 #include <functional>
23 #include <memory>
24 #include <type_traits>
25 
26 namespace coveo {
27 
28 /**
29  * @brief Type-erased sequence wrapper.
30  * @headerfile enumerable.h <coveo/seq/enumerable.h>
31  *
32  * Inspired by .NET's <tt>IEnumerable&lt;T&gt;</tt>, <tt>coveo::enumerable</tt>
33  * is a type-erased wrapper for a multipass, forward-only sequence of elements.
34  * It is possible to iterate over the elements using <tt>begin()</tt> / <tt>end()</tt>
35  * (or <tt>cbegin()</tt> / <tt>cend()</tt>, which is equivalent since this class is
36  * immutable).
37  *
38  * In order to fetch the elements to return, this class uses a <em>next delegate</em> -
39  * a function that returns a pointer to the next element every time it is called,
40  * finally returning @c nullptr when the enumeration is over. The next delegate
41  * is provided at construction time and cannot change.
42  *
43  * Optionally, it is also possible to specify a <em>size delegeate</em> for the
44  * @c enumerable at construction time. If provided, it will be used to fetch the
45  * number of elements in the sequence when <tt>size()</tt> is called; otherwise,
46  * a slower algorithm is used (iterating over the entire sequence using
47  * <tt>std::distance()</tt>). It is possible to determine if the @c enumerable
48  * has a fast size delegate by using <tt>has_fast_size()</tt>.
49  *
50  * While this class is immutable, the elements it returns are not necessarily so.
51  * In order to wrap a sequence of @c const elements, @c const must also be specified
52  * in this class' template argument:
53  *
54  * @code
55  * coveo::enumerable<const int> e1; // Iterates over const integers
56  * coveo::enumerable<int> e2; // Iterates over non-const integers
57  * @endcode
58  *
59  * @tparam T Type of elements stored in the sequence.
60  */
61 template<typename T>
63 {
64 /// @cond
65 
66  // Allows compatible enumerables to be friend with each other
67  template<typename> friend class enumerable;
68 
69 /// @endcond
70 
71 public:
72  /**
73  * @brief Type of element in the sequence.
74  *
75  * Type of element stored in the sequence.
76  */
77  using value_type = typename seq_element_traits<T>::value_type;
78 
79  /**
80  * @brief Raw type of element in the sequence.
81  *
82  * Same as <tt>coveo::enumerable::value_type</tt>, but "raw", e.g. without @c const or @c volatile.
83  */
84  using raw_value_type = typename seq_element_traits<T>::raw_value_type;
85 
86  /**
87  * @brief Pointer to a sequence element.
88  *
89  * Pointer to an element in the sequence.
90  * Corresponds to <tt>coveo::enumerable::value_type*</tt>.
91  * This is the type of pointer returned by the <tt>coveo::enumerable::next_delegate</tt>.
92  */
93  using pointer = typename seq_element_traits<T>::pointer;
94 
95  /**
96  * @brief Reference to a sequence element.
97  *
98  * Reference to an element in the sequence.
99  * Corresponds to <tt>coveo::enumerable::value_type&</tt>.
100  * This is the type of reference returned by the <tt>coveo::enumerable::iterator</tt>s.
101  */
102  using reference = typename seq_element_traits<T>::reference;
103 
104  /**
105  * @brief Delegate to fetch next element.
106  *
107  * Delegate that will be called by the @c enumerable to fetch
108  * the next element in the sequence when needed. The delegate
109  * must return a <tt>coveo::enumerable::pointer</tt> to the next
110  * element if there is one, or @c nullptr when done.
111  */
112  using next_delegate = std::function<pointer()>;
113 
114  /**
115  * @brief Delegate to fetch sequence size.
116  *
117  * Delegate that will be called by the @c enumerable to fetch
118  * the number of elements in the sequence when <tt>size()</tt>
119  * is called.
120  */
121  using size_delegate = std::function<std::size_t()>;
122 
123  // Forward declaration of iterator class.
124  class iterator;
125 
126  /**
127  * @brief @c iterator alias.
128  *
129  * Alias for <tt>coveo::enumerable::iterator</tt>. Provided because even though
130  * <tt>begin()</tt> and <tt>end()</tt> are already @c const, some generic code
131  * might want to use @c const_iterator.
132  */
133  using const_iterator = iterator;
134 
135 private:
136  next_delegate zero_; // Next delegate which we will clone to iterate sequence.
137  size_delegate size_; // Optional size delegate.
138 
139 public:
140  /**
141  * @brief Default constructor.
142  *
143  * Default constructor. Wraps an empty sequence.
144  *
145  * Using this constructor is equivalent to calling <tt>empty()</tt>.
146  *
147  * @see empty()
148  */
150  : zero_([]() -> pointer { return nullptr; }),
151  size_([]() -> std::size_t { return 0; }) { }
152 
153  /**
154  * @brief Constructor with delegates.
155  *
156  * Constructor that accepts a <tt>coveo::enumerable::next_delegate</tt>
157  * as well as an optional <tt>coveo::enumerable::size_delegate</tt>.
158  * The <em>next delegate</em> is used to fetch the elements to return
159  * during iteration. The <em>size delegate</em>, if provided, will
160  * be called to know the <tt>size()</tt> of the sequence.
161  *
162  * @param next Function object to use as next delegate.
163  * @param siz Optional function object to use as size delegate. Defaults to @c nullptr.
164  * @see coveo::enumerable::next_delegate
165  * @see coveo::enumerable::size_delegate
166  * @see size()
167  * @see has_fast_size()
168  */
169  template<typename F,
170  typename _S = std::nullptr_t,
171  typename = typename std::enable_if<!is_enumerable<typename std::decay<F>::type>::value &&
172  (!detail::has_begin<typename std::decay<F>::type>::value ||
173  !detail::has_end<typename std::decay<F>::type>::value), void>::type>
174  enumerable(F&& next, _S&& siz = nullptr)
175  : zero_(std::forward<F>(next)), size_(std::forward<_S>(siz)) { }
176 
177  /**
178  * @brief Constructor with container.
179  *
180  * Constructor that wraps a container. The container must have the
181  * following methods to be accepted by this constructor:
182  *
183  * - @c begin (or a specialization of <tt>std::begin()</tt>)
184  * - @c end (or a specialization of <tt>std::end()</tt>)
185  *
186  * The container will be wrapped in the enumerable, either by
187  * keeping a reference to it or by storing it internally, depending
188  * on how the container is passed to the method (if it is <tt>move</tt>d,
189  * it will be stored internally).
190  *
191  * Using this constructor is equivalent to calling <tt>for_container()</tt>.
192  * It is provided implicitely so that it is possible to call a function
193  * declared as accepting a <tt>coveo::enumerable</tt> with a container
194  * instance directly.
195  *
196  * @param cnt Container to wrap.
197  * @see for_container()
198  */
199  template<typename C,
200  typename = typename std::enable_if<!is_enumerable<typename std::decay<C>::type>::value &&
201  detail::has_begin<typename std::decay<C>::type>::value &&
202  detail::has_end<typename std::decay<C>::type>::value, void>::type>
203  enumerable(C&& cnt)
204  : zero_(), size_() { *this = for_container(std::forward<C>(cnt)); }
205 
206  /**
207  * @brief Constructor for non-<tt>const</tt> to @c const conversion.
208  *
209  * Constructor that creates an enumerable over @c const elements from
210  * an enumerable over non-<tt>const</tt> elements of the same type.
211  * Allows implicit non-<tt>const</tt> to @c const conversion.
212  *
213  * @param e <tt>coveo::enumerable</tt> to convert.
214  */
215  template<typename U,
216  typename = typename std::enable_if<!std::is_const<U>::value &&
217  std::is_same<T, typename std::add_const<U>::type>::value, void>::type>
219  : zero_(std::move(e.zero_)), size_(std::move(e.size_)) { }
220 
221  /**
222  * @brief Assignment operator for non-<tt>const</tt> to @c const conversion.
223  *
224  * Assignment operator that allows an enumerable over non-<tt>const</tt>
225  * elements to be assigned to an enumerable over @c const elements of
226  * the same type. Allows non-<tt>const</tt> to @c const conversion.
227  *
228  * @param e <tt>coveo::enumerable</tt> to convert.
229  * @return Reference to @c this enumerable.
230  */
231  template<typename U,
232  typename = typename std::enable_if<!std::is_const<U>::value &&
233  std::is_same<T, typename std::add_const<U>::type>::value, void>::type>
235  zero_ = std::move(e.zero_);
236  size_ = std::move(e.size_);
237  return *this;
238  }
239 
240  /**
241  * @brief Iterator to beginning of sequence.
242  *
243  * Returns a <tt>coveo::enumerable::iterator</tt> pointing at
244  * the beginning of the sequence. Together with <tt>end()</tt>,
245  * it can be used to enumerate the elements in the sequence.
246  *
247  * The iterator allows the elements to be modified if the
248  * enumerable's type @c T is not @c const.
249  *
250  * @return @c iterator to beginning of sequence.
251  * @see end()
252  */
253  iterator begin() const {
254  return iterator(*this, false);
255  }
256 
257  /**
258  * @brief Alias for <tt>begin()</tt>.
259  *
260  * Since this class is immutable, calling this is
261  * equivalent to calling <tt>begin()</tt>.
262  *
263  * @return @c iterator to beginning of sequence.
264  * @see begin()
265  * @see cend()
266  */
267  iterator cbegin() const {
268  return begin();
269  }
270 
271  /**
272  * @brief Iterator to end of sequence.
273  *
274  * Returns a <tt>coveo::enumerable::iterator</tt> pointing at
275  * the end of the sequence. Together with <tt>begin()</tt>,
276  * it can be used to enumerable the elements in the sequence.
277  *
278  * @return @c iterator to end of sequence.
279  * @see begin()
280  */
281  iterator end() const {
282  return iterator(*this, true);
283  }
284 
285  /**
286  * @brief Alias for <tt>end()</tt>.
287  *
288  * Since this class is immutable, calling this is
289  * equivalent to calling <tt>end()</tt>.
290  *
291  * @return @c iterator to end of sequence.
292  * @see end()
293  * @see cbegin()
294  */
295  iterator cend() const {
296  return end();
297  }
298 
299  /**
300  * @brief Determines if <tt>size()</tt> is fast.
301  *
302  * Method that can be used to know if this @c enumerable has a
303  * <tt>coveo::enumerable::size_delegate</tt>. If so, calling
304  * <tt>size()</tt> should be reasonably fast; otherwise,
305  * <tt>size()</tt> will have to iterate over the entire sequence
306  * in order to return a result.
307  *
308  * @return @c true if <tt>size()</tt> should be reasonably fast.
309  * @see size()
310  */
311  bool has_fast_size() const {
312  // If we have a delegate, size() should be reasonably fast
313  return size_ != nullptr;
314  }
315 
316  /**
317  * @brief Size of sequence.
318  *
319  * Returns the number of elements in the sequence. If this @c enumerable
320  * has a <tt>coveo::enumerable::size_delegate</tt>, it will be used to
321  * fetch the information; otherwise, a more lenghty process is used
322  * (e.g., using <tt>std::distance()</tt>, which forces the iteration
323  * over the entire sequence).
324  *
325  * @return Number of elements in the sequence.
326  * @see has_fast_size()
327  */
328  std::size_t size() const {
329  // If we have a delegate, use it, otherwise use distance.
330  return size_ != nullptr ? size_()
331  : static_cast<std::size_t>(std::distance(begin(), end()));
332  }
333 
334  /**
335  * @brief Non-<tt>const</tt> to @c const explicit conversion.
336  *
337  * Returns a copy of this @c enumerable, but iterating over
338  * @c const elements. Can be used to explicitely perform a
339  * non-<tt>const</tt> to @c const conversion.
340  *
341  * @return @c enumerable over @c const elements.
342  */
343  auto as_const() const -> enumerable<typename std::add_const<T>::type> {
344  return enumerable<typename std::add_const<T>::type>(*this);
345  }
346 
347 public:
348  /**
349  * @brief Iterator for elements in the sequence.
350  *
351  * Iterator for elements in a <tt>coveo::enumerable</tt>'s sequence.
352  * Uses the <tt>enumerable</tt>'s <em>next delegate</em> to fetch
353  * references to the elements during iteration.
354  *
355  * Elements are always late-initialized, e.g. they are not fetched
356  * from the next delegate until they are accessed.
357  *
358  * @see coveo::enumerable::begin()
359  * @see coveo::enumerable::end()
360  */
361  class iterator
362  {
363  public:
364  /**
365  * @brief Iterator category.
366  *
367  * Standard iterator typedef for iterator category. Because @c enumerable is a forward-only
368  * sequence, this corresponds to <tt>std::forward_iterator_tag</tt> to identify a
369  * <a href="https://en.cppreference.com/w/cpp/named_req/ForwardIterator">ForwardIterator</a>.
370  */
371  using iterator_category = std::forward_iterator_tag;
372 
373  /**
374  * @brief Type of elements returned by iterator.
375  *
376  * Type of the elements returned by this iterator.
377  *
378  * @see coveo::enumerable::value_type
379  */
380  using value_type = typename enumerable<T>::value_type;
381 
382  /**
383  * @brief Raw type of elements returned by iterator.
384  *
385  * Type of the elements returned by this iterator, but "raw",
386  * e.g. without @c const or @c volatile.
387  *
388  * @see coveo::enumerable::raw_value_type
389  */
390  using raw_value_type = typename enumerable<T>::raw_value_type;
391 
392  /**
393  * @brief Difference type.
394  *
395  * Standard iterator typedef for difference between iterators.
396  * Corresponds to <tt>std::ptfdiff_t</tt>.
397  */
398  using difference_type = std::ptrdiff_t;
399 
400  /**
401  * @brief Pointer to elements returned by iterator.
402  *
403  * Pointer to the type of elements returned by this iterator.
404  *
405  * @see coveo::enumerable::pointer
406  */
407  using pointer = typename enumerable<T>::pointer;
408 
409  /**
410  * @brief Reference to elements returned by iterator.
411  *
412  * Reference to the type of elements returned by this iterator.
413  * This is the type of reference returned by <tt>operator*()</tt>.
414  *
415  * @see coveo::enumerable::reference.
416  */
417  using reference = typename enumerable<T>::reference;
418 
419  private:
420  const enumerable<T>* pparent_ = nullptr; // Parent enumerable or nullptr if unbound
421  mutable next_delegate next_; // Delegate used to fetch elements
422  mutable pointer pcur_ = nullptr; // Pointer to current element or nullptr when at end of sequence
423  mutable bool has_cur_ = true; // Whether pcur_ has been loaded for current element
424  size_t pos_ = 0; // Position in sequence, to compare iterators
425 
426  // Fetches value of pcur_, late-loading it if needed
427  pointer get_pcur() const {
428  if (!has_cur_) {
429  pcur_ = next_();
430  has_cur_ = true;
431  }
432  return pcur_;
433  }
434 
435  public:
436  /**
437  * @brief Default constructor.
438  *
439  * Default constructor. Creates an invalid iterator that
440  * cannot be dereferenced.
441  */
442  iterator() = default;
443 
444  /**
445  * @brief Constructor from @c enumerable.
446  *
447  * Constructor that is used by <tt>coveo::enumerable</tt>
448  * to create its iterators.
449  *
450  * @param parent Parent @c enumerable to iterate.
451  * @param is_end Whether this iterator should point to the
452  * beginning of the sequence (@c false) or to
453  * the end of the sequence (@c true).
454  */
455  iterator(const enumerable<T>& parent, bool is_end)
457 
458  /**
459  * @brief Copy constructor.
460  *
461  * Copy constructor. Creates a copy of another iterator that
462  * will point to the same point in the enumeration.
463  *
464  * @param obj Iterator to copy.
465  */
466  iterator(const iterator& obj) = default;
467 
468  /**
469  * @brief Move constructor.
470  *
471  * Move constructor. Creates an iterator by moving the internals
472  * from another iterator. After this method returns, @c obj is
473  * invalid and cannot be used.
474  *
475  * @param obj Iterator to move.
476  */
480  {
481  obj.pparent_ = nullptr;
482  obj.pcur_ = nullptr;
483  obj.has_cur_ = true;
484  obj.pos_ = 0;
485  }
486 
487  /**
488  * @brief Assignment operator.
489  *
490  * Assignment operator. Copies another iterator, now pointing
491  * to the same point in the enumeration.
492  *
493  * @param obj Iterator to copy.
494  * @return Reference to @c this iterator.
495  */
496  iterator& operator=(const iterator& obj) = default;
497 
498  /**
499  * @brief Move assignment operator.
500  *
501  * Move assignment operator. Moves the internals of another
502  * iterator to this one. After this method returns, @c obj
503  * is invalid and cannot be used.
504  *
505  * @param obj Iterator to move.
506  * @return Reference to @c this iterator.
507  */
510  next_ = std::move(obj.next_);
511  pcur_ = obj.pcur_;
513  pos_ = obj.pos_;
514 
515  obj.pparent_ = nullptr;
516  obj.pcur_ = nullptr;
517  obj.has_cur_ = true;
518  obj.pos_ = 0;
519 
520  return *this;
521  }
522 
523  /**
524  * @brief Element access.
525  *
526  * Returns a reference to the current element in the enumeration,
527  * fetching it from the next delegate on the first call.
528  *
529  * @return Reference to current element.
530  */
531  reference operator*() const {
532  return *get_pcur();
533  }
534 
535  /**
536  * @brief Element pointer access.
537  *
538  * Returns a pointer to the current element in the enumeration,
539  * fetching it from the next delegate on the first call. Can be
540  * used to call methods or access members of the element.
541  *
542  * @return Pointer to current element.
543  */
544  pointer operator->() const {
545  return get_pcur();
546  }
547 
548  /**
549  * @brief Moves to next element (pre-increment).
550  *
551  * Moves forward to the next element in the enumeration.
552  * Cannot be used if this iterator points to the end of
553  * the enumeration.
554  *
555  * @return Reference to @c this iterator AFTER the move.
556  */
558  if (has_cur_) {
559  pcur_ = nullptr;
560  has_cur_ = false;
561  } else {
562  next_();
563  }
564  ++pos_;
565  return *this;
566  }
567 
568  /**
569  * @brief Moves to next element (post-increment).
570  *
571  * Moves forward to the next element in the enumeration.
572  * Cannot be used if this iterator points to the end of
573  * the enumeration.
574  *
575  * @return Iterator BEFORE the move.
576  */
578  iterator it(*this);
579  ++*this;
580  return it;
581  }
582 
583  /**
584  * @brief Compares iterator for equality.
585  *
586  * Determines if two iterators point to the same point in
587  * the same sequence.
588  *
589  * @param left First iterator to compare.
590  * @param right Second iterator to compare.
591  * @return @c true if @c left and @c right point to the same
592  * point in the same sequence.
593  */
594  friend bool operator==(const iterator& left, const iterator& right) {
595  return left.pparent_ == right.pparent_ &&
596  (left.get_pcur() == nullptr) == (right.get_pcur() == nullptr) &&
597  (left.get_pcur() == nullptr || left.pos_ == right.pos_);
598  }
599 
600  /**
601  * @brief Compares iterator for inequality.
602  *
603  * Determines if two iterators point to a different point
604  * in perhaps different sequences.
605  *
606  * @param left First iterator to compare.
607  * @param right Second iterator to compare.
608  * @return @c true if @c left does not point to the same point
609  * in the sequence as @c right.
610  * @see operator==()
611  */
612  friend bool operator!=(const iterator& left, const iterator& right) {
613  return !(left == right);
614  }
615  };
616 
617 public:
618  // Helper static methods
619 
620  /**
621  * @brief Returns @c enumerable over empty sequence.
622  *
623  * Static method that returns a <tt>coveo::enumerable</tt> over an
624  * empty sequence. Equivalent to using the default constructor.
625  *
626  * @return @c enumerable over empty sequence.
627  */
628  static enumerable<T> empty() {
629  return enumerable<T>();
630  }
631 
632  /**
633  * @brief Returns @c enumerable over sequence of one element (stored internally).
634  *
635  * Static method that returns a <tt>coveo::enumerable</tt> over
636  * a sequence of one element. The @c enumerable will store the
637  * element internally, moving it if possible.
638  *
639  * In order to auto-discover the enumerable's type, use
640  * <tt>coveo::enumerate_one()</tt>.
641  *
642  * @param obj Object to store as the sequence's only element.
643  * @return @c enumerable over sequence of one element.
644  * @see coveo::enumerate_one()
645  */
646  template<typename U>
647  static enumerable<T> for_one(U&& obj) {
649  bool available = true;
650  return enumerable<T>([spobj, available]() mutable {
651  pointer pobj = nullptr;
652  if (available) {
653  pobj = spobj.get();
654  available = false;
655  }
656  return pobj;
657  }, []() -> std::size_t {
658  return 1;
659  });
660  }
661 
662  /**
663  * @brief Returns @c enumerable over sequence of one element (stored externally).
664  *
665  * Static method that returns a <tt>coveo::enumerable</tt> over
666  * a sequence of one element. The @c enumerable will only store
667  * a reference to the element.
668  *
669  * In order to auto-discover the enumerable's type, use
670  * <tt>coveo::enumerate_one_ref()</tt>.
671  *
672  * @param obj Object to use as the sequence's only element.
673  * @return @c enumerable over sequence of one element.
674  * @see coveo::enumerate_one_ref()
675  */
676  static enumerable<T> for_one_ref(reference obj) {
677  bool available = true;
678  return enumerable<T>([&obj, available]() mutable {
679  pointer pobj = nullptr;
680  if (available) {
681  pobj = std::addressof(obj);
682  available = false;
683  }
684  return pobj;
685  }, []() -> std::size_t {
686  return 1;
687  });
688  }
689 
690  /**
691  * @brief Returns @c enumerable over sequence bound by iterators.
692  *
693  * Static method that returns a <tt>coveo::enumerable</tt>
694  * over a sequence bound by two iterators.
695  *
696  * In order to auto-discover the enumerable's type, use
697  * <tt>coveo::enumerate_range()</tt>.
698  *
699  * @param ibeg Iterator pointing at beginning of range.
700  * @param iend Iterator pointing at end of range.
701  * @return @c enumerable over sequence bound by <tt>[ibeg, iend[</tt>.
702  * @see coveo::enumerate_range()
703  */
704  template<typename It>
705  static enumerable<T> for_range(It ibeg, It iend) {
706  auto it = std::move(ibeg);
707  return enumerable<T>([it, iend]() mutable {
708  pointer pobj = nullptr;
709  if (it != iend) {
710  reference robj = *it;
711  pobj = std::addressof(robj);
712  ++it;
713  }
714  return pobj;
716  }
717 
718  /**
719  * @brief Returns @c enumerable over container's sequence (stored externally).
720  *
721  * Static method that returns a <tt>coveo::enumerable</tt> over
722  * a sequence stored in a container. Only a reference to the
723  * container is kept by the @c enumerable.
724  *
725  * In order to auto-discover the enumerable's type, use
726  * <tt>coveo::enumerate_container()</tt>.
727  *
728  * @param cnt Container whose elements to wrap.
729  * @return @c enumerable over sequence of elements from @c cnt.
730  * @see coveo::enumerate_container()
731  */
732  template<typename C>
733  static enumerable<T> for_container(C& cnt) {
734  auto it = std::begin(cnt);
735  auto end = std::end(cnt);
736  return enumerable<T>([it, end]() mutable {
737  pointer pobj = nullptr;
738  if (it != end) {
739  reference robj = *it;
740  pobj = std::addressof(robj);
741  ++it;
742  }
743  return pobj;
745  }
746 
747  /**
748  * @brief Returns @c enumerable over container's sequence (stored internally).
749  *
750  * Static method that returns a <tt>coveo::enumerable</tt> over
751  * a sequence stored in a container. The container is moved to
752  * the @c enumerable and stored internally.
753  *
754  * In order to auto-discover the enumerable's type, use
755  * <tt>coveo::enumerate_container()</tt>.
756  *
757  * @param cnt Container to store in the enumerable.
758  * @return @c enumerable over sequence of elements from @c cnt.
759  * @see coveo::enumerate_container()
760  */
761  template<typename C,
762  typename = typename std::enable_if<!std::is_reference<C>::value, void>::type>
763  static enumerable<T> for_container(C&& cnt) {
764  auto spcnt = std::make_shared<C>(std::move(cnt));
765  auto it = std::begin(*spcnt);
766  auto end = std::end(*spcnt);
767  return enumerable<T>([spcnt, it, end]() mutable {
768  pointer pobj = nullptr;
769  if (it != end) {
770  reference robj = *it;
771  pobj = std::addressof(robj);
772  ++it;
773  }
774  return pobj;
776  }
777 
778  /**
779  * @brief Returns @c enumerable over array's sequence.
780  *
781  * Static method that returns a <tt>coveo::enumerable</tt> over
782  * a sequence stored in a dynamic array. Equivalent to using
783  * <tt>for_range()</tt> without using pointer arithmetic.
784  *
785  * In order to auto-discover the enumerable's type, use
786  * <tt>coveo::enumerate_array()</tt>.
787  *
788  * @param parr Pointer to beginning of array.
789  * @param siz Size of array.
790  * @return @c enumerable over sequence in array.
791  * @see coveo::enumerate_array()
792  */
793  static enumerable<T> for_array(pointer parr, size_t siz) {
794  return for_range(parr, parr + siz);
795  }
796 };
797 
798 // Helper functions corresponding to the helper static methods in enumerable.
799 
800 /**
801  * @brief Returns @c enumerable over sequence of one element (stored internally).
802  *
803  * Returns a <tt>coveo::enumerable</tt> over a sequence of one element.
804  * The @c enumerable will store the element internally, moving it if possible.
805  *
806  * The <tt>enumerable</tt>'s type is deduced from the type of the element.
807  *
808  * @param obj Object to store as the sequence's only element.
809  * @return @c enumerable over sequence of one element.
810  * @see coveo::enumerable::for_one()
811  */
812 template<typename U>
814  return enumerable<typename seq_element_traits<U>::const_value_type>::for_one(std::forward<U>(obj));
815 }
816 
817 /**
818  * @brief Returns @c enumerable over sequence of one element (stored externally).
819  *
820  * Returns a <tt>coveo::enumerable</tt> over a sequence of one element.
821  * The @c enumerable will only store a reference to the element.
822  *
823  * The <tt>enumerable</tt>'s type is deduced from the type of the element.
824  *
825  * @param obj Object to use as the sequence's only element.
826  * @return @c enumerable over sequence of one element.
827  * @see coveo::enumerable::for_one_ref()
828  */
829 template<typename T>
830 auto enumerate_one_ref(T& obj) -> enumerable<T> {
831  return enumerable<T>::for_one_ref(obj);
832 }
833 
834 /**
835  * @brief Returns @c enumerable over sequence bound by iterators.
836  *
837  * Returns a <tt>coveo::enumerable</tt> over a sequence bound by two iterators.
838  *
839  * The <tt>enumerable</tt>'s type is deduced from the type of element returned
840  * by the iterators.
841  *
842  * @param ibeg Iterator pointing at beginning of range.
843  * @param iend Iterator pointing at end of range.
844  * @return @c enumerable over sequence bound by <tt>[ibeg, iend[</tt>.
845  * @see coveo::enumerable::for_range()
846  */
847 template<typename It>
849  -> enumerable<typename seq_element_traits<decltype(*std::declval<It>())>::value_type>
850 {
851  return enumerable<typename seq_element_traits<decltype(*std::declval<It>())>::value_type>::for_range(
852  std::move(ibeg), std::move(iend));
853 }
854 
855 /**
856  * @brief Returns @c enumerable over container's sequence (stored externally).
857  *
858  * Returns a <tt>coveo::enumerable</tt> over a sequence stored
859  * in a container. Only a reference to the container is kept by
860  * the @c enumerable.
861  *
862  * The <tt>enumerable</tt>'s type is deduced from the type of
863  * elements stored in the container.
864  *
865  * @param cnt Container whose elements to wrap.
866  * @return @c enumerable over sequence of elements from @c cnt.
867  * @see coveo::enumerable::for_container()
868  */
869 template<typename C>
871  -> enumerable<typename seq_element_traits<decltype(*std::begin(std::declval<C>()))>::value_type>
872 {
873  return enumerable<typename seq_element_traits<decltype(*std::begin(std::declval<C>()))>::value_type>::for_container(
874  cnt);
875 }
876 
877 /**
878  * @brief Returns @c enumerable over container's sequence (stored internally).
879  *
880  * Returns a <tt>coveo::enumerable</tt> over a sequence stored
881  * in a container. The container is moved to the @c enumerable
882  * and stored internally.
883  *
884  * The <tt>enumerable</tt>'s type is deduced from the type of
885  * elements stored in the container.
886  *
887  * @param cnt Container to store in the enumerable.
888  * @return @c enumerable over sequence of elements from @c cnt.
889  * @see coveo::enumerable::for_container()
890  */
891 template<typename C,
892  typename = typename std::enable_if<!std::is_reference<C>::value, void>::type>
893 auto enumerate_container(C&& cnt)
894  -> enumerable<typename seq_element_traits<decltype(*std::begin(std::declval<C>()))>::const_value_type>
895 {
896  return enumerable<typename seq_element_traits<decltype(*std::begin(std::declval<C>()))>::const_value_type>::for_container(
897  std::move(cnt));
898 }
899 
900 /**
901  * @brief Returns @c enumerable over array's sequence.
902  *
903  * Returns a <tt>coveo::enumerable</tt> over a sequence stored in a
904  * dynamic array. Equivalent to using <tt>coveo::enumerate_range()</tt>
905  * without using pointer arithmetic.
906  *
907  * The <tt>enumerable</tt>'s type is deduced from the type of elements
908  * stored in the array.
909  *
910  * @param parr Pointer to beginning of array.
911  * @param siz Size of array.
912  * @return @c enumerable over sequence in array.
913  * @see coveo::enumerable::for_array()
914  */
915 template<typename T>
916 auto enumerate_array(T* parr, size_t siz) -> enumerable<T> {
917  return enumerable<T>::for_array(parr, siz);
918 }
919 
920 } // coveo
921 
922 #endif // COVEO_ENUMERABLE_H
pointer operator->() const
Element pointer access.
Definition: enumerable.h:544
friend bool operator==(const iterator &left, const iterator &right)
Compares iterator for equality.
Definition: enumerable.h:594
static enumerable< T > for_container(C &&cnt)
Returns enumerable over container's sequence (stored internally).
Definition: enumerable.h:763
static enumerable< T > for_container(C &cnt)
Returns enumerable over container's sequence (stored externally).
Definition: enumerable.h:733
enumerable(F &&next, _S &&siz=nullptr)
Constructor with delegates.
Definition: enumerable.h:174
enumerable(C &&cnt)
Constructor with container.
Definition: enumerable.h:203
iterator operator++(int)
Moves to next element (post-increment).
Definition: enumerable.h:577
auto enumerate_one_ref(T &obj) -> enumerable< T >
Returns enumerable over sequence of one element (stored externally).
Definition: enumerable.h:830
Iterator for elements in the sequence.
Definition: enumerable.h:361
iterator & operator=(iterator &&obj)
Move assignment operator.
Definition: enumerable.h:508
auto enumerate_container(C &&cnt) -> enumerable< typename seq_element_traits< decltype(*std::begin(std::declval< C >()))>::const_value_type >
Returns enumerable over container's sequence (stored internally).
Definition: enumerable.h:893
reference operator *() const
Element access.
Definition: enumerable.h:531
enumerable & operator=(enumerable< U > e)
Assignment operator for non-const to const conversion.
Definition: enumerable.h:234
static enumerable< T > empty()
Returns enumerable over empty sequence.
Definition: enumerable.h:628
iterator end() const
Iterator to end of sequence.
Definition: enumerable.h:281
auto enumerate_range(It ibeg, It iend) -> enumerable< typename seq_element_traits< decltype(*std::declval< It >())>::value_type >
Returns enumerable over sequence bound by iterators.
Definition: enumerable.h:848
auto as_const() const -> enumerable< typename std::add_const< T >::type >
Non-const to const explicit conversion.
Definition: enumerable.h:343
static enumerable< T > for_one(U &&obj)
Returns enumerable over sequence of one element (stored internally).
Definition: enumerable.h:647
iterator begin() const
Iterator to beginning of sequence.
Definition: enumerable.h:253
auto enumerate_container(C &cnt) -> enumerable< typename seq_element_traits< decltype(*std::begin(std::declval< C >()))>::value_type >
Returns enumerable over container's sequence (stored externally).
Definition: enumerable.h:870
static enumerable< T > for_array(pointer parr, size_t siz)
Returns enumerable over array's sequence.
Definition: enumerable.h:793
iterator cbegin() const
Alias for begin().
Definition: enumerable.h:267
Type-erased sequence wrapper.
Definition: enumerable.h:62
iterator(const enumerable< T > &parent, bool is_end)
Constructor from enumerable.
Definition: enumerable.h:455
iterator cend() const
Alias for end().
Definition: enumerable.h:295
enumerable()
Default constructor.
Definition: enumerable.h:149
static enumerable< T > for_range(It ibeg, It iend)
Returns enumerable over sequence bound by iterators.
Definition: enumerable.h:705
Traits class for elements in a sequence.
Definition: sequence_util.h:40
bool has_fast_size() const
Determines if size() is fast.
Definition: enumerable.h:311
iterator(iterator &&obj)
Move constructor.
Definition: enumerable.h:477
iterator & operator=(const iterator &obj)=default
Assignment operator.
friend bool operator!=(const iterator &left, const iterator &right)
Compares iterator for inequality.
Definition: enumerable.h:612
std::size_t size() const
Size of sequence.
Definition: enumerable.h:328
auto enumerate_one(U &&obj) -> enumerable< typename seq_element_traits< U >::const_value_type >
Returns enumerable over sequence of one element (stored internally).
Definition: enumerable.h:813
enumerable(enumerable< U > e)
Constructor for non-const to const conversion.
Definition: enumerable.h:218
auto enumerate_array(T *parr, size_t siz) -> enumerable< T >
Returns enumerable over array's sequence.
Definition: enumerable.h:916
iterator & operator++()
Moves to next element (pre-increment).
Definition: enumerable.h:557
iterator()=default
Default constructor.
iterator(const iterator &obj)=default
Copy constructor.
static enumerable< T > for_one_ref(reference obj)
Returns enumerable over sequence of one element (stored externally).
Definition: enumerable.h:676