• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 InputType = typename std::iterator_traits<BaseIterator>::reference;
47   using ResultType = std::result_of_t<Function(InputType)>;
48 
49  public:
50   using iterator_category = typename std::iterator_traits<BaseIterator>::iterator_category;
51   using value_type = std::remove_const_t<std::remove_reference_t<ResultType>>;
52   using difference_type = typename std::iterator_traits<BaseIterator>::difference_type;
53   using pointer = std::conditional_t<std::is_reference_v<ResultType>,
54                                      std::add_pointer_t<std::remove_reference_t<ResultType>>,
55                                      TransformIterator>;
56   using reference = ResultType;
57 
TransformIterator(BaseIterator base,Function fn)58   TransformIterator(BaseIterator base, Function fn)
59       : data_(base, fn) { }
60 
61   template <typename OtherBI>
TransformIterator(const TransformIterator<OtherBI,Function> & other)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--() {
78     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--()");
81     --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 {
96     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[]");
99     return GetFunction()(base()[n]);
100   }
101 
102   TransformIterator operator+(difference_type n) const {
103     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+");
106     return TransformIterator(base() + n, GetFunction());
107   }
108 
109   TransformIterator operator-(difference_type n) const {
110     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-");
113     return TransformIterator(base() - n, GetFunction());
114   }
115 
116   difference_type operator-(const TransformIterator& other) const {
117     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-");
120     return base() - other.base();
121   }
122 
123   // Retrieve the base iterator.
base()124   BaseIterator base() const {
125     return data_.base_;
126   }
127 
128   // Retrieve the transformation function.
GetFunction()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:
DataData137     Data(BaseIterator base, Function fn) : Function(fn), base_(base) { }
138 
139     BaseIterator base_;
140   };
141 
142   Data data_;
143 };
144 
145 template <typename BaseIterator1, typename BaseIterator2, typename Function>
146 bool operator==(const TransformIterator<BaseIterator1, Function>& lhs,
147                 const TransformIterator<BaseIterator2, Function>& rhs) {
148   return lhs.base() == rhs.base();
149 }
150 
151 template <typename BaseIterator1, typename BaseIterator2, typename Function>
152 bool operator!=(const TransformIterator<BaseIterator1, Function>& lhs,
153                 const TransformIterator<BaseIterator2, Function>& rhs) {
154   return !(lhs == rhs);
155 }
156 
157 template <typename BaseIterator, typename Function>
MakeTransformIterator(BaseIterator base,Function f)158 TransformIterator<BaseIterator, Function> MakeTransformIterator(BaseIterator base, Function f) {
159   return TransformIterator<BaseIterator, Function>(base, f);
160 }
161 
162 template <typename BaseRange, typename Function>
MakeTransformRange(BaseRange && range,Function f)163 auto 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_
171