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