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_LENGTH_PREFIXED_ARRAY_H_
18 #define ART_LIBARTBASE_BASE_LENGTH_PREFIXED_ARRAY_H_
19 
20 #include <stddef.h>  // for offsetof()
21 #include <string.h>  // for memset()
22 
23 #include "bit_utils.h"
24 #include "casts.h"
25 #include "iteration_range.h"
26 #include "stride_iterator.h"
27 
28 namespace art {
29 
30 template<typename T>
31 class LengthPrefixedArray {
32  public:
33   explicit LengthPrefixedArray(size_t length)
34       : size_(dchecked_integral_cast<uint32_t>(length)) {}
35 
36   T& At(size_t index, size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
37     DCHECK_LT(index, size_);
38     return AtUnchecked(index, element_size, alignment);
39   }
40 
41   const T& At(size_t index, size_t element_size = sizeof(T), size_t alignment = alignof(T)) const {
42     DCHECK_LT(index, size_);
43     return AtUnchecked(index, element_size, alignment);
44   }
45 
46   StrideIterator<T> begin(size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
47     return StrideIterator<T>(&AtUnchecked(0, element_size, alignment), element_size);
48   }
49 
50   StrideIterator<const T> begin(size_t element_size = sizeof(T),
51                                 size_t alignment = alignof(T)) const {
52     return StrideIterator<const T>(&AtUnchecked(0, element_size, alignment), element_size);
53   }
54 
55   StrideIterator<T> end(size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
56     return StrideIterator<T>(&AtUnchecked(size_, element_size, alignment), element_size);
57   }
58 
59   StrideIterator<const T> end(size_t element_size = sizeof(T),
60                               size_t alignment = alignof(T)) const {
61     return StrideIterator<const T>(&AtUnchecked(size_, element_size, alignment), element_size);
62   }
63 
64   static size_t OffsetOfElement(size_t index,
65                                 size_t element_size = sizeof(T),
66                                 size_t alignment = alignof(T)) {
67     DCHECK_ALIGNED_PARAM(element_size, alignment);
68     return RoundUp(offsetof(LengthPrefixedArray<T>, data_), alignment) + index * element_size;
69   }
70 
71   static size_t ComputeSize(size_t num_elements,
72                             size_t element_size = sizeof(T),
73                             size_t alignment = alignof(T)) {
74     size_t result = OffsetOfElement(num_elements, element_size, alignment);
75     DCHECK_ALIGNED_PARAM(result, alignment);
76     return result;
77   }
78 
79   size_t size() const {
80     return size_;
81   }
82 
83   // Update the length but does not reallocate storage.
84   void SetSize(size_t length) {
85     size_ = dchecked_integral_cast<uint32_t>(length);
86   }
87 
88   // Clear the potentially uninitialized padding between the size_ and actual data.
89   void ClearPadding(size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
90     size_t gap_offset = offsetof(LengthPrefixedArray<T>, data_);
91     size_t gap_size = OffsetOfElement(0, element_size, alignment) - gap_offset;
92     memset(reinterpret_cast<uint8_t*>(this) + gap_offset, 0, gap_size);
93   }
94 
95  private:
96   T& AtUnchecked(size_t index, size_t element_size, size_t alignment) {
97     return *reinterpret_cast<T*>(
98         reinterpret_cast<uintptr_t>(this) + OffsetOfElement(index, element_size, alignment));
99   }
100 
101   const T& AtUnchecked(size_t index, size_t element_size, size_t alignment) const {
102     return *reinterpret_cast<T*>(
103         reinterpret_cast<uintptr_t>(this) + OffsetOfElement(index, element_size, alignment));
104   }
105 
106   uint32_t size_;
107   uint8_t data_[0];
108 };
109 
110 // Returns empty iteration range if the array is null.
111 template<typename T>
112 IterationRange<StrideIterator<T>> MakeIterationRangeFromLengthPrefixedArray(
113     LengthPrefixedArray<T>* arr, size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
114   return arr != nullptr ?
115       MakeIterationRange(arr->begin(element_size, alignment), arr->end(element_size, alignment)) :
116       MakeEmptyIterationRange(StrideIterator<T>(nullptr, 0));
117 }
118 
119 }  // namespace art
120 
121 #endif  // ART_LIBARTBASE_BASE_LENGTH_PREFIXED_ARRAY_H_
122