| /* |
| * 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_ARRAY_REF_H_ |
| #define ART_LIBARTBASE_BASE_TRANSFORM_ARRAY_REF_H_ |
| |
| #include <type_traits> |
| |
| #include "array_ref.h" |
| #include "transform_iterator.h" |
| |
| namespace art { |
| |
| /** |
| * @brief An ArrayRef<> wrapper that uses a transformation function for element access. |
| */ |
| template <typename BaseType, typename Function> |
| class TransformArrayRef { |
| private: |
| using Iter = TransformIterator<typename ArrayRef<BaseType>::iterator, Function>; |
| |
| // The Function may take a non-const reference, so const_iterator may not exist. |
| using FallbackConstIter = std::iterator<std::random_access_iterator_tag, void, void, void, void>; |
| using PreferredConstIter = |
| TransformIterator<typename ArrayRef<BaseType>::const_iterator, Function>; |
| template <typename F, typename = std::result_of_t<F(const BaseType&)>> |
| static PreferredConstIter ConstIterHelper(int&); |
| template <typename F> |
| static FallbackConstIter ConstIterHelper(const int&); |
| |
| using ConstIter = decltype(ConstIterHelper<Function>(*reinterpret_cast<int*>(0))); |
| |
| public: |
| using value_type = typename Iter::value_type; |
| using reference = typename Iter::reference; |
| using const_reference = typename ConstIter::reference; |
| using pointer = typename Iter::pointer; |
| using const_pointer = typename ConstIter::pointer; |
| using iterator = Iter; |
| using const_iterator = |
| std::conditional_t<std::is_same_v<ConstIter, FallbackConstIter>, void, ConstIter>; |
| using reverse_iterator = std::reverse_iterator<Iter>; |
| using const_reverse_iterator = std::conditional_t<std::is_same_v<ConstIter, FallbackConstIter>, |
| void, |
| std::reverse_iterator<ConstIter>>; |
| using difference_type = typename ArrayRef<BaseType>::difference_type; |
| using size_type = typename ArrayRef<BaseType>::size_type; |
| |
| // Constructors. |
| |
| TransformArrayRef(const TransformArrayRef& other) = default; |
| |
| template <typename OtherBT> |
| TransformArrayRef(const ArrayRef<OtherBT>& base, Function fn) |
| : data_(base, fn) { } |
| |
| template <typename OtherBT, |
| typename = std::enable_if_t<std::is_same_v<BaseType, const OtherBT>>> |
| TransformArrayRef(const TransformArrayRef<OtherBT, Function>& other) |
| : TransformArrayRef(other.base(), other.GetFunction()) { } |
| |
| // Assignment operators. |
| |
| TransformArrayRef& operator=(const TransformArrayRef& other) = default; |
| |
| template <typename OtherBT, |
| typename = std::enable_if_t<std::is_same_v<BaseType, const OtherBT>>> |
| TransformArrayRef& operator=(const TransformArrayRef<OtherBT, Function>& other) { |
| return *this = TransformArrayRef(other.base(), other.GetFunction()); |
| } |
| |
| // Destructor. |
| ~TransformArrayRef() = default; |
| |
| // Iterators. |
| iterator begin() { return MakeIterator(base().begin()); } |
| const_iterator begin() const { return MakeIterator(base().cbegin()); } |
| const_iterator cbegin() const { return MakeIterator(base().cbegin()); } |
| iterator end() { return MakeIterator(base().end()); } |
| const_iterator end() const { return MakeIterator(base().cend()); } |
| const_iterator cend() const { return MakeIterator(base().cend()); } |
| reverse_iterator rbegin() { return reverse_iterator(end()); } |
| const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } |
| const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); } |
| reverse_iterator rend() { return reverse_iterator(begin()); } |
| const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } |
| const_reverse_iterator crend() const { return const_reverse_iterator(cbegin()); } |
| |
| // Size. |
| size_type size() const { return base().size(); } |
| bool empty() const { return base().empty(); } |
| |
| // Element access. NOTE: Not providing data(). |
| |
| reference operator[](size_type n) { return GetFunction()(base()[n]); } |
| const_reference operator[](size_type n) const { return GetFunction()(base()[n]); } |
| |
| reference front() { return GetFunction()(base().front()); } |
| const_reference front() const { return GetFunction()(base().front()); } |
| |
| reference back() { return GetFunction()(base().back()); } |
| const_reference back() const { return GetFunction()(base().back()); } |
| |
| TransformArrayRef SubArray(size_type pos) { |
| return TransformArrayRef(base().subarray(pos), GetFunction()); |
| } |
| TransformArrayRef SubArray(size_type pos) const { |
| return TransformArrayRef(base().subarray(pos), GetFunction()); |
| } |
| TransformArrayRef SubArray(size_type pos, size_type length) const { |
| return TransformArrayRef(base().subarray(pos, length), GetFunction()); |
| } |
| |
| // Retrieve the base ArrayRef<>. |
| ArrayRef<BaseType> base() { |
| return data_.base_; |
| } |
| ArrayRef<const BaseType> base() const { |
| return ArrayRef<const BaseType>(data_.base_); |
| } |
| |
| private: |
| // Allow EBO for state-less Function. |
| struct Data : Function { |
| public: |
| Data(ArrayRef<BaseType> base, Function fn) : Function(fn), base_(base) { } |
| |
| ArrayRef<BaseType> base_; |
| }; |
| |
| const Function& GetFunction() const { |
| return static_cast<const Function&>(data_); |
| } |
| |
| template <typename BaseIterator> |
| auto MakeIterator(BaseIterator base) const { |
| return MakeTransformIterator(base, GetFunction()); |
| } |
| |
| Data data_; |
| |
| template <typename OtherBT, typename OtherFunction> |
| friend class TransformArrayRef; |
| }; |
| |
| template <typename BaseType, typename Function> |
| bool operator==(const TransformArrayRef<BaseType, Function>& lhs, |
| const TransformArrayRef<BaseType, Function>& rhs) { |
| return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); |
| } |
| |
| template <typename BaseType, typename Function> |
| bool operator!=(const TransformArrayRef<BaseType, Function>& lhs, |
| const TransformArrayRef<BaseType, Function>& rhs) { |
| return !(lhs == rhs); |
| } |
| |
| template <typename ValueType, typename Function> |
| TransformArrayRef<ValueType, Function> MakeTransformArrayRef( |
| ArrayRef<ValueType> container, Function f) { |
| return TransformArrayRef<ValueType, Function>(container, f); |
| } |
| |
| template <typename Container, typename Function> |
| TransformArrayRef<typename Container::value_type, Function> MakeTransformArrayRef( |
| Container& container, Function f) { |
| return TransformArrayRef<typename Container::value_type, Function>( |
| ArrayRef<typename Container::value_type>(container.data(), container.size()), f); |
| } |
| |
| template <typename Container, typename Function> |
| TransformArrayRef<const typename Container::value_type, Function> MakeTransformArrayRef( |
| const Container& container, Function f) { |
| return TransformArrayRef<const typename Container::value_type, Function>( |
| ArrayRef<const typename Container::value_type>(container.data(), container.size()), f); |
| } |
| |
| } // namespace art |
| |
| #endif // ART_LIBARTBASE_BASE_TRANSFORM_ARRAY_REF_H_ |