1 /* 2 * Copyright (C) 2015 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_ARRAY_SLICE_H_ 18 #define ART_LIBARTBASE_BASE_ARRAY_SLICE_H_ 19 20 #include <ostream> 21 #include "bit_utils.h" 22 #include "casts.h" 23 #include "iteration_range.h" 24 #include "length_prefixed_array.h" 25 #include "stride_iterator.h" 26 27 namespace art { 28 29 // An ArraySlice is an abstraction over an array or a part of an array of a particular type. It does 30 // bounds checking and can be made from several common array-like structures in Art. 31 template <typename T> 32 class ArraySlice { 33 public: 34 using value_type = T; 35 using reference = T&; 36 using const_reference = const T&; 37 using pointer = T*; 38 using const_pointer = const T*; 39 using iterator = StrideIterator<T>; 40 using const_iterator = StrideIterator<const T>; 41 using reverse_iterator = std::reverse_iterator<iterator>; 42 using const_reverse_iterator = std::reverse_iterator<const_iterator>; 43 using difference_type = ptrdiff_t; 44 using size_type = size_t; 45 46 // Create an empty array slice. ArraySlice()47 ArraySlice() : array_(nullptr), size_(0), element_size_(0) {} 48 49 // Create an array slice of the first 'length' elements of the array, with each element being 50 // element_size bytes long. 51 ArraySlice(T* array, 52 size_t length, 53 size_t element_size = sizeof(T)) array_(array)54 : array_(array), 55 size_(dchecked_integral_cast<uint32_t>(length)), 56 element_size_(element_size) { 57 DCHECK(array_ != nullptr || length == 0); 58 } 59 60 ArraySlice(LengthPrefixedArray<T>* lpa, 61 size_t element_size = sizeof(T), 62 size_t alignment = alignof(T)) 63 : ArraySlice( 64 lpa != nullptr && lpa->size() != 0 ? &lpa->At(0, element_size, alignment) : nullptr, 65 lpa != nullptr ? lpa->size() : 0, 66 element_size) {} 67 ArraySlice(const ArraySlice<T>&) = default; 68 ArraySlice(ArraySlice<T>&&) = default; 69 ArraySlice<T>& operator=(const ArraySlice<T>&) = default; 70 ArraySlice<T>& operator=(ArraySlice<T>&&) = default; 71 72 // Iterators. begin()73 iterator begin() { return iterator(&AtUnchecked(0), element_size_); } begin()74 const_iterator begin() const { return const_iterator(&AtUnchecked(0), element_size_); } cbegin()75 const_iterator cbegin() const { return const_iterator(&AtUnchecked(0), element_size_); } end()76 StrideIterator<T> end() { return StrideIterator<T>(&AtUnchecked(size_), element_size_); } end()77 const_iterator end() const { return const_iterator(&AtUnchecked(size_), element_size_); } cend()78 const_iterator cend() const { return const_iterator(&AtUnchecked(size_), element_size_); } rbegin()79 reverse_iterator rbegin() { return reverse_iterator(end()); } rbegin()80 const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } crbegin()81 const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); } rend()82 reverse_iterator rend() { return reverse_iterator(begin()); } rend()83 const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } crend()84 const_reverse_iterator crend() const { return const_reverse_iterator(cbegin()); } 85 86 // Size. size()87 size_type size() const { return size_; } empty()88 bool empty() const { return size() == 0u; } 89 90 // Element access. NOTE: Not providing at() and data(). 91 92 reference operator[](size_t index) { 93 DCHECK_LT(index, size_); 94 return AtUnchecked(index); 95 } 96 97 const_reference operator[](size_t index) const { 98 DCHECK_LT(index, size_); 99 return AtUnchecked(index); 100 } 101 front()102 reference front() { 103 DCHECK(!empty()); 104 return (*this)[0]; 105 } 106 front()107 const_reference front() const { 108 DCHECK(!empty()); 109 return (*this)[0]; 110 } 111 back()112 reference back() { 113 DCHECK(!empty()); 114 return (*this)[size_ - 1u]; 115 } 116 back()117 const_reference back() const { 118 DCHECK(!empty()); 119 return (*this)[size_ - 1u]; 120 } 121 SubArray(size_type pos)122 ArraySlice<T> SubArray(size_type pos) { 123 return SubArray(pos, size() - pos); 124 } 125 SubArray(size_type pos)126 ArraySlice<const T> SubArray(size_type pos) const { 127 return SubArray(pos, size() - pos); 128 } 129 SubArray(size_type pos,size_type length)130 ArraySlice<T> SubArray(size_type pos, size_type length) { 131 DCHECK_LE(pos, size()); 132 DCHECK_LE(length, size() - pos); 133 return ArraySlice<T>(&AtUnchecked(pos), length, element_size_); 134 } 135 SubArray(size_type pos,size_type length)136 ArraySlice<const T> SubArray(size_type pos, size_type length) const { 137 DCHECK_LE(pos, size()); 138 DCHECK_LE(length, size() - pos); 139 return ArraySlice<const T>(&AtUnchecked(pos), length, element_size_); 140 } 141 ElementSize()142 size_t ElementSize() const { 143 return element_size_; 144 } 145 Contains(const T * element)146 bool Contains(const T* element) const { 147 return &AtUnchecked(0) <= element && element < &AtUnchecked(size_) && 148 ((reinterpret_cast<uintptr_t>(element) - 149 reinterpret_cast<uintptr_t>(&AtUnchecked(0))) % element_size_) == 0; 150 } 151 OffsetOf(const T * element)152 size_t OffsetOf(const T* element) const { 153 DCHECK(Contains(element)); 154 // Since it's possible element_size_ != sizeof(T) we cannot just use pointer arithmatic 155 uintptr_t base_ptr = reinterpret_cast<uintptr_t>(&AtUnchecked(0)); 156 uintptr_t obj_ptr = reinterpret_cast<uintptr_t>(element); 157 return (obj_ptr - base_ptr) / element_size_; 158 } 159 160 private: AtUnchecked(size_t index)161 T& AtUnchecked(size_t index) { 162 return *reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(array_) + index * element_size_); 163 } 164 AtUnchecked(size_t index)165 const T& AtUnchecked(size_t index) const { 166 return *reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(array_) + index * element_size_); 167 } 168 169 T* array_; 170 size_t size_; 171 size_t element_size_; 172 }; 173 174 template<typename T> 175 std::ostream& operator<<(std::ostream& os, const ArraySlice<T>& ts) { 176 bool first = true; 177 os << "["; 178 for (const T& t : ts) { 179 if (!first) { os << ", "; } 180 first = false; 181 os << t; 182 } 183 os << "]"; 184 return os; 185 } 186 187 } // namespace art 188 189 #endif // ART_LIBARTBASE_BASE_ARRAY_SLICE_H_ 190