• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2 
3 ///
4 /// namespace cpplinq
5 /// -----------------
6 ///
7 /// Defines a number of range-based composable operators for enumerating and modifying collections
8 ///
9 /// The general design philosophy is to
10 ///   (1) emulate the composable query patterns introduced in C# Linq
11 ///   (2) preserve iterator category and writability where possible
12 /// For instance, like C# Linq we have a select operator to project one sequence into a new one.
13 /// Unlike Linq, invoking Select on a random access sequence will yield you a _random_ access sequence.
14 ///
15 /// The general workflow begins with 'from()' which normally only takes a reference
16 /// the the collection in question. However, from that point on, all operators function
17 /// by value, so that the range can store any necessary state, rather than duplicating it
18 /// onto iterator pairs.
19 ///
20 /// In subsequent documentation, "powers" lists which powers that the operator attempts to preserve if
21 /// available on on the input sequence. Some iterator powers may be skipped - in such a case, round down
22 /// to the next supported power (e.g. if 'fwd' and 'rnd', an input of 'bidi' will round down to a 'fwd' result).
23 ///
24 ///
25 ///
26 /// class linq_query
27 /// ----------------
28 ///
29 /// from(container&)
30 /// ================
31 /// -   Result: Query
32 ///
33 /// Construct a new query, from an lvalue reference to a collection. Does not copy the collection
34 ///
35 ///
36 ///
37 /// from(iter, iter)
38 /// ================
39 /// -   Result: Query
40 ///
41 /// Construct a new query, from an iterator pair.
42 ///
43 ///
44 ///
45 /// query.select(map)
46 /// ==========================
47 /// -   Result: Query
48 /// -   Powers: input, forward, bidirectional, random access
49 ///
50 /// For each element `x` in the input sequences, computes `map(x)` for the result sequence.
51 ///
52 ///
53 ///
54 /// query.where(pred) -> query
55 /// ==========================
56 /// -   Result: Query
57 /// -   Powers: input, forward, bidirectional
58 ///
59 /// Each element `x` in the input appears in the output if `pred(x)` is true.
60 ///
61 /// The expression `pred(x)` is evaluated only when moving iterators (op++, op--).
62 /// Dereferencing (op*) does not invoke the predicate.
63 ///
64 ///
65 ///
66 /// query.groupby(keymap [, keyequal])
67 /// ====================================
68 /// Result: Query of groups. Each group has a 'key' field, and is a query of elements from the input.
69 /// Powers: forward
70 ///
71 ///
72 ///
73 /// query.any([pred])
74 /// =================
75 /// -   Result: bool
76 ///
77 /// (No argument) Returns true if sequence is non-empty. Equivalent to `query.begin()!=query.end()`
78 ///
79 /// (One argument) Returns true if the sequence contains any elements for which `pred(element)` is true.
80 /// Equivalent to `query.where(pred).any()`.
81 ///
82 ///
83 ///
84 /// query.all(pred)
85 /// ===============
86 /// -   Result: bool
87 ///
88 /// Returns true if `pred` holds for all elements in the sequence. Equivalent to `!query.any(std::not1(pred))`
89 ///
90 ///
91 ///
92 /// query.take(n)
93 /// =============
94 /// -   Result: query
95 /// -   Powers: input, forward, random access (not bidirectional)
96 ///
97 /// Returns a sequence that contains up to `n` items from the original sequence.
98 ///
99 ///
100 ///
101 /// query.skip(n)
102 /// =============
103 /// -   Result: query
104 /// -   Powers: input, forward, random access (not bidirectional)
105 ///
106 /// Returns a sequence that skips the first `n` items from the original sequence, or an empty sequence if
107 /// fewer than `n` were available on input.
108 ///
109 /// Note: begin() takes O(n) time when input iteration power is weaker than random access.
110 ///
111 ///
112 ///
113 /// query.count([pred])
114 /// ===================
115 /// -   Result: std::size_t
116 ///
117 /// _TODO: should use inner container's iterator distance type instead._
118 ///
119 /// (Zero-argument) Returns the number of elements in the range.
120 /// Equivalent to `std::distance(query.begin(), query.end())`
121 ///
122 /// (One-argument) Returns the number of elements for whicht `pred(element)` is true.
123 /// Equivalent to `query.where(pred).count()`
124 ///
125 
126 
127 
128 #if !defined(CPPLINQ_LINQ_HPP)
129 #define CPPLINQ_LINQ_HPP
130 #pragma once
131 
132 #pragma push_macro("min")
133 #pragma push_macro("max")
134 #undef min
135 #undef max
136 
137 #include <functional>
138 #include <iterator>
139 #include <algorithm>
140 #include <numeric>
141 #include <list>
142 #include <map>
143 #include <set>
144 #include <memory>
145 #include <utility>
146 #include <type_traits>
147 #include <vector>
148 #include <cstddef>
149 
150 
151 
152 // some configuration macros
153 #if _MSC_VER > 1600 || __cplusplus > 199711L
154 #define LINQ_USE_RVALUEREF 1
155 #endif
156 
157 #if (defined(_MSC_VER) && _CPPRTTI) || !defined(_MSC_VER)
158 #define LINQ_USE_RTTI 1
159 #endif
160 
161 #if defined(__clang__)
162 #if __has_feature(cxx_rvalue_references)
163 #define LINQ_USE_RVALUEREF 1
164 #endif
165 #if __has_feature(cxx_rtti)
166 #define LINQ_USE_RTTI 1
167 #endif
168 #endif
169 
170 
171 // individual features
172 #include "util.hpp"
173 #include "linq_cursor.hpp"
174 #include "linq_iterators.hpp"
175 #include "linq_select.hpp"
176 #include "linq_take.hpp"
177 #include "linq_skip.hpp"
178 #include "linq_groupby.hpp"
179 #include "linq_where.hpp"
180 #include "linq_last.hpp"
181 #include "linq_selectmany.hpp"
182 
183 
184 
185 
186 namespace cpplinq
187 {
188 
189 namespace detail
190 {
191     template<class Pred>
192     struct not1_{
193         Pred pred;
not1_cpplinq::detail::not1_194         not1_(Pred p) : pred(p)
195         {}
196         template<class T>
operator ()cpplinq::detail::not1_197         bool operator()(const T& value)
198         {
199             return !pred(value);
200         }
201     };
202     // note: VC2010's std::not1 doesn't support lambda expressions. provide our own.
203     template<class Pred>
not1(Pred p)204     not1_<Pred> not1(Pred p) { return not1_<Pred>(p); }
205 }
206 
207 namespace detail {
208     template <class U>
209     struct cast_to {
210         template <class T>
operator ()cpplinq::detail::cast_to211         U operator()(const T& value) const {
212             return static_cast<U>(value);
213         }
214     };
215 }
216 
217 template <class Collection>
218 class linq_driver
219 {
220     typedef typename Collection::cursor::element_type
221         element_type;
222     typedef typename Collection::cursor::reference_type
223         reference_type;
224 public:
225     typedef cursor_iterator<typename Collection::cursor>
226         iterator;
227 
linq_driver(Collection c)228     linq_driver(Collection c) : c(c) {}
229 
230 
231     // -------------------- linq core methods --------------------
232 
233     template <class KeyFn>
groupby(KeyFn fn)234     linq_driver< linq_groupby<Collection, KeyFn> > groupby(KeyFn fn)
235     {
236         return linq_groupby<Collection, KeyFn>(c, std::move(fn) );
237     }
238 
239     // TODO: groupby(keyfn, eq)
240 
241     // TODO: join...
242 
243     template <class Selector>
select(Selector sel) const244     linq_driver< linq_select<Collection, Selector> > select(Selector sel) const {
245         return linq_select<Collection, Selector>(c, std::move(sel) );
246     }
247 
248     template <class Fn>
249     linq_driver< linq_select_many<Collection, Fn, detail::default_select_many_selector> >
select_many(Fn fn) const250         select_many(Fn fn) const
251     {
252         return linq_select_many<Collection, Fn, detail::default_select_many_selector>(c, fn, detail::default_select_many_selector());
253     }
254 
255     template <class Fn, class Fn2>
select_many(Fn fn,Fn2 fn2) const256     linq_driver< linq_select_many<Collection, Fn, Fn2> > select_many(Fn fn, Fn2 fn2) const
257     {
258         return linq_select_many<Collection, Fn, Fn2>(c, fn, fn2);
259     }
260 
261     template <class Predicate>
where(Predicate p) const262     linq_driver< linq_where<Collection, Predicate> > where(Predicate p) const {
263         return linq_where<Collection, Predicate>(c, std::move(p) );
264     }
265 
266 
267     // -------------------- linq peripheral methods --------------------
268 
269     template <class Fn>
aggregate(Fn fn) const270     element_type aggregate(Fn fn) const
271     {
272         auto it = begin();
273         if (it == end()) {
274             return element_type();
275         }
276 
277         reference_type first = *it;
278         return std::accumulate(++it, end(), first, fn);
279     }
280 
281     template <class T, class Fn>
aggregate(T initialValue,Fn fn) const282     T aggregate(T initialValue, Fn fn) const
283     {
284         return std::accumulate(begin(), end(), initialValue, fn);
285     }
286 
any() const287     bool any() const { auto cur = c.get_cursor(); return !cur.empty(); }
288 
289     template <class Predicate>
any(Predicate p) const290     bool any(Predicate p) const {
291         auto it = std::find_if(begin(), end(), p);
292         return it != end();
293     }
294 
295     template <class Predicate>
all(Predicate p) const296     bool all(Predicate p) const {
297         auto it = std::find_if(begin(), end(), detail::not1(p));
298         return it == end();
299     }
300 
301     // TODO: average
302 
303 #if !defined(__clang__)
304     // Clang complains that linq_driver is not complete until the closing brace
305     // so (linq_driver*)->select() cannot be resolved.
306     template <class U>
cast()307     auto cast()
308     -> decltype(static_cast<linq_driver*>(0)->select(detail::cast_to<U>()))
309     {
310         return this->select(detail::cast_to<U>());
311     }
312 #endif
313 
314     // TODO: concat
315 
contains(const typename Collection::cursor::element_type & value) const316     bool contains(const typename Collection::cursor::element_type& value) const {
317         return std::find(begin(), end(), value) != end();
318     }
319 
count() const320     typename std::iterator_traits<iterator>::difference_type count() const {
321         return std::distance(begin(), end());
322     }
323 
324     template <class Predicate>
count(Predicate p) const325     typename std::iterator_traits<iterator>::difference_type count(Predicate p) const {
326         auto filtered = this->where(p);
327         return std::distance(begin(filtered), end(filtered));
328     }
329 
330     // TODO: default_if_empty
331 
332     // TODO: distinct()
333     // TODO: distinct(cmp)
334 
element_at(std::size_t ix) const335     reference_type element_at(std::size_t ix) const {
336         auto cur = c.get_cursor();
337         while(ix && !cur.empty()) {
338             cur.inc();
339             --ix;
340         }
341         if (cur.empty()) { throw std::logic_error("index out of bounds"); }
342         else             { return cur.get(); }
343     }
344 
element_at_or_default(std::size_t ix) const345     element_type element_at_or_default(std::size_t ix) const {
346         auto cur = c.get_cursor();
347         while(ix && !cur.empty()) {
348             cur.inc();
349             -- ix;
350         }
351         if (cur.empty()) { return element_type(); }
352         else             { return cur.get(); }
353     }
354 
empty() const355     bool empty() const {
356         return !this->any();
357     }
358 
359     // TODO: except(second)
360     // TODO: except(second, eq)
361 
first() const362     reference_type first() const {
363         auto cur = c.get_cursor();
364         if (cur.empty()) { throw std::logic_error("index out of bounds"); }
365         else             { return cur.get(); }
366     }
367 
368     template <class Predicate>
first(Predicate pred) const369     reference_type first(Predicate pred) const {
370         auto cur = c.get_cursor();
371         while (!cur.empty() && !pred(cur.get())) {
372             cur.inc();
373         }
374         if (cur.empty()) { throw std::logic_error("index out of bounds"); }
375         else             { return cur.get(); }
376     }
377 
first_or_default() const378     element_type first_or_default() const {
379         auto cur = c.get_cursor();
380         if (cur.empty()) { return element_type(); }
381         else             { return cur.get(); }
382     }
383 
384     template <class Predicate>
first_or_default(Predicate pred) const385     element_type first_or_default(Predicate pred) const {
386         auto cur = c.get_cursor();
387         while (!cur.empty() && !pred(cur.get())) {
388             cur.inc();
389         }
390         if (cur.empty()) { return element_type(); }
391         else             { return cur.get(); }
392     }
393 
394     // TODO: intersect(second)
395     // TODO: intersect(second, eq)
396 
397     // note: forward cursors and beyond can provide a clone, so we can refer to the element directly
398     typename std::conditional<
399         std::is_convertible<
400             typename Collection::cursor::cursor_category,
401             forward_cursor_tag>::value,
402         reference_type,
403         element_type>::type
last() const404     last() const
405     {
406         return linq_last_(c.get_cursor(), typename Collection::cursor::cursor_category());
407     }
408 
409     template <class Predicate>
last(Predicate pred) const410     reference_type last(Predicate pred) const
411     {
412         auto cur = c.where(pred).get_cursor();
413         return linq_last_(cur, typename decltype(cur)::cursor_category());
414     }
415 
last_or_default() const416     element_type last_or_default() const
417     {
418         return linq_last_or_default_(c.get_cursor(), typename Collection::cursor::cursor_category());
419     }
420 
421     template <class Predicate>
last_or_default(Predicate pred) const422     element_type last_or_default(Predicate pred) const
423     {
424         auto cur = c.where(pred).get_cursor();
425         return linq_last_or_default_(cur, typename decltype(cur)::cursor_category());
426     }
427 
max() const428     reference_type max() const
429     {
430         return max(std::less<element_type>());
431     }
432 
433     template <class Compare>
max(Compare less) const434     reference_type max(Compare less) const
435     {
436         auto it = std::max_element(begin(), end(), less);
437         if (it == end())
438             throw std::logic_error("max performed on empty range");
439 
440         return *it;
441     }
442 
min() const443     reference_type min() const
444     {
445         return min(std::less<element_type>());
446     }
447 
448     template <class Compare>
min(Compare less) const449     reference_type min(Compare less) const
450     {
451         auto it = std::min_element(begin(), end(), less);
452         if (it == end())
453             throw std::logic_error("max performed on empty range");
454 
455         return *it;
456     }
457 
458     // TODO: order_by(sel)
459     // TODO: order_by(sel, less)
460     // TODO: order_by_descending(sel)
461     // TODO: order_by_descending(sel, less)
462 
463     // TODO: sequence_equal(second)
464     // TODO: sequence_equal(second, eq)
465 
466     // TODO: single / single_or_default
467 
skip(std::size_t n) const468     linq_driver<linq_skip<Collection>> skip(std::size_t n) const {
469         return linq_skip<Collection>(c, n);
470     }
471 
472     // TODO: skip_while(pred)
473 
474     template<typename ITEM = element_type>
sum() const475     typename std::enable_if<std::is_default_constructible<ITEM>::value, ITEM>::type sum() const {
476         ITEM seed{};
477         return sum(seed);
478     }
479 
sum(element_type seed) const480     element_type sum(element_type seed) const {
481         return std::accumulate(begin(), end(), seed);
482     }
483 
484     template <typename Selector, typename Result = typename std::result_of<Selector(element_type)>::type>
sum(Selector sel) const485     typename std::enable_if<std::is_default_constructible<Result>::value, Result>::type sum(Selector sel) const {
486         return from(begin(), end()).select(sel).sum();
487     }
488 
489     template <typename Selector, typename Result = typename std::result_of<Selector(element_type)>::type>
sum(Selector sel,Result seed) const490     Result sum(Selector sel, Result seed) const {
491         return from(begin(), end()).select(sel).sum(seed);
492     }
493 
take(std::size_t n) const494     linq_driver<linq_take<Collection>> take(std::size_t n) const {
495         return linq_take<Collection>(c, n);
496     }
497 
498     // TODO: take_while
499 
500     // TODO: then_by / then_by_descending ?
501 
502     // TODO: to_...
503 
504     // TODO: union(second)
505     // TODO: union(eq)
506 
507     // TODO: zip
508 
509     // -------------------- conversion methods --------------------
510 
to_vector() const511     std::vector<typename Collection::cursor::element_type> to_vector() const
512     {
513         return std::vector<typename Collection::cursor::element_type>(begin(), end());
514     }
515 
to_list() const516     std::list<typename Collection::cursor::element_type> to_list() const
517     {
518         return std::list<typename Collection::cursor::element_type>(begin(), end());
519     }
520 
to_set() const521     std::set<typename Collection::cursor::element_type> to_set() const
522     {
523         return std::set<typename Collection::cursor::element_type>(begin(), end());
524     }
525 
526     // -------------------- container/range methods --------------------
527 
begin() const528     iterator begin() const  { auto cur = c.get_cursor(); return !cur.empty() ? iterator(cur) : iterator(); }
end() const529     iterator end() const    { return iterator(); }
operator =(const linq_driver & other)530     linq_driver& operator=(const linq_driver& other) { c = other.c; return *this; }
531     template <class TC2>
operator =(const linq_driver<TC2> & other)532     linq_driver& operator=(const linq_driver<TC2>& other) { c = other.c; return *this; }
533 
534     typename std::iterator_traits<iterator>::reference
operator [](std::size_t ix) const535         operator[](std::size_t ix) const {
536         return *(begin()+=ix);
537     }
538 
539     // -------------------- collection methods (leaky abstraction) --------------------
540 
541     typedef typename Collection::cursor cursor;
get_cursor()542     cursor get_cursor() { return c.get_cursor(); }
543 
544     linq_driver< dynamic_collection<typename Collection::cursor::reference_type> >
late_bind() const545         late_bind() const
546     {
547         return dynamic_collection<typename Collection::cursor::reference_type>(c);
548     }
549 
550 private:
551     Collection c;
552 };
553 
554 // TODO: should probably use reference-wrapper instead?
555 template <class TContainer>
from(TContainer & c)556 linq_driver<iter_cursor<typename util::container_traits<TContainer>::iterator>> from(TContainer& c)
557 {
558     auto cur = iter_cursor<typename util::container_traits<TContainer>::iterator>(std::begin(c), std::end(c));
559     return cur;
560 }
561 template <class T>
from(const linq_driver<T> & c)562 const linq_driver<T>& from(const linq_driver<T>& c)
563 {
564     return c;
565 }
566 template <class Iter>
from(Iter start,Iter finish)567 linq_driver<iter_cursor<Iter>> from(Iter start, Iter finish)
568 {
569     return iter_cursor<Iter>(start, finish);
570 }
571 
572 template <class TContainer>
from_value(const TContainer & c)573 linq_driver<TContainer> from_value(const TContainer& c)
574 {
575     return linq_driver<TContainer>(c);
576 }
577 
578 }
579 
580 #pragma pop_macro("min")
581 #pragma pop_macro("max")
582 
583 #endif // defined(CPPLINQ_LINQ_HPP)
584 
585