Home | History | Annotate | Download | only in base
      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_ARRAY_REF_H_
     18 #define ART_LIBARTBASE_BASE_TRANSFORM_ARRAY_REF_H_
     19 
     20 #include <type_traits>
     21 
     22 #include "base/array_ref.h"
     23 #include "base/transform_iterator.h"
     24 
     25 namespace art {
     26 
     27 /**
     28  * @brief An ArrayRef<> wrapper that uses a transformation function for element access.
     29  */
     30 template <typename BaseType, typename Function>
     31 class TransformArrayRef {
     32  private:
     33   using Iter = TransformIterator<typename ArrayRef<BaseType>::iterator, Function>;
     34 
     35   // The Function may take a non-const reference, so const_iterator may not exist.
     36   using FallbackConstIter = std::iterator<std::random_access_iterator_tag, void, void, void, void>;
     37   using PreferredConstIter =
     38       TransformIterator<typename ArrayRef<BaseType>::const_iterator, Function>;
     39   template <typename F, typename = typename std::result_of<F(const BaseType&)>::type>
     40   static PreferredConstIter ConstIterHelper(int&);
     41   template <typename F>
     42   static FallbackConstIter ConstIterHelper(const int&);
     43 
     44   using ConstIter = decltype(ConstIterHelper<Function>(*reinterpret_cast<int*>(0)));
     45 
     46  public:
     47   using value_type = typename Iter::value_type;
     48   using reference = typename Iter::reference;
     49   using const_reference = typename ConstIter::reference;
     50   using pointer = typename Iter::pointer;
     51   using const_pointer = typename ConstIter::pointer;
     52   using iterator = Iter;
     53   using const_iterator = typename std::conditional<
     54       std::is_same<ConstIter, FallbackConstIter>::value,
     55       void,
     56       ConstIter>::type;
     57   using reverse_iterator = std::reverse_iterator<Iter>;
     58   using const_reverse_iterator = typename std::conditional<
     59       std::is_same<ConstIter, FallbackConstIter>::value,
     60       void,
     61       std::reverse_iterator<ConstIter>>::type;
     62   using difference_type = typename ArrayRef<BaseType>::difference_type;
     63   using size_type = typename ArrayRef<BaseType>::size_type;
     64 
     65   // Constructors.
     66 
     67   TransformArrayRef(const TransformArrayRef& other) = default;
     68 
     69   template <typename OtherBT>
     70   TransformArrayRef(const ArrayRef<OtherBT>& base, Function fn)
     71       : data_(base, fn) { }
     72 
     73   template <typename OtherBT,
     74             typename = typename std::enable_if<std::is_same<BaseType, const OtherBT>::value>::type>
     75   TransformArrayRef(const TransformArrayRef<OtherBT, Function>& other)
     76       : TransformArrayRef(other.base(), other.GetFunction()) { }
     77 
     78   // Assignment operators.
     79 
     80   TransformArrayRef& operator=(const TransformArrayRef& other) = default;
     81 
     82   template <typename OtherBT,
     83             typename = typename std::enable_if<std::is_same<BaseType, const OtherBT>::value>::type>
     84   TransformArrayRef& operator=(const TransformArrayRef<OtherBT, Function>& other) {
     85     return *this = TransformArrayRef(other.base(), other.GetFunction());
     86   }
     87 
     88   // Destructor.
     89   ~TransformArrayRef() = default;
     90 
     91   // Iterators.
     92   iterator begin() { return MakeIterator(base().begin()); }
     93   const_iterator begin() const { return MakeIterator(base().cbegin()); }
     94   const_iterator cbegin() const { return MakeIterator(base().cbegin()); }
     95   iterator end() { return MakeIterator(base().end()); }
     96   const_iterator end() const { MakeIterator(base().cend()); }
     97   const_iterator cend() const { return MakeIterator(base().cend()); }
     98   reverse_iterator rbegin() { return reverse_iterator(end()); }
     99   const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
    100   const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); }
    101   reverse_iterator rend() { return reverse_iterator(begin()); }
    102   const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
    103   const_reverse_iterator crend() const { return const_reverse_iterator(cbegin()); }
    104 
    105   // Size.
    106   size_type size() const { return base().size(); }
    107   bool empty() const { return base().empty(); }
    108 
    109   // Element access. NOTE: Not providing data().
    110 
    111   reference operator[](size_type n) { return GetFunction()(base()[n]); }
    112   const_reference operator[](size_type n) const { return GetFunction()(base()[n]); }
    113 
    114   reference front() { return GetFunction()(base().front()); }
    115   const_reference front() const { return GetFunction()(base().front()); }
    116 
    117   reference back() { return GetFunction()(base().back()); }
    118   const_reference back() const { return GetFunction()(base().back()); }
    119 
    120   TransformArrayRef SubArray(size_type pos) {
    121     return TransformArrayRef(base().subarray(pos), GetFunction());
    122   }
    123   TransformArrayRef SubArray(size_type pos) const {
    124     return TransformArrayRef(base().subarray(pos), GetFunction());
    125   }
    126   TransformArrayRef SubArray(size_type pos, size_type length) const {
    127     return TransformArrayRef(base().subarray(pos, length), GetFunction());
    128   }
    129 
    130   // Retrieve the base ArrayRef<>.
    131   ArrayRef<BaseType> base() {
    132     return data_.base_;
    133   }
    134   ArrayRef<const BaseType> base() const {
    135     return ArrayRef<const BaseType>(data_.base_);
    136   }
    137 
    138  private:
    139   // Allow EBO for state-less Function.
    140   struct Data : Function {
    141    public:
    142     Data(ArrayRef<BaseType> base, Function fn) : Function(fn), base_(base) { }
    143 
    144     ArrayRef<BaseType> base_;
    145   };
    146 
    147   const Function& GetFunction() const {
    148     return static_cast<const Function&>(data_);
    149   }
    150 
    151   template <typename BaseIterator>
    152   auto MakeIterator(BaseIterator base) const {
    153     return MakeTransformIterator(base, GetFunction());
    154   }
    155 
    156   Data data_;
    157 
    158   template <typename OtherBT, typename OtherFunction>
    159   friend class TransformArrayRef;
    160 };
    161 
    162 template <typename BaseType, typename Function>
    163 bool operator==(const TransformArrayRef<BaseType, Function>& lhs,
    164                 const TransformArrayRef<BaseType, Function>& rhs) {
    165   return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
    166 }
    167 
    168 template <typename BaseType, typename Function>
    169 bool operator!=(const TransformArrayRef<BaseType, Function>& lhs,
    170                 const TransformArrayRef<BaseType, Function>& rhs) {
    171   return !(lhs == rhs);
    172 }
    173 
    174 template <typename ValueType, typename Function>
    175 TransformArrayRef<ValueType, Function> MakeTransformArrayRef(
    176     ArrayRef<ValueType> container, Function f) {
    177   return TransformArrayRef<ValueType, Function>(container, f);
    178 }
    179 
    180 template <typename Container, typename Function>
    181 TransformArrayRef<typename Container::value_type, Function> MakeTransformArrayRef(
    182     Container& container, Function f) {
    183   return TransformArrayRef<typename Container::value_type, Function>(
    184       ArrayRef<typename Container::value_type>(container.data(), container.size()), f);
    185 }
    186 
    187 template <typename Container, typename Function>
    188 TransformArrayRef<const typename Container::value_type, Function> MakeTransformArrayRef(
    189     const Container& container, Function f) {
    190   return TransformArrayRef<const typename Container::value_type, Function>(
    191       ArrayRef<const typename Container::value_type>(container.data(), container.size()), f);
    192 }
    193 
    194 }  // namespace art
    195 
    196 #endif  // ART_LIBARTBASE_BASE_TRANSFORM_ARRAY_REF_H_
    197