/src/flatbuffers/include/flatbuffers/array.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2021 Google Inc. All rights reserved. |
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 FLATBUFFERS_ARRAY_H_ |
18 | | #define FLATBUFFERS_ARRAY_H_ |
19 | | |
20 | | #include <cstdint> |
21 | | #include <memory> |
22 | | |
23 | | #include "flatbuffers/base.h" |
24 | | #include "flatbuffers/stl_emulation.h" |
25 | | #include "flatbuffers/vector.h" |
26 | | |
27 | | namespace flatbuffers { |
28 | | |
29 | | // This is used as a helper type for accessing arrays. |
30 | | template<typename T, uint16_t length> class Array { |
31 | | // Array<T> can carry only POD data types (scalars or structs). |
32 | | typedef typename flatbuffers::bool_constant<flatbuffers::is_scalar<T>::value> |
33 | | scalar_tag; |
34 | | |
35 | | public: |
36 | | typedef uint16_t size_type; |
37 | | typedef typename IndirectHelper<T>::return_type return_type; |
38 | | typedef VectorConstIterator<T, return_type, uoffset_t> const_iterator; |
39 | | typedef VectorReverseIterator<const_iterator> const_reverse_iterator; |
40 | | |
41 | | // If T is a LE-scalar or a struct (!scalar_tag::value). |
42 | | static FLATBUFFERS_CONSTEXPR bool is_span_observable = |
43 | | (scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1)) || |
44 | | !scalar_tag::value; |
45 | | |
46 | 0 | FLATBUFFERS_CONSTEXPR uint16_t size() const { return length; } Unexecuted instantiation: flatbuffers::Array<unsigned char, (unsigned short)65535>::size() const Unexecuted instantiation: flatbuffers::Array<signed char, (unsigned short)65535>::size() const Unexecuted instantiation: flatbuffers::Array<short, (unsigned short)65535>::size() const Unexecuted instantiation: flatbuffers::Array<unsigned short, (unsigned short)65535>::size() const Unexecuted instantiation: flatbuffers::Array<int, (unsigned short)65535>::size() const Unexecuted instantiation: flatbuffers::Array<unsigned int, (unsigned short)65535>::size() const Unexecuted instantiation: flatbuffers::Array<long, (unsigned short)65535>::size() const Unexecuted instantiation: flatbuffers::Array<unsigned long, (unsigned short)65535>::size() const Unexecuted instantiation: flatbuffers::Array<float, (unsigned short)65535>::size() const Unexecuted instantiation: flatbuffers::Array<double, (unsigned short)65535>::size() const |
47 | | |
48 | 0 | return_type Get(uoffset_t i) const { |
49 | 0 | FLATBUFFERS_ASSERT(i < size()); |
50 | 0 | return IndirectHelper<T>::Read(Data(), i); |
51 | 0 | } Unexecuted instantiation: flatbuffers::Array<unsigned char, (unsigned short)65535>::Get(unsigned int) const Unexecuted instantiation: flatbuffers::Array<signed char, (unsigned short)65535>::Get(unsigned int) const Unexecuted instantiation: flatbuffers::Array<short, (unsigned short)65535>::Get(unsigned int) const Unexecuted instantiation: flatbuffers::Array<unsigned short, (unsigned short)65535>::Get(unsigned int) const Unexecuted instantiation: flatbuffers::Array<int, (unsigned short)65535>::Get(unsigned int) const Unexecuted instantiation: flatbuffers::Array<unsigned int, (unsigned short)65535>::Get(unsigned int) const Unexecuted instantiation: flatbuffers::Array<long, (unsigned short)65535>::Get(unsigned int) const Unexecuted instantiation: flatbuffers::Array<unsigned long, (unsigned short)65535>::Get(unsigned int) const Unexecuted instantiation: flatbuffers::Array<float, (unsigned short)65535>::Get(unsigned int) const Unexecuted instantiation: flatbuffers::Array<double, (unsigned short)65535>::Get(unsigned int) const |
52 | | |
53 | 0 | return_type operator[](uoffset_t i) const { return Get(i); } Unexecuted instantiation: flatbuffers::Array<unsigned char, (unsigned short)65535>::operator[](unsigned int) const Unexecuted instantiation: flatbuffers::Array<signed char, (unsigned short)65535>::operator[](unsigned int) const Unexecuted instantiation: flatbuffers::Array<short, (unsigned short)65535>::operator[](unsigned int) const Unexecuted instantiation: flatbuffers::Array<unsigned short, (unsigned short)65535>::operator[](unsigned int) const Unexecuted instantiation: flatbuffers::Array<int, (unsigned short)65535>::operator[](unsigned int) const Unexecuted instantiation: flatbuffers::Array<unsigned int, (unsigned short)65535>::operator[](unsigned int) const Unexecuted instantiation: flatbuffers::Array<long, (unsigned short)65535>::operator[](unsigned int) const Unexecuted instantiation: flatbuffers::Array<unsigned long, (unsigned short)65535>::operator[](unsigned int) const Unexecuted instantiation: flatbuffers::Array<float, (unsigned short)65535>::operator[](unsigned int) const Unexecuted instantiation: flatbuffers::Array<double, (unsigned short)65535>::operator[](unsigned int) const |
54 | | |
55 | | // If this is a Vector of enums, T will be its storage type, not the enum |
56 | | // type. This function makes it convenient to retrieve value with enum |
57 | | // type E. |
58 | | template<typename E> E GetEnum(uoffset_t i) const { |
59 | | return static_cast<E>(Get(i)); |
60 | | } |
61 | | |
62 | | const_iterator begin() const { return const_iterator(Data(), 0); } |
63 | | const_iterator end() const { return const_iterator(Data(), size()); } |
64 | | |
65 | | const_reverse_iterator rbegin() const { |
66 | | return const_reverse_iterator(end()); |
67 | | } |
68 | | const_reverse_iterator rend() const { |
69 | | return const_reverse_iterator(begin()); |
70 | | } |
71 | | |
72 | | const_iterator cbegin() const { return begin(); } |
73 | | const_iterator cend() const { return end(); } |
74 | | |
75 | | const_reverse_iterator crbegin() const { return rbegin(); } |
76 | | const_reverse_iterator crend() const { return rend(); } |
77 | | |
78 | | // Get a mutable pointer to elements inside this array. |
79 | | // This method used to mutate arrays of structs followed by a @p Mutate |
80 | | // operation. For primitive types use @p Mutate directly. |
81 | | // @warning Assignments and reads to/from the dereferenced pointer are not |
82 | | // automatically converted to the correct endianness. |
83 | | typename flatbuffers::conditional<scalar_tag::value, void, T *>::type |
84 | | GetMutablePointer(uoffset_t i) const { |
85 | | FLATBUFFERS_ASSERT(i < size()); |
86 | | return const_cast<T *>(&data()[i]); |
87 | | } |
88 | | |
89 | | // Change elements if you have a non-const pointer to this object. |
90 | | void Mutate(uoffset_t i, const T &val) { MutateImpl(scalar_tag(), i, val); } |
91 | | |
92 | | // The raw data in little endian format. Use with care. |
93 | 0 | const uint8_t *Data() const { return data_; } Unexecuted instantiation: flatbuffers::Array<unsigned char, (unsigned short)65535>::Data() const Unexecuted instantiation: flatbuffers::Array<signed char, (unsigned short)65535>::Data() const Unexecuted instantiation: flatbuffers::Array<short, (unsigned short)65535>::Data() const Unexecuted instantiation: flatbuffers::Array<unsigned short, (unsigned short)65535>::Data() const Unexecuted instantiation: flatbuffers::Array<int, (unsigned short)65535>::Data() const Unexecuted instantiation: flatbuffers::Array<unsigned int, (unsigned short)65535>::Data() const Unexecuted instantiation: flatbuffers::Array<long, (unsigned short)65535>::Data() const Unexecuted instantiation: flatbuffers::Array<unsigned long, (unsigned short)65535>::Data() const Unexecuted instantiation: flatbuffers::Array<float, (unsigned short)65535>::Data() const Unexecuted instantiation: flatbuffers::Array<double, (unsigned short)65535>::Data() const |
94 | | |
95 | | uint8_t *Data() { return data_; } |
96 | | |
97 | | // Similarly, but typed, much like std::vector::data |
98 | | const T *data() const { return reinterpret_cast<const T *>(Data()); } |
99 | | T *data() { return reinterpret_cast<T *>(Data()); } |
100 | | |
101 | | // Copy data from a span with endian conversion. |
102 | | // If this Array and the span overlap, the behavior is undefined. |
103 | | void CopyFromSpan(flatbuffers::span<const T, length> src) { |
104 | | const auto p1 = reinterpret_cast<const uint8_t *>(src.data()); |
105 | | const auto p2 = Data(); |
106 | | FLATBUFFERS_ASSERT(!(p1 >= p2 && p1 < (p2 + length)) && |
107 | | !(p2 >= p1 && p2 < (p1 + length))); |
108 | | (void)p1; |
109 | | (void)p2; |
110 | | CopyFromSpanImpl(flatbuffers::bool_constant<is_span_observable>(), src); |
111 | | } |
112 | | |
113 | | protected: |
114 | | void MutateImpl(flatbuffers::true_type, uoffset_t i, const T &val) { |
115 | | FLATBUFFERS_ASSERT(i < size()); |
116 | | WriteScalar(data() + i, val); |
117 | | } |
118 | | |
119 | | void MutateImpl(flatbuffers::false_type, uoffset_t i, const T &val) { |
120 | | *(GetMutablePointer(i)) = val; |
121 | | } |
122 | | |
123 | | void CopyFromSpanImpl(flatbuffers::true_type, |
124 | | flatbuffers::span<const T, length> src) { |
125 | | // Use std::memcpy() instead of std::copy() to avoid performance degradation |
126 | | // due to aliasing if T is char or unsigned char. |
127 | | // The size is known at compile time, so memcpy would be inlined. |
128 | | std::memcpy(data(), src.data(), length * sizeof(T)); |
129 | | } |
130 | | |
131 | | // Copy data from flatbuffers::span with endian conversion. |
132 | | void CopyFromSpanImpl(flatbuffers::false_type, |
133 | | flatbuffers::span<const T, length> src) { |
134 | | for (size_type k = 0; k < length; k++) { Mutate(k, src[k]); } |
135 | | } |
136 | | |
137 | | // This class is only used to access pre-existing data. Don't ever |
138 | | // try to construct these manually. |
139 | | // 'constexpr' allows us to use 'size()' at compile time. |
140 | | // @note Must not use 'FLATBUFFERS_CONSTEXPR' here, as const is not allowed on |
141 | | // a constructor. |
142 | | #if defined(__cpp_constexpr) |
143 | | constexpr Array(); |
144 | | #else |
145 | | Array(); |
146 | | #endif |
147 | | |
148 | | uint8_t data_[length * sizeof(T)]; |
149 | | |
150 | | private: |
151 | | // This class is a pointer. Copying will therefore create an invalid object. |
152 | | // Private and unimplemented copy constructor. |
153 | | Array(const Array &); |
154 | | Array &operator=(const Array &); |
155 | | }; |
156 | | |
157 | | // Specialization for Array[struct] with access using Offset<void> pointer. |
158 | | // This specialization used by idl_gen_text.cpp. |
159 | | template<typename T, uint16_t length, template<typename> class OffsetT> |
160 | | class Array<OffsetT<T>, length> { |
161 | | static_assert(flatbuffers::is_same<T, void>::value, "unexpected type T"); |
162 | | |
163 | | public: |
164 | | typedef const void *return_type; |
165 | | typedef uint16_t size_type; |
166 | | |
167 | 0 | const uint8_t *Data() const { return data_; } Unexecuted instantiation: flatbuffers::Array<flatbuffers::Offset<void>, (unsigned short)65535>::Data() const Unexecuted instantiation: flatbuffers::Array<flatbuffers::Offset64<void>, (unsigned short)65535>::Data() const |
168 | | |
169 | | // Make idl_gen_text.cpp::PrintContainer happy. |
170 | 0 | return_type operator[](uoffset_t) const { |
171 | 0 | FLATBUFFERS_ASSERT(false); |
172 | 0 | return nullptr; |
173 | 0 | } Unexecuted instantiation: flatbuffers::Array<flatbuffers::Offset<void>, (unsigned short)65535>::operator[](unsigned int) const Unexecuted instantiation: flatbuffers::Array<flatbuffers::Offset64<void>, (unsigned short)65535>::operator[](unsigned int) const |
174 | | |
175 | | private: |
176 | | // This class is only used to access pre-existing data. |
177 | | Array(); |
178 | | Array(const Array &); |
179 | | Array &operator=(const Array &); |
180 | | |
181 | | uint8_t data_[1]; |
182 | | }; |
183 | | |
184 | | template<class U, uint16_t N> |
185 | | FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U, N> make_span(Array<U, N> &arr) |
186 | | FLATBUFFERS_NOEXCEPT { |
187 | | static_assert( |
188 | | Array<U, N>::is_span_observable, |
189 | | "wrong type U, only plain struct, LE-scalar, or byte types are allowed"); |
190 | | return span<U, N>(arr.data(), N); |
191 | | } |
192 | | |
193 | | template<class U, uint16_t N> |
194 | | FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U, N> make_span( |
195 | | const Array<U, N> &arr) FLATBUFFERS_NOEXCEPT { |
196 | | static_assert( |
197 | | Array<U, N>::is_span_observable, |
198 | | "wrong type U, only plain struct, LE-scalar, or byte types are allowed"); |
199 | | return span<const U, N>(arr.data(), N); |
200 | | } |
201 | | |
202 | | template<class U, uint16_t N> |
203 | | FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<uint8_t, sizeof(U) * N> |
204 | | make_bytes_span(Array<U, N> &arr) FLATBUFFERS_NOEXCEPT { |
205 | | static_assert(Array<U, N>::is_span_observable, |
206 | | "internal error, Array<T> might hold only scalars or structs"); |
207 | | return span<uint8_t, sizeof(U) * N>(arr.Data(), sizeof(U) * N); |
208 | | } |
209 | | |
210 | | template<class U, uint16_t N> |
211 | | FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const uint8_t, sizeof(U) * N> |
212 | | make_bytes_span(const Array<U, N> &arr) FLATBUFFERS_NOEXCEPT { |
213 | | static_assert(Array<U, N>::is_span_observable, |
214 | | "internal error, Array<T> might hold only scalars or structs"); |
215 | | return span<const uint8_t, sizeof(U) * N>(arr.Data(), sizeof(U) * N); |
216 | | } |
217 | | |
218 | | // Cast a raw T[length] to a raw flatbuffers::Array<T, length> |
219 | | // without endian conversion. Use with care. |
220 | | // TODO: move these Cast-methods to `internal` namespace. |
221 | | template<typename T, uint16_t length> |
222 | | Array<T, length> &CastToArray(T (&arr)[length]) { |
223 | | return *reinterpret_cast<Array<T, length> *>(arr); |
224 | | } |
225 | | |
226 | | template<typename T, uint16_t length> |
227 | | const Array<T, length> &CastToArray(const T (&arr)[length]) { |
228 | | return *reinterpret_cast<const Array<T, length> *>(arr); |
229 | | } |
230 | | |
231 | | template<typename E, typename T, uint16_t length> |
232 | | Array<E, length> &CastToArrayOfEnum(T (&arr)[length]) { |
233 | | static_assert(sizeof(E) == sizeof(T), "invalid enum type E"); |
234 | | return *reinterpret_cast<Array<E, length> *>(arr); |
235 | | } |
236 | | |
237 | | template<typename E, typename T, uint16_t length> |
238 | | const Array<E, length> &CastToArrayOfEnum(const T (&arr)[length]) { |
239 | | static_assert(sizeof(E) == sizeof(T), "invalid enum type E"); |
240 | | return *reinterpret_cast<const Array<E, length> *>(arr); |
241 | | } |
242 | | |
243 | | template<typename T, uint16_t length> |
244 | | bool operator==(const Array<T, length> &lhs, |
245 | | const Array<T, length> &rhs) noexcept { |
246 | | return std::addressof(lhs) == std::addressof(rhs) || |
247 | | (lhs.size() == rhs.size() && |
248 | | std::memcmp(lhs.Data(), rhs.Data(), rhs.size() * sizeof(T)) == 0); |
249 | | } |
250 | | |
251 | | } // namespace flatbuffers |
252 | | |
253 | | #endif // FLATBUFFERS_ARRAY_H_ |