You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
6.1 KiB
179 lines
6.1 KiB
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef ART_LIBARTBASE_BASE_TRANSFORM_ITERATOR_H_
|
|
#define ART_LIBARTBASE_BASE_TRANSFORM_ITERATOR_H_
|
|
|
|
#include <iterator>
|
|
#include <type_traits>
|
|
|
|
#include "iteration_range.h"
|
|
|
|
namespace art {
|
|
|
|
// The transform iterator transforms values from the base iterator with a given
|
|
// transformation function. It can serve as a replacement for std::transform(), i.e.
|
|
// std::copy(MakeTransformIterator(begin, f), MakeTransformIterator(end, f), out)
|
|
// is equivalent to
|
|
// std::transform(begin, end, f)
|
|
// If the function returns an l-value reference or a wrapper that supports assignment,
|
|
// the TransformIterator can be used also as an output iterator, i.e.
|
|
// std::copy(begin, end, MakeTransformIterator(out, f))
|
|
// is equivalent to
|
|
// for (auto it = begin; it != end; ++it) {
|
|
// f(*out++) = *it;
|
|
// }
|
|
template <typename BaseIterator, typename Function>
|
|
class TransformIterator {
|
|
private:
|
|
static_assert(std::is_base_of<
|
|
std::input_iterator_tag,
|
|
typename std::iterator_traits<BaseIterator>::iterator_category>::value,
|
|
"Transform iterator base must be an input iterator.");
|
|
|
|
using InputType = typename std::iterator_traits<BaseIterator>::reference;
|
|
using ResultType = typename std::result_of<Function(InputType)>::type;
|
|
|
|
public:
|
|
using iterator_category = typename std::iterator_traits<BaseIterator>::iterator_category;
|
|
using value_type =
|
|
typename std::remove_const<typename std::remove_reference<ResultType>::type>::type;
|
|
using difference_type = typename std::iterator_traits<BaseIterator>::difference_type;
|
|
using pointer = typename std::conditional<
|
|
std::is_reference<ResultType>::value,
|
|
typename std::add_pointer<typename std::remove_reference<ResultType>::type>::type,
|
|
TransformIterator>::type;
|
|
using reference = ResultType;
|
|
|
|
TransformIterator(BaseIterator base, Function fn)
|
|
: data_(base, fn) { }
|
|
|
|
template <typename OtherBI>
|
|
TransformIterator(const TransformIterator<OtherBI, Function>& other)
|
|
: data_(other.base(), other.GetFunction()) {
|
|
}
|
|
|
|
TransformIterator& operator++() {
|
|
++data_.base_;
|
|
return *this;
|
|
}
|
|
|
|
TransformIterator operator++(int) {
|
|
TransformIterator tmp(*this);
|
|
++*this;
|
|
return tmp;
|
|
}
|
|
|
|
TransformIterator& operator--() {
|
|
static_assert(
|
|
std::is_base_of<std::bidirectional_iterator_tag,
|
|
typename std::iterator_traits<BaseIterator>::iterator_category>::value,
|
|
"BaseIterator must be bidirectional iterator to use operator--()");
|
|
--data_.base_;
|
|
return *this;
|
|
}
|
|
|
|
TransformIterator operator--(int) {
|
|
TransformIterator tmp(*this);
|
|
--*this;
|
|
return tmp;
|
|
}
|
|
|
|
reference operator*() const {
|
|
return GetFunction()(*base());
|
|
}
|
|
|
|
reference operator[](difference_type n) const {
|
|
static_assert(
|
|
std::is_base_of<std::random_access_iterator_tag,
|
|
typename std::iterator_traits<BaseIterator>::iterator_category>::value,
|
|
"BaseIterator must be random access iterator to use operator[]");
|
|
return GetFunction()(base()[n]);
|
|
}
|
|
|
|
TransformIterator operator+(difference_type n) const {
|
|
static_assert(
|
|
std::is_base_of<std::random_access_iterator_tag,
|
|
typename std::iterator_traits<BaseIterator>::iterator_category>::value,
|
|
"BaseIterator must be random access iterator to use operator+");
|
|
return TransformIterator(base() + n, GetFunction());
|
|
}
|
|
|
|
TransformIterator operator-(difference_type n) const {
|
|
static_assert(
|
|
std::is_base_of<std::random_access_iterator_tag,
|
|
typename std::iterator_traits<BaseIterator>::iterator_category>::value,
|
|
"BaseIterator must be random access iterator to use operator-");
|
|
return TransformIterator(base() - n, GetFunction());
|
|
}
|
|
|
|
difference_type operator-(const TransformIterator& other) const {
|
|
static_assert(
|
|
std::is_base_of<std::random_access_iterator_tag,
|
|
typename std::iterator_traits<BaseIterator>::iterator_category>::value,
|
|
"BaseIterator must be random access iterator to use operator-");
|
|
return base() - other.base();
|
|
}
|
|
|
|
// Retrieve the base iterator.
|
|
BaseIterator base() const {
|
|
return data_.base_;
|
|
}
|
|
|
|
// Retrieve the transformation function.
|
|
const Function& GetFunction() const {
|
|
return static_cast<const Function&>(data_);
|
|
}
|
|
|
|
private:
|
|
// Allow EBO for state-less Function.
|
|
struct Data : Function {
|
|
public:
|
|
Data(BaseIterator base, Function fn) : Function(fn), base_(base) { }
|
|
|
|
BaseIterator base_;
|
|
};
|
|
|
|
Data data_;
|
|
};
|
|
|
|
template <typename BaseIterator1, typename BaseIterator2, typename Function>
|
|
bool operator==(const TransformIterator<BaseIterator1, Function>& lhs,
|
|
const TransformIterator<BaseIterator2, Function>& rhs) {
|
|
return lhs.base() == rhs.base();
|
|
}
|
|
|
|
template <typename BaseIterator1, typename BaseIterator2, typename Function>
|
|
bool operator!=(const TransformIterator<BaseIterator1, Function>& lhs,
|
|
const TransformIterator<BaseIterator2, Function>& rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
template <typename BaseIterator, typename Function>
|
|
TransformIterator<BaseIterator, Function> MakeTransformIterator(BaseIterator base, Function f) {
|
|
return TransformIterator<BaseIterator, Function>(base, f);
|
|
}
|
|
|
|
template <typename BaseRange, typename Function>
|
|
auto MakeTransformRange(BaseRange& range, Function f) {
|
|
return MakeIterationRange(MakeTransformIterator(range.begin(), f),
|
|
MakeTransformIterator(range.end(), f));
|
|
}
|
|
|
|
} // namespace art
|
|
|
|
#endif // ART_LIBARTBASE_BASE_TRANSFORM_ITERATOR_H_
|