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_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_
18#define ART_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_
19
20#include <stddef.h>  // for offsetof()
21#include <string.h>  // for memset()
22
23#include "stride_iterator.h"
24#include "base/bit_utils.h"
25#include "base/casts.h"
26#include "base/iteration_range.h"
27
28namespace art {
29
30template<typename T>
31class 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.
111template<typename T>
112IterationRange<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_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_
122