1 /*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9 //===--- ArrayRef.h - Array Reference Wrapper -------------------*- C++ -*-===//
10 //
11 // The LLVM Compiler Infrastructure
12 //
13 // This file is distributed under the University of Illinois Open Source
14 // License. See LICENSE.TXT for details.
15 //
16 //===----------------------------------------------------------------------===//
17
18 // removed llvm-specific functionality
19 // removed some implicit const -> non-const conversions that rely on
20 // complicated std::enable_if meta-programming
21 // removed a bunch of slice variants for simplicity...
22 // remove constructors for std::array
23 // remove constructors and operators for std::vector
24 // removed some prevention of accidental assignments from temporary that
25 // required std::enable_if meta-programming
26 // removed reverse iterator
27
28 #pragma once
29
30 #include <cstdint>
31
32 #include <executorch/runtime/platform/assert.h>
33
34 namespace executorch {
35 namespace runtime {
36
37 /**
38 * Represents a constant reference to an array (0 or more elements
39 * consecutively in memory), i.e. a start pointer and a length. It allows
40 * various APIs to take consecutive elements easily and conveniently.
41 *
42 * This class does not own the underlying data, it is expected to be used in
43 * situations where the data resides in some other buffer, whose lifetime
44 * extends past that of the ArrayRef. For this reason, it is not in general
45 * safe to store an ArrayRef.
46 *
47 * Span and ArrayRef are extrememly similar with the difference being ArrayRef
48 * views a list of constant elements and Span views a list of mutable elements.
49 * Clients should decide between the two based on if the list elements for their
50 * use case should be mutable.
51 *
52 * This is intended to be trivially copyable, so it should be passed by
53 * value.
54 */
55 template <typename T>
56 class ArrayRef final {
57 public:
58 using iterator = const T*;
59 using const_iterator = const T*;
60 using size_type = size_t;
61 using value_type = T;
62
63 private:
64 /// The start of the array, in an external buffer.
65 const T* Data;
66
67 /// The number of elements.
68 size_type Length;
69
70 public:
71 /// @name Constructors
72 /// @{
73
74 /// Construct an empty ArrayRef.
ArrayRef()75 /* implicit */ constexpr ArrayRef() : Data(nullptr), Length(0) {}
76
77 /// Construct a ArrayRef from a single element. Implicitly convert element
78 /// type. It is aligned with PyTorch's c10::ArrayRef.
ArrayRef(const T & OneElt)79 /* implicit */ constexpr ArrayRef(const T& OneElt)
80 : Data(&OneElt), Length(1) {}
81
82 /// Construct a ArrayRef from a pointer and length.
ArrayRef(const T * data,size_t length)83 ArrayRef(const T* data, size_t length) : Data(data), Length(length) {
84 ET_DCHECK(Data != nullptr || Length == 0);
85 }
86
87 /// Construct a ArrayRef from a range.
ArrayRef(const T * begin,const T * end)88 ArrayRef(const T* begin, const T* end) : Data(begin), Length(end - begin) {}
89
90 /// Construct a ArrayRef from a C array.
91 template <size_t N>
ArrayRef(const T (& Arr)[N])92 /* implicit */ constexpr ArrayRef(const T (&Arr)[N]) : Data(Arr), Length(N) {}
93
94 /// @}
95 /// @name Simple Operations
96 /// @{
97
begin()98 constexpr iterator begin() const {
99 return Data;
100 }
end()101 constexpr iterator end() const {
102 return Data + Length;
103 }
104
105 // These are actually the same as iterator, since ArrayRef only
106 // gives you const iterators.
cbegin()107 constexpr const_iterator cbegin() const {
108 return Data;
109 }
cend()110 constexpr const_iterator cend() const {
111 return Data + Length;
112 }
113
114 /// empty - Check if the array is empty.
empty()115 constexpr bool empty() const {
116 return Length == 0;
117 }
118
data()119 constexpr const T* data() const {
120 return Data;
121 }
122
123 /// size - Get the array size.
size()124 constexpr size_t size() const {
125 return Length;
126 }
127
128 /// front - Get the first element.
front()129 const T& front() const {
130 // ArrayRef: attempted to access front() of empty list
131 ET_CHECK(!empty());
132 return Data[0];
133 }
134
135 /// back - Get the last element.
back()136 const T& back() const {
137 // ArrayRef: attempted to access back() of empty list
138 ET_CHECK(!empty());
139 return Data[Length - 1];
140 }
141
142 /// equals - Check for element-wise equality.
equals(ArrayRef RHS)143 bool equals(ArrayRef RHS) const {
144 if (Length != RHS.Length) {
145 return false;
146 }
147 for (size_t i = 0; i < this->Length; i++) {
148 if (Data[i] != RHS.Data[i]) {
149 return false;
150 }
151 }
152 return true;
153 }
154
155 /// slice(n, m) - Take M elements of the array starting at element N
slice(size_t N,size_t M)156 ArrayRef<T> slice(size_t N, size_t M) const {
157 // cant slice longer then the array
158 ET_CHECK(N + M <= size());
159 return ArrayRef<T>(data() + N, M);
160 }
161
162 /// slice(n) - Chop off the first N elements of the array.
slice(size_t N)163 constexpr ArrayRef<T> slice(size_t N) const {
164 return slice(N, size() - N);
165 }
166
167 /// @}
168 /// @name Operator Overloads
169 /// @{
170 constexpr const T& operator[](size_t Index) const {
171 return Data[Index];
172 }
173
174 /// Vector compatibility
at(size_t Index)175 const T& at(size_t Index) const {
176 // invalid index
177 ET_CHECK(Index < Length);
178 return Data[Index];
179 }
180
181 /// @}
182 };
183
184 /// @name ArrayRef Convenience constructors
185 /// @{
186
187 /// Construct an ArrayRef from a single element.
188 template <typename T>
makeArrayRef(const T & OneElt)189 ArrayRef<T> makeArrayRef(const T& OneElt) {
190 return OneElt;
191 }
192
193 /// Construct an ArrayRef from a pointer and length.
194 template <typename T>
makeArrayRef(const T * data,size_t length)195 ArrayRef<T> makeArrayRef(const T* data, size_t length) {
196 return ArrayRef<T>(data, length);
197 }
198
199 /// Construct an ArrayRef from a range.
200 template <typename T>
makeArrayRef(const T * begin,const T * end)201 ArrayRef<T> makeArrayRef(const T* begin, const T* end) {
202 return ArrayRef<T>(begin, end);
203 }
204
205 /// Construct an ArrayRef from an ArrayRef (no-op) (const)
206 template <typename T>
makeArrayRef(const ArrayRef<T> & Vec)207 ArrayRef<T> makeArrayRef(const ArrayRef<T>& Vec) {
208 return Vec;
209 }
210
211 /// Construct an ArrayRef from an ArrayRef (no-op)
212 template <typename T>
makeArrayRef(ArrayRef<T> & Vec)213 ArrayRef<T>& makeArrayRef(ArrayRef<T>& Vec) {
214 return Vec;
215 }
216
217 /// Construct an ArrayRef from a C array.
218 template <typename T, size_t N>
makeArrayRef(const T (& Arr)[N])219 ArrayRef<T> makeArrayRef(const T (&Arr)[N]) {
220 return ArrayRef<T>(Arr);
221 }
222
223 // WARNING: Template instantiation will NOT be willing to do an implicit
224 // conversions to get you to an ArrayRef, which is why we need so
225 // many overloads.
226
227 template <typename T>
228 bool operator==(ArrayRef<T> a1, ArrayRef<T> a2) {
229 return a1.equals(a2);
230 }
231
232 template <typename T>
233 bool operator!=(ArrayRef<T> a1, ArrayRef<T> a2) {
234 return !a1.equals(a2);
235 }
236
237 using IntArrayRef = ArrayRef<int64_t>;
238
239 } // namespace runtime
240 } // namespace executorch
241
242 namespace torch {
243 namespace executor {
244 // TODO(T197294990): Remove these deprecated aliases once all users have moved
245 // to the new `::executorch` namespaces.
246 using ::executorch::runtime::ArrayRef;
247 using ::executorch::runtime::IntArrayRef;
248 using ::executorch::runtime::makeArrayRef;
249 } // namespace executor
250 } // namespace torch
251