xref: /third_party/skia/src/core/SkEnumerate.h (revision cb93a386)
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
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
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
55public:
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
90private:
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
102template <typename C, typename Iter = decltype(std::begin(std::declval<C>()))>
103inline constexpr SkEnumerate<Iter> SkMakeEnumerate(C& c) {
104    return SkEnumerate<Iter>{std::begin(c), std::end(c)};
105}
106template <typename C, typename Iter = decltype(std::begin(std::declval<C>()))>
107inline constexpr SkEnumerate<Iter, C> SkMakeEnumerate(C&& c) {
108    return SkEnumerate<Iter, C>{std::forward<C>(c)};
109}
110
111template <class T, std::size_t N, typename Iter = decltype(std::begin(std::declval<T(&)[N]>()))>
112inline constexpr SkEnumerate<Iter> SkMakeEnumerate(T (&a)[N]) {
113    return SkEnumerate<Iter>{std::begin(a), std::end(a)};
114}
115#endif  // SkEnumerate_DEFINED
116