/* * 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_LENGTH_PREFIXED_ARRAY_H_ #define ART_LIBARTBASE_BASE_LENGTH_PREFIXED_ARRAY_H_ #include // for offsetof() #include // for memset() #include "bit_utils.h" #include "casts.h" #include "iteration_range.h" #include "stride_iterator.h" namespace art { template class LengthPrefixedArray { public: explicit LengthPrefixedArray(size_t length) : size_(dchecked_integral_cast(length)) {} T& At(size_t index, size_t element_size = sizeof(T), size_t alignment = alignof(T)) { DCHECK_LT(index, size_); return AtUnchecked(index, element_size, alignment); } const T& At(size_t index, size_t element_size = sizeof(T), size_t alignment = alignof(T)) const { DCHECK_LT(index, size_); return AtUnchecked(index, element_size, alignment); } StrideIterator begin(size_t element_size = sizeof(T), size_t alignment = alignof(T)) { return StrideIterator(&AtUnchecked(0, element_size, alignment), element_size); } StrideIterator begin(size_t element_size = sizeof(T), size_t alignment = alignof(T)) const { return StrideIterator(&AtUnchecked(0, element_size, alignment), element_size); } StrideIterator end(size_t element_size = sizeof(T), size_t alignment = alignof(T)) { return StrideIterator(&AtUnchecked(size_, element_size, alignment), element_size); } StrideIterator end(size_t element_size = sizeof(T), size_t alignment = alignof(T)) const { return StrideIterator(&AtUnchecked(size_, element_size, alignment), element_size); } static size_t OffsetOfElement(size_t index, size_t element_size = sizeof(T), size_t alignment = alignof(T)) { DCHECK_ALIGNED_PARAM(element_size, alignment); return RoundUp(offsetof(LengthPrefixedArray, data_), alignment) + index * element_size; } static size_t ComputeSize(size_t num_elements, size_t element_size = sizeof(T), size_t alignment = alignof(T)) { size_t result = OffsetOfElement(num_elements, element_size, alignment); DCHECK_ALIGNED_PARAM(result, alignment); return result; } size_t size() const { return size_; } // Update the length but does not reallocate storage. void SetSize(size_t length) { size_ = dchecked_integral_cast(length); } // Clear the potentially uninitialized padding between the size_ and actual data. void ClearPadding(size_t element_size = sizeof(T), size_t alignment = alignof(T)) { size_t gap_offset = offsetof(LengthPrefixedArray, data_); size_t gap_size = OffsetOfElement(0, element_size, alignment) - gap_offset; memset(reinterpret_cast(this) + gap_offset, 0, gap_size); } private: T& AtUnchecked(size_t index, size_t element_size, size_t alignment) { return *reinterpret_cast( reinterpret_cast(this) + OffsetOfElement(index, element_size, alignment)); } const T& AtUnchecked(size_t index, size_t element_size, size_t alignment) const { return *reinterpret_cast( reinterpret_cast(this) + OffsetOfElement(index, element_size, alignment)); } uint32_t size_; uint8_t data_[0]; }; // Returns empty iteration range if the array is null. template IterationRange> MakeIterationRangeFromLengthPrefixedArray( LengthPrefixedArray* arr, size_t element_size = sizeof(T), size_t alignment = alignof(T)) { return arr != nullptr ? MakeIterationRange(arr->begin(element_size, alignment), arr->end(element_size, alignment)) : MakeEmptyIterationRange(StrideIterator(nullptr, 0)); } } // namespace art #endif // ART_LIBARTBASE_BASE_LENGTH_PREFIXED_ARRAY_H_