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
17template <typename Iter, typename C = skstd::monostate>
18class 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
52public:
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
87private:
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
99template <typename C, typename Iter = decltype(std::begin(std::declval<C>()))>
100inline constexpr SkEnumerate<Iter> SkMakeEnumerate(C& c) {
101 return SkEnumerate<Iter>{std::begin(c), std::end(c)};
102}
103template <typename C, typename Iter = decltype(std::begin(std::declval<C>()))>
104inline constexpr SkEnumerate<Iter, C> SkMakeEnumerate(C&& c) {
105 return SkEnumerate<Iter, C>{std::forward<C>(c)};
106}
107
108template <class T, std::size_t N, typename Iter = decltype(std::begin(std::declval<T(&)[N]>()))>
109inline constexpr SkEnumerate<Iter> SkMakeEnumerate(T (&a)[N]) {
110 return SkEnumerate<Iter>{std::begin(a), std::end(a)};
111}
112#endif // SkIota_DEFINED
113