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 #if !defined(CPPLINQ_LINQ_TAKE_HPP)
      4 #define CPPLINQ_LINQ_TAKE_HPP
      5 #pragma once
      6 
      7 #include <cstddef>
      8 
      9 namespace cpplinq
     10 {
     11     template <class InnerCursor>
     12     struct linq_take_cursor
     13     {
     14         typedef typename InnerCursor::element_type element_type;
     15         typedef typename InnerCursor::reference_type reference_type;
     16         typedef typename InnerCursor::cursor_category cursor_category;
     17 
     18         linq_take_cursor(const InnerCursor& cur, std::size_t rem) : cur(cur), rem(rem) {}
     19 
     20         void forget() { cur.forget(); }
     21         bool empty() const { return cur.empty() || rem == 0; }
     22         void inc() { cur.inc(); --rem; }
     23         reference_type get() const { return cur.get(); }
     24 
     25         bool atbegin() const { return cur.atbegin(); }
     26         void dec() { cur.dec(); --rem; }
     27 
     28         void skip(std::size_t n) { cur.skip(n); rem -= n; }
     29         std::size_t position() const { return cur.position(); }
     30         std::size_t size() const { return cur.size(); }
     31 
     32     private:
     33         InnerCursor cur;
     34         std::size_t rem;
     35     };
     36 
     37     namespace detail {
     38         template <class Collection>
     39         linq_take_cursor<typename Collection::cursor>
     40             take_get_cursor_(
     41                 const Collection& c,
     42                 std::size_t n,
     43                 onepass_cursor_tag
     44                 )
     45         {
     46             return linq_take_cursor<typename Collection::cursor>(c.get_cursor(), n);
     47         }
     48 
     49         template <class Collection>
     50         typename Collection::cursor
     51             take_get_cursor_(
     52                 const Collection& c,
     53                 std::size_t n,
     54                 random_access_cursor_tag
     55                 )
     56         {
     57             auto cur = c.get_cursor();
     58             if (cur.size() > n) {
     59                 cur.truncate(n);
     60             }
     61             return cur;
     62         }
     63     }
     64 
     65     template <class Collection>
     66     struct linq_take
     67     {
     68         typedef typename std::conditional<
     69                 util::less_or_equal_cursor_category<
     70                     random_access_cursor_tag,
     71                     typename Collection::cursor::cursor_category>::value,
     72                 typename Collection::cursor,
     73                 linq_take_cursor<typename Collection::cursor>>::type
     74             cursor;
     75 
     76         linq_take(const Collection& c, std::size_t n) : c(c), n(n) {}
     77 
     78         cursor get_cursor() const {
     79             return detail::take_get_cursor_(c, n, typename Collection::cursor::cursor_category());
     80         }
     81 
     82         Collection  c;
     83         std::size_t n;
     84     };
     85 
     86     template <class Collection>
     87     auto get_cursor(
     88             const linq_take<Collection>& take
     89             )
     90     -> decltype(get_cursor_(take, typename Collection::cursor::cursor_category()))
     91     {
     92         return get_cursor_(take, typename Collection::cursor::cursor_category());
     93     }
     94 
     95 
     96 }
     97 #endif // !defined(CPPLINQ_LINQ_TAKE_HPP)
     98 
     99