blob: 062c88b62908db88303fc5a1da887152320e0246 [file] [log] [blame]
Martin Stjernholmc15e7e42020-12-02 22:50:53 +00001/*
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
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:
android-t13d2c5b22022-10-12 13:43:18 +080042 static_assert(std::is_base_of_v<std::input_iterator_tag,
43 typename std::iterator_traits<BaseIterator>::iterator_category>,
Martin Stjernholmc15e7e42020-12-02 22:50:53 +000044 "Transform iterator base must be an input iterator.");
45
46 using InputType = typename std::iterator_traits<BaseIterator>::reference;
android-t13d2c5b22022-10-12 13:43:18 +080047 using ResultType = std::result_of_t<Function(InputType)>;
Martin Stjernholmc15e7e42020-12-02 22:50:53 +000048
49 public:
50 using iterator_category = typename std::iterator_traits<BaseIterator>::iterator_category;
android-t13d2c5b22022-10-12 13:43:18 +080051 using value_type = std::remove_const_t<std::remove_reference_t<ResultType>>;
Martin Stjernholmc15e7e42020-12-02 22:50:53 +000052 using difference_type = typename std::iterator_traits<BaseIterator>::difference_type;
android-t13d2c5b22022-10-12 13:43:18 +080053 using pointer = std::conditional_t<std::is_reference_v<ResultType>,
54 std::add_pointer_t<std::remove_reference_t<ResultType>>,
55 TransformIterator>;
Martin Stjernholmc15e7e42020-12-02 22:50:53 +000056 using reference = ResultType;
57
58 TransformIterator(BaseIterator base, Function fn)
59 : data_(base, fn) { }
60
61 template <typename OtherBI>
62 TransformIterator(const TransformIterator<OtherBI, Function>& other)
63 : data_(other.base(), other.GetFunction()) {
64 }
65
66 TransformIterator& operator++() {
67 ++data_.base_;
68 return *this;
69 }
70
71 TransformIterator operator++(int) {
72 TransformIterator tmp(*this);
73 ++*this;
74 return tmp;
75 }
76
77 TransformIterator& operator--() {
android-t13d2c5b22022-10-12 13:43:18 +080078 static_assert(std::is_base_of_v<std::bidirectional_iterator_tag,
79 typename std::iterator_traits<BaseIterator>::iterator_category>,
80 "BaseIterator must be bidirectional iterator to use operator--()");
Martin Stjernholmc15e7e42020-12-02 22:50:53 +000081 --data_.base_;
82 return *this;
83 }
84
85 TransformIterator operator--(int) {
86 TransformIterator tmp(*this);
87 --*this;
88 return tmp;
89 }
90
91 reference operator*() const {
92 return GetFunction()(*base());
93 }
94
95 reference operator[](difference_type n) const {
android-t13d2c5b22022-10-12 13:43:18 +080096 static_assert(std::is_base_of_v<std::random_access_iterator_tag,
97 typename std::iterator_traits<BaseIterator>::iterator_category>,
98 "BaseIterator must be random access iterator to use operator[]");
Martin Stjernholmc15e7e42020-12-02 22:50:53 +000099 return GetFunction()(base()[n]);
100 }
101
102 TransformIterator operator+(difference_type n) const {
android-t13d2c5b22022-10-12 13:43:18 +0800103 static_assert(std::is_base_of_v<std::random_access_iterator_tag,
104 typename std::iterator_traits<BaseIterator>::iterator_category>,
105 "BaseIterator must be random access iterator to use operator+");
Martin Stjernholmc15e7e42020-12-02 22:50:53 +0000106 return TransformIterator(base() + n, GetFunction());
107 }
108
109 TransformIterator operator-(difference_type n) const {
android-t13d2c5b22022-10-12 13:43:18 +0800110 static_assert(std::is_base_of_v<std::random_access_iterator_tag,
111 typename std::iterator_traits<BaseIterator>::iterator_category>,
112 "BaseIterator must be random access iterator to use operator-");
Martin Stjernholmc15e7e42020-12-02 22:50:53 +0000113 return TransformIterator(base() - n, GetFunction());
114 }
115
116 difference_type operator-(const TransformIterator& other) const {
android-t13d2c5b22022-10-12 13:43:18 +0800117 static_assert(std::is_base_of_v<std::random_access_iterator_tag,
118 typename std::iterator_traits<BaseIterator>::iterator_category>,
119 "BaseIterator must be random access iterator to use operator-");
Martin Stjernholmc15e7e42020-12-02 22:50:53 +0000120 return base() - other.base();
121 }
122
123 // Retrieve the base iterator.
124 BaseIterator base() const {
125 return data_.base_;
126 }
127
128 // Retrieve the transformation function.
129 const Function& GetFunction() const {
130 return static_cast<const Function&>(data_);
131 }
132
133 private:
134 // Allow EBO for state-less Function.
135 struct Data : Function {
136 public:
137 Data(BaseIterator base, Function fn) : Function(fn), base_(base) { }
138
139 BaseIterator base_;
140 };
141
142 Data data_;
143};
144
145template <typename BaseIterator1, typename BaseIterator2, typename Function>
146bool operator==(const TransformIterator<BaseIterator1, Function>& lhs,
147 const TransformIterator<BaseIterator2, Function>& rhs) {
148 return lhs.base() == rhs.base();
149}
150
151template <typename BaseIterator1, typename BaseIterator2, typename Function>
152bool operator!=(const TransformIterator<BaseIterator1, Function>& lhs,
153 const TransformIterator<BaseIterator2, Function>& rhs) {
154 return !(lhs == rhs);
155}
156
157template <typename BaseIterator, typename Function>
158TransformIterator<BaseIterator, Function> MakeTransformIterator(BaseIterator base, Function f) {
159 return TransformIterator<BaseIterator, Function>(base, f);
160}
161
162template <typename BaseRange, typename Function>
163auto MakeTransformRange(BaseRange& range, Function f) {
164 return MakeIterationRange(MakeTransformIterator(range.begin(), f),
165 MakeTransformIterator(range.end(), f));
166}
167
168} // namespace art
169
170#endif // ART_LIBARTBASE_BASE_TRANSFORM_ITERATOR_H_