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