xref: /aosp_15_r20/external/skia/src/core/SkEnumerate.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 SkEnumerate_DEFINED
9 #define SkEnumerate_DEFINED
10 
11 #include <cstddef>
12 #include <iterator>
13 #include <tuple>
14 #include <variant>
15 
16 template <typename Iter, typename C = std::monostate>
17 class SkEnumerate {
18     using Captured = decltype(*std::declval<Iter>());
19     template <typename> struct is_tuple : std::false_type {};
20     template <typename... T> struct is_tuple<std::tuple<T...>> : std::true_type {};
21 
22     // v must be a r-value to bind to temporary non-const references.
23     static constexpr auto MakeResult(size_t i, Captured&& v) {
24         if constexpr (is_tuple<Captured>::value) {
25             return std::tuple_cat(std::tuple<size_t>{i}, v);
26         } else {
27             // Capture v by reference instead of by value by using std::tie.
28             return std::tuple_cat(std::tuple<size_t>{i}, std::tie(v));
29         }
30     }
31 
32     using Result = decltype(MakeResult(0, std::declval<Captured>()));
33 
34     class Iterator {
35     public:
36         using value_type = Result;
37         using difference_type = ptrdiff_t;
38         using pointer = value_type*;
39         using reference = value_type;
40         using iterator_category = std::input_iterator_tag;
41         constexpr Iterator(ptrdiff_t index, Iter it) : fIndex{index}, fIt{it} { }
42         constexpr Iterator(const Iterator&) = default;
43         constexpr Iterator operator++() { ++fIndex; ++fIt; return *this; }
44         constexpr Iterator operator++(int) { Iterator tmp(*this); operator++(); return tmp; }
45         constexpr bool operator==(const Iterator& rhs) const { return fIt == rhs.fIt; }
46         constexpr bool operator!=(const Iterator& rhs) const { return fIt != rhs.fIt; }
47         constexpr reference operator*() { return MakeResult(fIndex, *fIt); }
48 
49     private:
50         ptrdiff_t fIndex;
51         Iter fIt;
52     };
53 
54 public:
55     constexpr SkEnumerate(Iter begin, Iter end) : SkEnumerate{0, begin, end} {}
56     explicit constexpr SkEnumerate(C&& c)
57             : fCollection{std::move(c)}
58             , fBeginIndex{0}
59             , fBegin{std::begin(fCollection)}
60             , fEnd{std::end(fCollection)} { }
61     constexpr SkEnumerate(const SkEnumerate& that) = default;
62     constexpr SkEnumerate& operator=(const SkEnumerate& that) {
63         fBegin = that.fBegin;
64         fEnd = that.fEnd;
65         return *this;
66     }
67     constexpr Iterator begin() const { return Iterator{fBeginIndex, fBegin}; }
68     constexpr Iterator end() const { return Iterator{fBeginIndex + this->ssize(), fEnd}; }
69     constexpr bool empty() const { return fBegin == fEnd; }
70     constexpr size_t size() const { return std::distance(fBegin,  fEnd); }
71     constexpr ptrdiff_t ssize() const { return std::distance(fBegin,  fEnd); }
72     constexpr SkEnumerate first(size_t n) {
73         SkASSERT(n <= this->size());
74         ptrdiff_t deltaEnd = this->ssize() - n;
75         return SkEnumerate{fBeginIndex, fBegin, std::prev(fEnd, deltaEnd)};
76     }
77     constexpr SkEnumerate last(size_t n) {
78         SkASSERT(n <= this->size());
79         ptrdiff_t deltaBegin = this->ssize() - n;
80         return SkEnumerate{fBeginIndex + deltaBegin, std::next(fBegin, deltaBegin), fEnd};
81     }
82     constexpr SkEnumerate subspan(size_t offset, size_t count) {
83         SkASSERT(offset < this->size());
84         SkASSERT(count <= this->size() - offset);
85         auto newBegin = std::next(fBegin, offset);
86         return SkEnumerate(fBeginIndex + offset, newBegin, std::next(newBegin, count));
87     }
88 
89 private:
90     constexpr SkEnumerate(ptrdiff_t beginIndex, Iter begin, Iter end)
91         : fBeginIndex{beginIndex}
92         , fBegin(begin)
93         , fEnd(end) {}
94 
95     C fCollection;
96     const ptrdiff_t fBeginIndex;
97     Iter fBegin;
98     Iter fEnd;
99 };
100 
101 template <typename C, typename Iter = decltype(std::begin(std::declval<C>()))>
102 inline constexpr SkEnumerate<Iter> SkMakeEnumerate(C& c) {
103     return SkEnumerate<Iter>{std::begin(c), std::end(c)};
104 }
105 template <typename C, typename Iter = decltype(std::begin(std::declval<C>()))>
106 inline constexpr SkEnumerate<Iter, C> SkMakeEnumerate(C&& c) {
107     return SkEnumerate<Iter, C>{std::forward<C>(c)};
108 }
109 
110 template <class T, std::size_t N, typename Iter = decltype(std::begin(std::declval<T(&)[N]>()))>
111 inline constexpr SkEnumerate<Iter> SkMakeEnumerate(T (&a)[N]) {
112     return SkEnumerate<Iter>{std::begin(a), std::end(a)};
113 }
114 #endif  // SkEnumerate_DEFINED
115