Home | History | Annotate | Download | only in cpplinq
      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;
    194         not1_(Pred p) : pred(p)
    195         {}
    196         template<class T>
    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>
    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>
    211         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 
    228     linq_driver(Collection c) : c(c) {}
    229 
    230 
    231     // -------------------- linq core methods --------------------
    232 
    233     template <class KeyFn>
    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>
    244     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> >
    250         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>
    256     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>
    262     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>
    270     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>
    282     T aggregate(T initialValue, Fn fn) const
    283     {
    284         return std::accumulate(begin(), end(), initialValue, fn);
    285     }
    286 
    287     bool any() const { auto cur = c.get_cursor(); return !cur.empty(); }
    288 
    289     template <class Predicate>
    290     bool any(Predicate p) const {
    291         auto it = std::find_if(begin(), end(), p);
    292         return it != end();
    293     }
    294 
    295     template <class Predicate>
    296     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>
    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 
    316     bool contains(const typename Collection::cursor::element_type& value) const {
    317         return std::find(begin(), end(), value) != end();
    318     }
    319 
    320     typename std::iterator_traits<iterator>::difference_type count() const {
    321         return std::distance(begin(), end());
    322     }
    323 
    324     template <class Predicate>
    325     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 
    335     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 
    345     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 
    355     bool empty() const {
    356         return !this->any();
    357     }
    358 
    359     // TODO: except(second)
    360     // TODO: except(second, eq)
    361 
    362     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>
    369     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 
    378     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>
    385     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
    404     last() const
    405     {
    406         return linq_last_(c.get_cursor(), typename Collection::cursor::cursor_category());
    407     }
    408 
    409     template <class Predicate>
    410     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 
    416     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>
    422     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 
    428     reference_type max() const
    429     {
    430         return max(std::less<element_type>());
    431     }
    432 
    433     template <class Compare>
    434     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 
    443     reference_type min() const
    444     {
    445         return min(std::less<element_type>());
    446     }
    447 
    448     template <class Compare>
    449     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 
    468     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>
    475     typename std::enable_if<std::is_default_constructible<ITEM>::value, ITEM>::type sum() const {
    476         ITEM seed{};
    477         return sum(seed);
    478     }
    479 
    480     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>
    485     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>
    490     Result sum(Selector sel, Result seed) const {
    491         return from(begin(), end()).select(sel).sum(seed);
    492     }
    493 
    494     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 
    511     std::vector<typename Collection::cursor::element_type> to_vector() const
    512     {
    513         return std::vector<typename Collection::cursor::element_type>(begin(), end());
    514     }
    515 
    516     std::list<typename Collection::cursor::element_type> to_list() const
    517     {
    518         return std::list<typename Collection::cursor::element_type>(begin(), end());
    519     }
    520 
    521     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 
    528     iterator begin() const  { auto cur = c.get_cursor(); return !cur.empty() ? iterator(cur) : iterator(); }
    529     iterator end() const    { return iterator(); }
    530     linq_driver& operator=(const linq_driver& other) { c = other.c; return *this; }
    531     template <class TC2>
    532     linq_driver& operator=(const linq_driver<TC2>& other) { c = other.c; return *this; }
    533 
    534     typename std::iterator_traits<iterator>::reference
    535         operator[](std::size_t ix) const {
    536         return *(begin()+=ix);
    537     }
    538 
    539     // -------------------- collection methods (leaky abstraction) --------------------
    540 
    541     typedef typename Collection::cursor cursor;
    542     cursor get_cursor() { return c.get_cursor(); }
    543 
    544     linq_driver< dynamic_collection<typename Collection::cursor::reference_type> >
    545         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>
    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>
    562 const linq_driver<T>& from(const linq_driver<T>& c)
    563 {
    564     return c;
    565 }
    566 template <class Iter>
    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>
    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