blob: f0769d480080263564bcc1985770bb03e83849bb [file] [log] [blame]
Vladimir Marko372f10e2016-05-17 16:30:10 +01001/*
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_COMPILER_UTILS_TRANSFORM_ITERATOR_H_
18#define ART_COMPILER_UTILS_TRANSFORM_ITERATOR_H_
19
20#include <iterator>
21#include <type_traits>
22
23#include "base/iteration_range.h"
24
25namespace 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// }
39template <typename BaseIterator, typename Function>
40class TransformIterator {
41 private:
42 static_assert(std::is_base_of<
43 std::input_iterator_tag,
44 typename std::iterator_traits<BaseIterator>::iterator_category>::value,
45 "Transform iterator base must be an input iterator.");
46
47 using InputType =
48 typename std::conditional<
49 std::is_same<void, typename std::iterator_traits<BaseIterator>::reference>::value,
50 typename std::iterator_traits<BaseIterator>::value_type,
51 typename std::iterator_traits<BaseIterator>::reference>::type;
52 using ResultType = typename std::result_of<Function(InputType)>::type;
53
54 public:
55 using iterator_category = typename std::iterator_traits<BaseIterator>::iterator_category;
56 using value_type =
57 typename std::remove_const<typename std::remove_reference<ResultType>::type>::type;
58 using difference_type = typename std::iterator_traits<BaseIterator>::difference_type;
59 using pointer = typename std::conditional<
60 std::is_reference<ResultType>::value,
61 typename std::add_pointer<typename std::remove_reference<ResultType>::type>::type,
62 TransformIterator>::type;
63 using reference = ResultType;
64
65 TransformIterator(BaseIterator base, Function fn)
66 : data_(base, fn) { }
67
68 template <typename OtherBI>
69 TransformIterator(const TransformIterator<OtherBI, Function>& other)
70 : data_(other.base(), other.GetFunction()) {
71 }
72
73 TransformIterator& operator++() {
74 ++data_.base_;
75 return *this;
76 }
77
78 TransformIterator& operator++(int) {
79 TransformIterator tmp(*this);
80 ++*this;
81 return tmp;
82 }
83
84 TransformIterator& operator--() {
85 static_assert(
86 std::is_base_of<std::bidirectional_iterator_tag,
87 typename std::iterator_traits<BaseIterator>::iterator_category>::value,
88 "BaseIterator must be bidirectional iterator to use operator--()");
89 --data_.base_;
90 return *this;
91 }
92
93 TransformIterator& operator--(int) {
94 TransformIterator tmp(*this);
95 --*this;
96 return tmp;
97 }
98
99 reference operator*() const {
100 return GetFunction()(*base());
101 }
102
103 reference operator[](difference_type n) const {
104 static_assert(
105 std::is_base_of<std::random_access_iterator_tag,
106 typename std::iterator_traits<BaseIterator>::iterator_category>::value,
107 "BaseIterator must be random access iterator to use operator[]");
108 return GetFunction()(base()[n]);
109 }
110
111 TransformIterator operator+(difference_type n) const {
112 static_assert(
113 std::is_base_of<std::random_access_iterator_tag,
114 typename std::iterator_traits<BaseIterator>::iterator_category>::value,
115 "BaseIterator must be random access iterator to use operator+");
116 return TransformIterator(base() + n, GetFunction());
117 }
118
119 TransformIterator operator-(difference_type n) const {
120 static_assert(
121 std::is_base_of<std::random_access_iterator_tag,
122 typename std::iterator_traits<BaseIterator>::iterator_category>::value,
123 "BaseIterator must be random access iterator to use operator-");
124 return TransformIterator(base() - n, GetFunction());
125 }
126
127 difference_type operator-(const TransformIterator& other) const {
128 static_assert(
129 std::is_base_of<std::random_access_iterator_tag,
130 typename std::iterator_traits<BaseIterator>::iterator_category>::value,
131 "BaseIterator must be random access iterator to use operator-");
132 return base() - other.base();
133 }
134
135 // Retrieve the base iterator.
136 BaseIterator base() const {
137 return data_.base_;
138 }
139
140 // Retrieve the transformation function.
141 const Function& GetFunction() const {
142 return static_cast<const Function&>(data_);
143 }
144
145 private:
146 // Allow EBO for state-less Function.
147 struct Data : Function {
148 public:
149 Data(BaseIterator base, Function fn) : Function(fn), base_(base) { }
150
151 BaseIterator base_;
152 };
153
154 Data data_;
155};
156
157template <typename BaseIterator1, typename BaseIterator2, typename Function>
158bool operator==(const TransformIterator<BaseIterator1, Function>& lhs,
159 const TransformIterator<BaseIterator2, Function>& rhs) {
160 return lhs.base() == rhs.base();
161}
162
163template <typename BaseIterator1, typename BaseIterator2, typename Function>
164bool operator!=(const TransformIterator<BaseIterator1, Function>& lhs,
165 const TransformIterator<BaseIterator2, Function>& rhs) {
166 return !(lhs == rhs);
167}
168
169template <typename BaseIterator, typename Function>
170TransformIterator<BaseIterator, Function> MakeTransformIterator(BaseIterator base, Function f) {
171 return TransformIterator<BaseIterator, Function>(base, f);
172}
173
174template <typename BaseRange, typename Function>
175auto MakeTransformRange(BaseRange& range, Function f) {
176 return MakeIterationRange(MakeTransformIterator(range.begin(), f),
177 MakeTransformIterator(range.end(), f));
178}
179
180} // namespace art
181
182#endif // ART_COMPILER_UTILS_TRANSFORM_ITERATOR_H_