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_VECTOR_H_ |
18 | #define FLATBUFFERS_VECTOR_H_ |
19 | |
20 | #include "flatbuffers/base.h" |
21 | #include "flatbuffers/buffer.h" |
22 | |
23 | namespace flatbuffers { |
24 | |
25 | struct String; |
26 | |
27 | // An STL compatible iterator implementation for Vector below, effectively |
28 | // calling Get() for every element. |
29 | template<typename T, typename IT> struct VectorIterator { |
30 | typedef std::random_access_iterator_tag iterator_category; |
31 | typedef IT value_type; |
32 | typedef ptrdiff_t difference_type; |
33 | typedef IT *pointer; |
34 | typedef IT &reference; |
35 | |
36 | VectorIterator(const uint8_t *data, uoffset_t i) |
37 | : data_(data + IndirectHelper<T>::element_stride * i) {} |
38 | VectorIterator(const VectorIterator &other) : data_(other.data_) {} |
39 | VectorIterator() : data_(nullptr) {} |
40 | |
41 | VectorIterator &operator=(const VectorIterator &other) { |
42 | data_ = other.data_; |
43 | return *this; |
44 | } |
45 | |
46 | VectorIterator &operator=(VectorIterator &&other) { |
47 | data_ = other.data_; |
48 | return *this; |
49 | } |
50 | |
51 | bool operator==(const VectorIterator &other) const { |
52 | return data_ == other.data_; |
53 | } |
54 | |
55 | bool operator<(const VectorIterator &other) const { |
56 | return data_ < other.data_; |
57 | } |
58 | |
59 | bool operator!=(const VectorIterator &other) const { |
60 | return data_ != other.data_; |
61 | } |
62 | |
63 | difference_type operator-(const VectorIterator &other) const { |
64 | return (data_ - other.data_) / IndirectHelper<T>::element_stride; |
65 | } |
66 | |
67 | // Note: return type is incompatible with the standard |
68 | // `reference operator*()`. |
69 | IT operator*() const { return IndirectHelper<T>::Read(data_, 0); } |
70 | |
71 | // Note: return type is incompatible with the standard |
72 | // `pointer operator->()`. |
73 | IT operator->() const { return IndirectHelper<T>::Read(data_, 0); } |
74 | |
75 | VectorIterator &operator++() { |
76 | data_ += IndirectHelper<T>::element_stride; |
77 | return *this; |
78 | } |
79 | |
80 | VectorIterator operator++(int) { |
81 | VectorIterator temp(data_, 0); |
82 | data_ += IndirectHelper<T>::element_stride; |
83 | return temp; |
84 | } |
85 | |
86 | VectorIterator operator+(const uoffset_t &offset) const { |
87 | return VectorIterator(data_ + offset * IndirectHelper<T>::element_stride, |
88 | 0); |
89 | } |
90 | |
91 | VectorIterator &operator+=(const uoffset_t &offset) { |
92 | data_ += offset * IndirectHelper<T>::element_stride; |
93 | return *this; |
94 | } |
95 | |
96 | VectorIterator &operator--() { |
97 | data_ -= IndirectHelper<T>::element_stride; |
98 | return *this; |
99 | } |
100 | |
101 | VectorIterator operator--(int) { |
102 | VectorIterator temp(data_, 0); |
103 | data_ -= IndirectHelper<T>::element_stride; |
104 | return temp; |
105 | } |
106 | |
107 | VectorIterator operator-(const uoffset_t &offset) const { |
108 | return VectorIterator(data_ - offset * IndirectHelper<T>::element_stride, |
109 | 0); |
110 | } |
111 | |
112 | VectorIterator &operator-=(const uoffset_t &offset) { |
113 | data_ -= offset * IndirectHelper<T>::element_stride; |
114 | return *this; |
115 | } |
116 | |
117 | private: |
118 | const uint8_t *data_; |
119 | }; |
120 | |
121 | template<typename Iterator> |
122 | struct VectorReverseIterator : public std::reverse_iterator<Iterator> { |
123 | explicit VectorReverseIterator(Iterator iter) |
124 | : std::reverse_iterator<Iterator>(iter) {} |
125 | |
126 | // Note: return type is incompatible with the standard |
127 | // `reference operator*()`. |
128 | typename Iterator::value_type operator*() const { |
129 | auto tmp = std::reverse_iterator<Iterator>::current; |
130 | return *--tmp; |
131 | } |
132 | |
133 | // Note: return type is incompatible with the standard |
134 | // `pointer operator->()`. |
135 | typename Iterator::value_type operator->() const { |
136 | auto tmp = std::reverse_iterator<Iterator>::current; |
137 | return *--tmp; |
138 | } |
139 | }; |
140 | |
141 | // This is used as a helper type for accessing vectors. |
142 | // Vector::data() assumes the vector elements start after the length field. |
143 | template<typename T> class Vector { |
144 | public: |
145 | typedef VectorIterator<T, typename IndirectHelper<T>::mutable_return_type> |
146 | iterator; |
147 | typedef VectorIterator<T, typename IndirectHelper<T>::return_type> |
148 | const_iterator; |
149 | typedef VectorReverseIterator<iterator> reverse_iterator; |
150 | typedef VectorReverseIterator<const_iterator> const_reverse_iterator; |
151 | |
152 | typedef typename flatbuffers::bool_constant<flatbuffers::is_scalar<T>::value> |
153 | scalar_tag; |
154 | |
155 | static FLATBUFFERS_CONSTEXPR bool is_span_observable = |
156 | scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1); |
157 | |
158 | uoffset_t size() const { return EndianScalar(length_); } |
159 | |
160 | // Deprecated: use size(). Here for backwards compatibility. |
161 | FLATBUFFERS_ATTRIBUTE([[deprecated("use size() instead" )]]) |
162 | uoffset_t Length() const { return size(); } |
163 | |
164 | typedef typename IndirectHelper<T>::return_type return_type; |
165 | typedef typename IndirectHelper<T>::mutable_return_type mutable_return_type; |
166 | typedef return_type value_type; |
167 | |
168 | return_type Get(uoffset_t i) const { |
169 | FLATBUFFERS_ASSERT(i < size()); |
170 | return IndirectHelper<T>::Read(Data(), i); |
171 | } |
172 | |
173 | return_type operator[](uoffset_t i) const { return Get(i); } |
174 | |
175 | // If this is a Vector of enums, T will be its storage type, not the enum |
176 | // type. This function makes it convenient to retrieve value with enum |
177 | // type E. |
178 | template<typename E> E GetEnum(uoffset_t i) const { |
179 | return static_cast<E>(Get(i)); |
180 | } |
181 | |
182 | // If this a vector of unions, this does the cast for you. There's no check |
183 | // to make sure this is the right type! |
184 | template<typename U> const U *GetAs(uoffset_t i) const { |
185 | return reinterpret_cast<const U *>(Get(i)); |
186 | } |
187 | |
188 | // If this a vector of unions, this does the cast for you. There's no check |
189 | // to make sure this is actually a string! |
190 | const String *GetAsString(uoffset_t i) const { |
191 | return reinterpret_cast<const String *>(Get(i)); |
192 | } |
193 | |
194 | const void *GetStructFromOffset(size_t o) const { |
195 | return reinterpret_cast<const void *>(Data() + o); |
196 | } |
197 | |
198 | iterator begin() { return iterator(Data(), 0); } |
199 | const_iterator begin() const { return const_iterator(Data(), 0); } |
200 | |
201 | iterator end() { return iterator(Data(), size()); } |
202 | const_iterator end() const { return const_iterator(Data(), size()); } |
203 | |
204 | reverse_iterator rbegin() { return reverse_iterator(end()); } |
205 | const_reverse_iterator rbegin() const { |
206 | return const_reverse_iterator(end()); |
207 | } |
208 | |
209 | reverse_iterator rend() { return reverse_iterator(begin()); } |
210 | const_reverse_iterator rend() const { |
211 | return const_reverse_iterator(begin()); |
212 | } |
213 | |
214 | const_iterator cbegin() const { return begin(); } |
215 | |
216 | const_iterator cend() const { return end(); } |
217 | |
218 | const_reverse_iterator crbegin() const { return rbegin(); } |
219 | |
220 | const_reverse_iterator crend() const { return rend(); } |
221 | |
222 | // Change elements if you have a non-const pointer to this object. |
223 | // Scalars only. See reflection.h, and the documentation. |
224 | void Mutate(uoffset_t i, const T &val) { |
225 | FLATBUFFERS_ASSERT(i < size()); |
226 | WriteScalar(data() + i, val); |
227 | } |
228 | |
229 | // Change an element of a vector of tables (or strings). |
230 | // "val" points to the new table/string, as you can obtain from |
231 | // e.g. reflection::AddFlatBuffer(). |
232 | void MutateOffset(uoffset_t i, const uint8_t *val) { |
233 | FLATBUFFERS_ASSERT(i < size()); |
234 | static_assert(sizeof(T) == sizeof(uoffset_t), "Unrelated types" ); |
235 | WriteScalar(data() + i, |
236 | static_cast<uoffset_t>(val - (Data() + i * sizeof(uoffset_t)))); |
237 | } |
238 | |
239 | // Get a mutable pointer to tables/strings inside this vector. |
240 | mutable_return_type GetMutableObject(uoffset_t i) const { |
241 | FLATBUFFERS_ASSERT(i < size()); |
242 | return const_cast<mutable_return_type>(IndirectHelper<T>::Read(Data(), i)); |
243 | } |
244 | |
245 | // The raw data in little endian format. Use with care. |
246 | const uint8_t *Data() const { |
247 | return reinterpret_cast<const uint8_t *>(&length_ + 1); |
248 | } |
249 | |
250 | uint8_t *Data() { return reinterpret_cast<uint8_t *>(&length_ + 1); } |
251 | |
252 | // Similarly, but typed, much like std::vector::data |
253 | const T *data() const { return reinterpret_cast<const T *>(Data()); } |
254 | T *data() { return reinterpret_cast<T *>(Data()); } |
255 | |
256 | template<typename K> return_type LookupByKey(K key) const { |
257 | void *search_result = std::bsearch( |
258 | &key, Data(), size(), IndirectHelper<T>::element_stride, KeyCompare<K>); |
259 | |
260 | if (!search_result) { |
261 | return nullptr; // Key not found. |
262 | } |
263 | |
264 | const uint8_t *element = reinterpret_cast<const uint8_t *>(search_result); |
265 | |
266 | return IndirectHelper<T>::Read(element, 0); |
267 | } |
268 | |
269 | template<typename K> mutable_return_type MutableLookupByKey(K key) { |
270 | return const_cast<mutable_return_type>(LookupByKey(key)); |
271 | } |
272 | |
273 | protected: |
274 | // This class is only used to access pre-existing data. Don't ever |
275 | // try to construct these manually. |
276 | Vector(); |
277 | |
278 | uoffset_t length_; |
279 | |
280 | private: |
281 | // This class is a pointer. Copying will therefore create an invalid object. |
282 | // Private and unimplemented copy constructor. |
283 | Vector(const Vector &); |
284 | Vector &operator=(const Vector &); |
285 | |
286 | template<typename K> static int KeyCompare(const void *ap, const void *bp) { |
287 | const K *key = reinterpret_cast<const K *>(ap); |
288 | const uint8_t *data = reinterpret_cast<const uint8_t *>(bp); |
289 | auto table = IndirectHelper<T>::Read(data, 0); |
290 | |
291 | // std::bsearch compares with the operands transposed, so we negate the |
292 | // result here. |
293 | return -table->KeyCompareWithValue(*key); |
294 | } |
295 | }; |
296 | |
297 | template<class U> |
298 | FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U> make_span(Vector<U> &vec) |
299 | FLATBUFFERS_NOEXCEPT { |
300 | static_assert(Vector<U>::is_span_observable, |
301 | "wrong type U, only LE-scalar, or byte types are allowed" ); |
302 | return span<U>(vec.data(), vec.size()); |
303 | } |
304 | |
305 | template<class U> |
306 | FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U> make_span( |
307 | const Vector<U> &vec) FLATBUFFERS_NOEXCEPT { |
308 | static_assert(Vector<U>::is_span_observable, |
309 | "wrong type U, only LE-scalar, or byte types are allowed" ); |
310 | return span<const U>(vec.data(), vec.size()); |
311 | } |
312 | |
313 | template<class U> |
314 | FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<uint8_t> make_bytes_span( |
315 | Vector<U> &vec) FLATBUFFERS_NOEXCEPT { |
316 | static_assert(Vector<U>::scalar_tag::value, |
317 | "wrong type U, only LE-scalar, or byte types are allowed" ); |
318 | return span<uint8_t>(vec.Data(), vec.size() * sizeof(U)); |
319 | } |
320 | |
321 | template<class U> |
322 | FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const uint8_t> make_bytes_span( |
323 | const Vector<U> &vec) FLATBUFFERS_NOEXCEPT { |
324 | static_assert(Vector<U>::scalar_tag::value, |
325 | "wrong type U, only LE-scalar, or byte types are allowed" ); |
326 | return span<const uint8_t>(vec.Data(), vec.size() * sizeof(U)); |
327 | } |
328 | |
329 | // Represent a vector much like the template above, but in this case we |
330 | // don't know what the element types are (used with reflection.h). |
331 | class VectorOfAny { |
332 | public: |
333 | uoffset_t size() const { return EndianScalar(length_); } |
334 | |
335 | const uint8_t *Data() const { |
336 | return reinterpret_cast<const uint8_t *>(&length_ + 1); |
337 | } |
338 | uint8_t *Data() { return reinterpret_cast<uint8_t *>(&length_ + 1); } |
339 | |
340 | protected: |
341 | VectorOfAny(); |
342 | |
343 | uoffset_t length_; |
344 | |
345 | private: |
346 | VectorOfAny(const VectorOfAny &); |
347 | VectorOfAny &operator=(const VectorOfAny &); |
348 | }; |
349 | |
350 | template<typename T, typename U> |
351 | Vector<Offset<T>> *VectorCast(Vector<Offset<U>> *ptr) { |
352 | static_assert(std::is_base_of<T, U>::value, "Unrelated types" ); |
353 | return reinterpret_cast<Vector<Offset<T>> *>(ptr); |
354 | } |
355 | |
356 | template<typename T, typename U> |
357 | const Vector<Offset<T>> *VectorCast(const Vector<Offset<U>> *ptr) { |
358 | static_assert(std::is_base_of<T, U>::value, "Unrelated types" ); |
359 | return reinterpret_cast<const Vector<Offset<T>> *>(ptr); |
360 | } |
361 | |
362 | // Convenient helper function to get the length of any vector, regardless |
363 | // of whether it is null or not (the field is not set). |
364 | template<typename T> static inline size_t VectorLength(const Vector<T> *v) { |
365 | return v ? v->size() : 0; |
366 | } |
367 | |
368 | } // namespace flatbuffers |
369 | |
370 | #endif // FLATBUFFERS_VERIFIER_H_ |
371 | |