/* * Copyright (C) 2015 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_ARRAY_SLICE_H_ #define ART_LIBARTBASE_BASE_ARRAY_SLICE_H_ #include #include "bit_utils.h" #include "casts.h" #include "iteration_range.h" #include "length_prefixed_array.h" #include "stride_iterator.h" namespace art { // An ArraySlice is an abstraction over an array or a part of an array of a particular type. It does // bounds checking and can be made from several common array-like structures in Art. template class ArraySlice { public: using value_type = T; using reference = T&; using const_reference = const T&; using pointer = T*; using const_pointer = const T*; using iterator = StrideIterator; using const_iterator = StrideIterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using difference_type = ptrdiff_t; using size_type = size_t; // Create an empty array slice. ArraySlice() : array_(nullptr), size_(0), element_size_(0) {} // Create an array slice of the first 'length' elements of the array, with each element being // element_size bytes long. ArraySlice(T* array, size_t length, size_t element_size = sizeof(T)) : array_(array), size_(dchecked_integral_cast(length)), element_size_(element_size) { DCHECK(array_ != nullptr || length == 0); } ArraySlice(LengthPrefixedArray* lpa, size_t element_size = sizeof(T), size_t alignment = alignof(T)) : ArraySlice( lpa != nullptr && lpa->size() != 0 ? &lpa->At(0, element_size, alignment) : nullptr, lpa != nullptr ? lpa->size() : 0, element_size) {} ArraySlice(const ArraySlice&) = default; ArraySlice(ArraySlice&&) noexcept = default; ArraySlice& operator=(const ArraySlice&) = default; ArraySlice& operator=(ArraySlice&&) noexcept = default; // Iterators. iterator begin() { return iterator(&AtUnchecked(0), element_size_); } const_iterator begin() const { return const_iterator(&AtUnchecked(0), element_size_); } const_iterator cbegin() const { return const_iterator(&AtUnchecked(0), element_size_); } StrideIterator end() { return StrideIterator(&AtUnchecked(size_), element_size_); } const_iterator end() const { return const_iterator(&AtUnchecked(size_), element_size_); } const_iterator cend() const { return const_iterator(&AtUnchecked(size_), element_size_); } 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 size_; } bool empty() const { return size() == 0u; } // Element access. NOTE: Not providing at() and data(). reference operator[](size_t index) { DCHECK_LT(index, size_); return AtUnchecked(index); } const_reference operator[](size_t index) const { DCHECK_LT(index, size_); return AtUnchecked(index); } reference front() { DCHECK(!empty()); return (*this)[0]; } const_reference front() const { DCHECK(!empty()); return (*this)[0]; } reference back() { DCHECK(!empty()); return (*this)[size_ - 1u]; } const_reference back() const { DCHECK(!empty()); return (*this)[size_ - 1u]; } ArraySlice SubArray(size_type pos) { return SubArray(pos, size() - pos); } ArraySlice SubArray(size_type pos) const { return SubArray(pos, size() - pos); } ArraySlice SubArray(size_type pos, size_type length) { DCHECK_LE(pos, size()); DCHECK_LE(length, size() - pos); return ArraySlice(&AtUnchecked(pos), length, element_size_); } ArraySlice SubArray(size_type pos, size_type length) const { DCHECK_LE(pos, size()); DCHECK_LE(length, size() - pos); return ArraySlice(&AtUnchecked(pos), length, element_size_); } size_t ElementSize() const { return element_size_; } bool Contains(const T* element) const { return &AtUnchecked(0) <= element && element < &AtUnchecked(size_) && ((reinterpret_cast(element) - reinterpret_cast(&AtUnchecked(0))) % element_size_) == 0; } size_t OffsetOf(const T* element) const { DCHECK(Contains(element)); // Since it's possible element_size_ != sizeof(T) we cannot just use pointer arithmatic uintptr_t base_ptr = reinterpret_cast(&AtUnchecked(0)); uintptr_t obj_ptr = reinterpret_cast(element); return (obj_ptr - base_ptr) / element_size_; } private: T& AtUnchecked(size_t index) { return *reinterpret_cast(reinterpret_cast(array_) + index * element_size_); } const T& AtUnchecked(size_t index) const { return *reinterpret_cast(reinterpret_cast(array_) + index * element_size_); } T* array_; size_t size_; size_t element_size_; }; template std::ostream& operator<<(std::ostream& os, const ArraySlice& ts) { bool first = true; os << "["; for (const T& t : ts) { if (!first) { os << ", "; } first = false; os << t; } os << "]"; return os; } } // namespace art #endif // ART_LIBARTBASE_BASE_ARRAY_SLICE_H_