1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef ART_LIBARTBASE_BASE_TRANSFORM_ITERATOR_H_
18 #define ART_LIBARTBASE_BASE_TRANSFORM_ITERATOR_H_
19
20 #include <iterator>
21 #include <type_traits>
22
23 #include "iteration_range.h"
24
25 namespace art {
26
27 // The transform iterator transforms values from the base iterator with a given
28 // transformation function. It can serve as a replacement for std::transform(), i.e.
29 // std::copy(MakeTransformIterator(begin, f), MakeTransformIterator(end, f), out)
30 // is equivalent to
31 // std::transform(begin, end, f)
32 // If the function returns an l-value reference or a wrapper that supports assignment,
33 // the TransformIterator can be used also as an output iterator, i.e.
34 // std::copy(begin, end, MakeTransformIterator(out, f))
35 // is equivalent to
36 // for (auto it = begin; it != end; ++it) {
37 // f(*out++) = *it;
38 // }
39 template <typename BaseIterator, typename Function>
40 class TransformIterator {
41 private:
42 static_assert(std::is_base_of_v<std::input_iterator_tag,
43 typename std::iterator_traits<BaseIterator>::iterator_category>,
44 "Transform iterator base must be an input iterator.");
45
46 using BaseReference = typename std::iterator_traits<BaseIterator>::reference;
47 using InputType = std::conditional_t<std::is_same_v<BaseReference, void>,
48 typename std::iterator_traits<BaseIterator>::value_type,
49 BaseReference>;
50 using ResultType = std::invoke_result_t<Function, InputType>;
51
52 public:
53 using iterator_category = typename std::iterator_traits<BaseIterator>::iterator_category;
54 using value_type = std::remove_const_t<std::remove_reference_t<ResultType>>;
55 using difference_type = typename std::iterator_traits<BaseIterator>::difference_type;
56 using pointer = std::conditional_t<std::is_reference_v<ResultType>,
57 std::add_pointer_t<std::remove_reference_t<ResultType>>,
58 TransformIterator>;
59 using reference = ResultType;
60
TransformIterator(BaseIterator base,Function fn)61 TransformIterator(BaseIterator base, Function fn)
62 : data_(base, fn) { }
63
64 template <typename OtherBI>
TransformIterator(const TransformIterator<OtherBI,Function> & other)65 TransformIterator(const TransformIterator<OtherBI, Function>& other)
66 : data_(other.base(), other.GetFunction()) {
67 }
68
69 TransformIterator& operator++() {
70 ++data_.base_;
71 return *this;
72 }
73
74 TransformIterator operator++(int) {
75 TransformIterator tmp(*this);
76 ++*this;
77 return tmp;
78 }
79
80 TransformIterator& operator--() {
81 static_assert(std::is_base_of_v<std::bidirectional_iterator_tag,
82 typename std::iterator_traits<BaseIterator>::iterator_category>,
83 "BaseIterator must be bidirectional iterator to use operator--()");
84 --data_.base_;
85 return *this;
86 }
87
88 TransformIterator operator--(int) {
89 TransformIterator tmp(*this);
90 --*this;
91 return tmp;
92 }
93
94 reference operator*() const {
95 return GetFunction()(*base());
96 }
97
98 reference operator[](difference_type n) const {
99 static_assert(std::is_base_of_v<std::random_access_iterator_tag,
100 typename std::iterator_traits<BaseIterator>::iterator_category>,
101 "BaseIterator must be random access iterator to use operator[]");
102 return GetFunction()(base()[n]);
103 }
104
105 TransformIterator operator+(difference_type n) const {
106 static_assert(std::is_base_of_v<std::random_access_iterator_tag,
107 typename std::iterator_traits<BaseIterator>::iterator_category>,
108 "BaseIterator must be random access iterator to use operator+");
109 return TransformIterator(base() + n, GetFunction());
110 }
111
112 TransformIterator operator-(difference_type n) const {
113 static_assert(std::is_base_of_v<std::random_access_iterator_tag,
114 typename std::iterator_traits<BaseIterator>::iterator_category>,
115 "BaseIterator must be random access iterator to use operator-");
116 return TransformIterator(base() - n, GetFunction());
117 }
118
119 difference_type operator-(const TransformIterator& other) const {
120 static_assert(std::is_base_of_v<std::random_access_iterator_tag,
121 typename std::iterator_traits<BaseIterator>::iterator_category>,
122 "BaseIterator must be random access iterator to use operator-");
123 return base() - other.base();
124 }
125
126 // Retrieve the base iterator.
base()127 BaseIterator base() const {
128 return data_.base_;
129 }
130
131 // Retrieve the transformation function.
GetFunction()132 const Function& GetFunction() const {
133 return static_cast<const Function&>(data_);
134 }
135
136 private:
137 // Allow EBO for state-less Function.
138 struct Data : Function {
139 public:
DataData140 Data(BaseIterator base, Function fn) : Function(fn), base_(base) { }
141
142 BaseIterator base_;
143 };
144
145 Data data_;
146 };
147
148 template <typename BaseIterator1, typename BaseIterator2, typename Function>
149 bool operator==(const TransformIterator<BaseIterator1, Function>& lhs,
150 const TransformIterator<BaseIterator2, Function>& rhs) {
151 return lhs.base() == rhs.base();
152 }
153
154 template <typename BaseIterator1, typename BaseIterator2, typename Function>
155 bool operator!=(const TransformIterator<BaseIterator1, Function>& lhs,
156 const TransformIterator<BaseIterator2, Function>& rhs) {
157 return !(lhs == rhs);
158 }
159
160 template <typename BaseIterator, typename Function>
MakeTransformIterator(BaseIterator base,Function f)161 TransformIterator<BaseIterator, Function> MakeTransformIterator(BaseIterator base, Function f) {
162 return TransformIterator<BaseIterator, Function>(base, f);
163 }
164
165 template <typename BaseRange, typename Function>
MakeTransformRange(BaseRange && range,Function f)166 auto MakeTransformRange(BaseRange&& range, Function f) {
167 return MakeIterationRange(MakeTransformIterator(range.begin(), f),
168 MakeTransformIterator(range.end(), f));
169 }
170
171 } // namespace art
172
173 #endif // ART_LIBARTBASE_BASE_TRANSFORM_ITERATOR_H_
174