/* * 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 #include "array_ref.h" #include "transform_iterator.h" namespace art { /** * @brief An ArrayRef<> wrapper that uses a transformation function for element access. */ template class TransformArrayRef { private: using Iter = TransformIterator::iterator, Function>; // The Function may take a non-const reference, so const_iterator may not exist. using FallbackConstIter = std::iterator; using PreferredConstIter = TransformIterator::const_iterator, Function>; template ::type> static PreferredConstIter ConstIterHelper(int&); template static FallbackConstIter ConstIterHelper(const int&); using ConstIter = decltype(ConstIterHelper(*reinterpret_cast(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 = typename std::conditional< std::is_same::value, void, ConstIter>::type; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = typename std::conditional< std::is_same::value, void, std::reverse_iterator>::type; using difference_type = typename ArrayRef::difference_type; using size_type = typename ArrayRef::size_type; // Constructors. TransformArrayRef(const TransformArrayRef& other) = default; template TransformArrayRef(const ArrayRef& base, Function fn) : data_(base, fn) { } template ::value>::type> TransformArrayRef(const TransformArrayRef& other) : TransformArrayRef(other.base(), other.GetFunction()) { } // Assignment operators. TransformArrayRef& operator=(const TransformArrayRef& other) = default; template ::value>::type> TransformArrayRef& operator=(const TransformArrayRef& 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 base() { return data_.base_; } ArrayRef base() const { return ArrayRef(data_.base_); } private: // Allow EBO for state-less Function. struct Data : Function { public: Data(ArrayRef base, Function fn) : Function(fn), base_(base) { } ArrayRef base_; }; const Function& GetFunction() const { return static_cast(data_); } template auto MakeIterator(BaseIterator base) const { return MakeTransformIterator(base, GetFunction()); } Data data_; template friend class TransformArrayRef; }; template bool operator==(const TransformArrayRef& lhs, const TransformArrayRef& rhs) { return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); } template bool operator!=(const TransformArrayRef& lhs, const TransformArrayRef& rhs) { return !(lhs == rhs); } template TransformArrayRef MakeTransformArrayRef( ArrayRef container, Function f) { return TransformArrayRef(container, f); } template TransformArrayRef MakeTransformArrayRef( Container& container, Function f) { return TransformArrayRef( ArrayRef(container.data(), container.size()), f); } template TransformArrayRef MakeTransformArrayRef( const Container& container, Function f) { return TransformArrayRef( ArrayRef(container.data(), container.size()), f); } } // namespace art #endif // ART_LIBARTBASE_BASE_TRANSFORM_ARRAY_REF_H_