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
23namespace flatbuffers {
24
25struct String;
26
27// An STL compatible iterator implementation for Vector below, effectively
28// calling Get() for every element.
29template<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
121template<typename Iterator>
122struct 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.
143template<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
297template<class U>
298FLATBUFFERS_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
305template<class U>
306FLATBUFFERS_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
313template<class U>
314FLATBUFFERS_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
321template<class U>
322FLATBUFFERS_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).
331class 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
350template<typename T, typename U>
351Vector<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
356template<typename T, typename U>
357const 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).
364template<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