• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkIota_DEFINED
9 #define SkIota_DEFINED
10 
11 #include <cstddef>
12 #include <iterator>
13 #include <tuple>
14 
15 #include "include/private/SkTLogic.h"
16 
17 template <typename Iter, typename C = skstd::monostate>
18 class SkEnumerate {
19     using Captured = decltype(*std::declval<Iter>());
20     template <typename> struct is_tuple : std::false_type {};
21     template <typename... T> struct is_tuple<std::tuple<T...>> : std::true_type {};
22     static constexpr auto MakeResult(size_t i, Captured&& v) {
23         if constexpr (is_tuple<Captured>::value) {
24             return std::tuple_cat(std::tuple<size_t>{i}, std::forward<Captured>(v));
25         } else {
26             return std::tuple_cat(std::tuple<size_t>{i},
27                     std::make_tuple(std::forward<Captured>(v)));
28         }
29     }
30     using Result = decltype(MakeResult(0, std::declval<Captured>()));
31 
32     class Iterator {
33     public:
34         using value_type = Result;
35         using difference_type = ptrdiff_t;
36         using pointer = value_type*;
37         using reference = value_type;
38         using iterator_category = std::input_iterator_tag;
39         constexpr Iterator(ptrdiff_t index, Iter it) : fIndex{index}, fIt{it} { }
40         constexpr Iterator(const Iterator&) = default;
41         constexpr Iterator operator++() { ++fIndex; ++fIt; return *this; }
42         constexpr Iterator operator++(int) { Iterator tmp(*this); operator++(); return tmp; }
43         constexpr bool operator==(const Iterator& rhs) const { return fIt == rhs.fIt; }
44         constexpr bool operator!=(const Iterator& rhs) const { return fIt != rhs.fIt; }
45         constexpr reference operator*() { return MakeResult(fIndex, *fIt); }
46 
47     private:
48         ptrdiff_t fIndex;
49         Iter fIt;
50     };
51 
52 public:
53     constexpr SkEnumerate(Iter begin, Iter end) : SkEnumerate{0, begin, end} {}
54     explicit constexpr SkEnumerate(C&& c)
55             : fCollection{std::move(c)}
56             , fBeginIndex{0}
57             , fBegin{std::begin(fCollection)}
58             , fEnd{std::end(fCollection)} { }
59     constexpr SkEnumerate(const SkEnumerate& that) = default;
60     constexpr SkEnumerate& operator=(const SkEnumerate& that) {
61         fBegin = that.fBegin;
62         fEnd = that.fEnd;
63         return *this;
64     }
65     constexpr Iterator begin() const { return Iterator{fBeginIndex, fBegin}; }
66     constexpr Iterator end() const { return Iterator{fBeginIndex + this->ssize(), fEnd}; }
67     constexpr bool empty() const { return fBegin == fEnd; }
68     constexpr size_t size() const { return std::distance(fBegin,  fEnd); }
69     constexpr ptrdiff_t ssize() const { return std::distance(fBegin,  fEnd); }
70     constexpr SkEnumerate first(size_t n) {
71         SkASSERT(n <= this->size());
72         ptrdiff_t deltaEnd = this->ssize() - n;
73         return SkEnumerate{fBeginIndex, fBegin, std::prev(fEnd, deltaEnd)};
74     }
75     constexpr SkEnumerate last(size_t n) {
76         SkASSERT(n <= this->size());
77         ptrdiff_t deltaBegin = this->ssize() - n;
78         return SkEnumerate{fBeginIndex + deltaBegin, std::next(fBegin, deltaBegin), fEnd};
79     }
80     constexpr SkEnumerate subspan(size_t offset, size_t count) {
81         SkASSERT(offset < this->size());
82         SkASSERT(count <= this->size() - offset);
83         auto newBegin = std::next(fBegin, offset);
84         return SkEnumerate(fBeginIndex + offset, newBegin, std::next(newBegin, count));
85     }
86 
87 private:
88     constexpr SkEnumerate(ptrdiff_t beginIndex, Iter begin, Iter end)
89         : fBeginIndex{beginIndex}
90         , fBegin(begin)
91         , fEnd(end) {}
92 
93     C fCollection;
94     const ptrdiff_t fBeginIndex;
95     Iter fBegin;
96     Iter fEnd;
97 };
98 
99 template <typename C, typename Iter = decltype(std::begin(std::declval<C>()))>
100 inline constexpr SkEnumerate<Iter> SkMakeEnumerate(C& c) {
101     return SkEnumerate<Iter>{std::begin(c), std::end(c)};
102 }
103 template <typename C, typename Iter = decltype(std::begin(std::declval<C>()))>
104 inline constexpr SkEnumerate<Iter, C> SkMakeEnumerate(C&& c) {
105     return SkEnumerate<Iter, C>{std::forward<C>(c)};
106 }
107 
108 template <class T, std::size_t N, typename Iter = decltype(std::begin(std::declval<T(&)[N]>()))>
109 inline constexpr SkEnumerate<Iter> SkMakeEnumerate(T (&a)[N]) {
110     return SkEnumerate<Iter>{std::begin(a), std::end(a)};
111 }
112 #endif  // SkIota_DEFINED
113