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_FLATBUFFER_BUILDER_H_
18 #define FLATBUFFERS_FLATBUFFER_BUILDER_H_
19
20 #include <functional>
21 #include <initializer_list>
22
23 #include "flatbuffers/allocator.h"
24 #include "flatbuffers/array.h"
25 #include "flatbuffers/base.h"
26 #include "flatbuffers/buffer_ref.h"
27 #include "flatbuffers/default_allocator.h"
28 #include "flatbuffers/detached_buffer.h"
29 #include "flatbuffers/stl_emulation.h"
30 #include "flatbuffers/string.h"
31 #include "flatbuffers/struct.h"
32 #include "flatbuffers/table.h"
33 #include "flatbuffers/vector.h"
34 #include "flatbuffers/vector_downward.h"
35 #include "flatbuffers/verifier.h"
36
37 namespace flatbuffers {
38
39 // Converts a Field ID to a virtual table offset.
FieldIndexToOffset(voffset_t field_id)40 inline voffset_t FieldIndexToOffset(voffset_t field_id) {
41 // Should correspond to what EndTable() below builds up.
42 const int fixed_fields = 2; // Vtable size and Object Size.
43 return static_cast<voffset_t>((field_id + fixed_fields) * sizeof(voffset_t));
44 }
45
46 template<typename T, typename Alloc = std::allocator<T>>
data(const std::vector<T,Alloc> & v)47 const T *data(const std::vector<T, Alloc> &v) {
48 // Eventually the returned pointer gets passed down to memcpy, so
49 // we need it to be non-null to avoid undefined behavior.
50 static uint8_t t;
51 return v.empty() ? reinterpret_cast<const T *>(&t) : &v.front();
52 }
53 template<typename T, typename Alloc = std::allocator<T>>
data(std::vector<T,Alloc> & v)54 T *data(std::vector<T, Alloc> &v) {
55 // Eventually the returned pointer gets passed down to memcpy, so
56 // we need it to be non-null to avoid undefined behavior.
57 static uint8_t t;
58 return v.empty() ? reinterpret_cast<T *>(&t) : &v.front();
59 }
60
61 /// @addtogroup flatbuffers_cpp_api
62 /// @{
63 /// @class FlatBufferBuilder
64 /// @brief Helper class to hold data needed in creation of a FlatBuffer.
65 /// To serialize data, you typically call one of the `Create*()` functions in
66 /// the generated code, which in turn call a sequence of `StartTable`/
67 /// `PushElement`/`AddElement`/`EndTable`, or the builtin `CreateString`/
68 /// `CreateVector` functions. Do this is depth-first order to build up a tree to
69 /// the root. `Finish()` wraps up the buffer ready for transport.
70 class FlatBufferBuilder {
71 public:
72 /// @brief Default constructor for FlatBufferBuilder.
73 /// @param[in] initial_size The initial size of the buffer, in bytes. Defaults
74 /// to `1024`.
75 /// @param[in] allocator An `Allocator` to use. If null will use
76 /// `DefaultAllocator`.
77 /// @param[in] own_allocator Whether the builder/vector should own the
78 /// allocator. Defaults to / `false`.
79 /// @param[in] buffer_minalign Force the buffer to be aligned to the given
80 /// minimum alignment upon reallocation. Only needed if you intend to store
81 /// types with custom alignment AND you wish to read the buffer in-place
82 /// directly after creation.
83 explicit FlatBufferBuilder(
84 size_t initial_size = 1024, Allocator *allocator = nullptr,
85 bool own_allocator = false,
86 size_t buffer_minalign = AlignOf<largest_scalar_t>())
buf_(initial_size,allocator,own_allocator,buffer_minalign)87 : buf_(initial_size, allocator, own_allocator, buffer_minalign),
88 num_field_loc(0),
89 max_voffset_(0),
90 nested(false),
91 finished(false),
92 minalign_(1),
93 force_defaults_(false),
94 dedup_vtables_(true),
95 string_pool(nullptr) {
96 EndianCheck();
97 }
98
99 /// @brief Move constructor for FlatBufferBuilder.
FlatBufferBuilder(FlatBufferBuilder && other)100 FlatBufferBuilder(FlatBufferBuilder &&other)
101 : buf_(1024, nullptr, false, AlignOf<largest_scalar_t>()),
102 num_field_loc(0),
103 max_voffset_(0),
104 nested(false),
105 finished(false),
106 minalign_(1),
107 force_defaults_(false),
108 dedup_vtables_(true),
109 string_pool(nullptr) {
110 EndianCheck();
111 // Default construct and swap idiom.
112 // Lack of delegating constructors in vs2010 makes it more verbose than
113 // needed.
114 Swap(other);
115 }
116
117 /// @brief Move assignment operator for FlatBufferBuilder.
118 FlatBufferBuilder &operator=(FlatBufferBuilder &&other) {
119 // Move construct a temporary and swap idiom
120 FlatBufferBuilder temp(std::move(other));
121 Swap(temp);
122 return *this;
123 }
124
Swap(FlatBufferBuilder & other)125 void Swap(FlatBufferBuilder &other) {
126 using std::swap;
127 buf_.swap(other.buf_);
128 swap(num_field_loc, other.num_field_loc);
129 swap(max_voffset_, other.max_voffset_);
130 swap(nested, other.nested);
131 swap(finished, other.finished);
132 swap(minalign_, other.minalign_);
133 swap(force_defaults_, other.force_defaults_);
134 swap(dedup_vtables_, other.dedup_vtables_);
135 swap(string_pool, other.string_pool);
136 }
137
~FlatBufferBuilder()138 ~FlatBufferBuilder() {
139 if (string_pool) delete string_pool;
140 }
141
Reset()142 void Reset() {
143 Clear(); // clear builder state
144 buf_.reset(); // deallocate buffer
145 }
146
147 /// @brief Reset all the state in this FlatBufferBuilder so it can be reused
148 /// to construct another buffer.
Clear()149 void Clear() {
150 ClearOffsets();
151 buf_.clear();
152 nested = false;
153 finished = false;
154 minalign_ = 1;
155 if (string_pool) string_pool->clear();
156 }
157
158 /// @brief The current size of the serialized buffer, counting from the end.
159 /// @return Returns an `uoffset_t` with the current size of the buffer.
GetSize()160 uoffset_t GetSize() const { return buf_.size(); }
161
162 /// @brief Get the serialized buffer (after you call `Finish()`).
163 /// @return Returns an `uint8_t` pointer to the FlatBuffer data inside the
164 /// buffer.
GetBufferPointer()165 uint8_t *GetBufferPointer() const {
166 Finished();
167 return buf_.data();
168 }
169
170 /// @brief Get the serialized buffer (after you call `Finish()`) as a span.
171 /// @return Returns a constructed flatbuffers::span that is a view over the
172 /// FlatBuffer data inside the buffer.
GetBufferSpan()173 flatbuffers::span<uint8_t> GetBufferSpan() const {
174 Finished();
175 return flatbuffers::span<uint8_t>(buf_.data(), buf_.size());
176 }
177
178 /// @brief Get a pointer to an unfinished buffer.
179 /// @return Returns a `uint8_t` pointer to the unfinished buffer.
GetCurrentBufferPointer()180 uint8_t *GetCurrentBufferPointer() const { return buf_.data(); }
181
182 /// @brief Get the released pointer to the serialized buffer.
183 /// @warning Do NOT attempt to use this FlatBufferBuilder afterwards!
184 /// @return A `FlatBuffer` that owns the buffer and its allocator and
185 /// behaves similar to a `unique_ptr` with a deleter.
FLATBUFFERS_ATTRIBUTE()186 FLATBUFFERS_ATTRIBUTE([[deprecated("use Release() instead")]])
187 DetachedBuffer ReleaseBufferPointer() {
188 Finished();
189 return buf_.release();
190 }
191
192 /// @brief Get the released DetachedBuffer.
193 /// @return A `DetachedBuffer` that owns the buffer and its allocator.
Release()194 DetachedBuffer Release() {
195 Finished();
196 return buf_.release();
197 }
198
199 /// @brief Get the released pointer to the serialized buffer.
200 /// @param size The size of the memory block containing
201 /// the serialized `FlatBuffer`.
202 /// @param offset The offset from the released pointer where the finished
203 /// `FlatBuffer` starts.
204 /// @return A raw pointer to the start of the memory block containing
205 /// the serialized `FlatBuffer`.
206 /// @remark If the allocator is owned, it gets deleted when the destructor is
207 /// called..
ReleaseRaw(size_t & size,size_t & offset)208 uint8_t *ReleaseRaw(size_t &size, size_t &offset) {
209 Finished();
210 return buf_.release_raw(size, offset);
211 }
212
213 /// @brief get the minimum alignment this buffer needs to be accessed
214 /// properly. This is only known once all elements have been written (after
215 /// you call Finish()). You can use this information if you need to embed
216 /// a FlatBuffer in some other buffer, such that you can later read it
217 /// without first having to copy it into its own buffer.
GetBufferMinAlignment()218 size_t GetBufferMinAlignment() const {
219 Finished();
220 return minalign_;
221 }
222
223 /// @cond FLATBUFFERS_INTERNAL
Finished()224 void Finished() const {
225 // If you get this assert, you're attempting to get access a buffer
226 // which hasn't been finished yet. Be sure to call
227 // FlatBufferBuilder::Finish with your root table.
228 // If you really need to access an unfinished buffer, call
229 // GetCurrentBufferPointer instead.
230 FLATBUFFERS_ASSERT(finished);
231 }
232 /// @endcond
233
234 /// @brief In order to save space, fields that are set to their default value
235 /// don't get serialized into the buffer.
236 /// @param[in] fd When set to `true`, always serializes default values that
237 /// are set. Optional fields which are not set explicitly, will still not be
238 /// serialized.
ForceDefaults(bool fd)239 void ForceDefaults(bool fd) { force_defaults_ = fd; }
240
241 /// @brief By default vtables are deduped in order to save space.
242 /// @param[in] dedup When set to `true`, dedup vtables.
DedupVtables(bool dedup)243 void DedupVtables(bool dedup) { dedup_vtables_ = dedup; }
244
245 /// @cond FLATBUFFERS_INTERNAL
Pad(size_t num_bytes)246 void Pad(size_t num_bytes) { buf_.fill(num_bytes); }
247
TrackMinAlign(size_t elem_size)248 void TrackMinAlign(size_t elem_size) {
249 if (elem_size > minalign_) minalign_ = elem_size;
250 }
251
Align(size_t elem_size)252 void Align(size_t elem_size) {
253 TrackMinAlign(elem_size);
254 buf_.fill(PaddingBytes(buf_.size(), elem_size));
255 }
256
PushFlatBuffer(const uint8_t * bytes,size_t size)257 void PushFlatBuffer(const uint8_t *bytes, size_t size) {
258 PushBytes(bytes, size);
259 finished = true;
260 }
261
PushBytes(const uint8_t * bytes,size_t size)262 void PushBytes(const uint8_t *bytes, size_t size) { buf_.push(bytes, size); }
263
PopBytes(size_t amount)264 void PopBytes(size_t amount) { buf_.pop(amount); }
265
AssertScalarT()266 template<typename T> void AssertScalarT() {
267 // The code assumes power of 2 sizes and endian-swap-ability.
268 static_assert(flatbuffers::is_scalar<T>::value, "T must be a scalar type");
269 }
270
271 // Write a single aligned scalar to the buffer
PushElement(T element)272 template<typename T> uoffset_t PushElement(T element) {
273 AssertScalarT<T>();
274 Align(sizeof(T));
275 buf_.push_small(EndianScalar(element));
276 return GetSize();
277 }
278
PushElement(Offset<T> off)279 template<typename T> uoffset_t PushElement(Offset<T> off) {
280 // Special case for offsets: see ReferTo below.
281 return PushElement(ReferTo(off.o));
282 }
283
284 // When writing fields, we track where they are, so we can create correct
285 // vtables later.
TrackField(voffset_t field,uoffset_t off)286 void TrackField(voffset_t field, uoffset_t off) {
287 FieldLoc fl = { off, field };
288 buf_.scratch_push_small(fl);
289 num_field_loc++;
290 if (field > max_voffset_) { max_voffset_ = field; }
291 }
292
293 // Like PushElement, but additionally tracks the field this represents.
AddElement(voffset_t field,T e,T def)294 template<typename T> void AddElement(voffset_t field, T e, T def) {
295 // We don't serialize values equal to the default.
296 if (IsTheSameAs(e, def) && !force_defaults_) return;
297 TrackField(field, PushElement(e));
298 }
299
AddElement(voffset_t field,T e)300 template<typename T> void AddElement(voffset_t field, T e) {
301 TrackField(field, PushElement(e));
302 }
303
AddOffset(voffset_t field,Offset<T> off)304 template<typename T> void AddOffset(voffset_t field, Offset<T> off) {
305 if (off.IsNull()) return; // Don't store.
306 AddElement(field, ReferTo(off.o), static_cast<uoffset_t>(0));
307 }
308
AddStruct(voffset_t field,const T * structptr)309 template<typename T> void AddStruct(voffset_t field, const T *structptr) {
310 if (!structptr) return; // Default, don't store.
311 Align(AlignOf<T>());
312 buf_.push_small(*structptr);
313 TrackField(field, GetSize());
314 }
315
AddStructOffset(voffset_t field,uoffset_t off)316 void AddStructOffset(voffset_t field, uoffset_t off) {
317 TrackField(field, off);
318 }
319
320 // Offsets initially are relative to the end of the buffer (downwards).
321 // This function converts them to be relative to the current location
322 // in the buffer (when stored here), pointing upwards.
ReferTo(uoffset_t off)323 uoffset_t ReferTo(uoffset_t off) {
324 // Align to ensure GetSize() below is correct.
325 Align(sizeof(uoffset_t));
326 // Offset must refer to something already in buffer.
327 const uoffset_t size = GetSize();
328 FLATBUFFERS_ASSERT(off && off <= size);
329 return size - off + static_cast<uoffset_t>(sizeof(uoffset_t));
330 }
331
NotNested()332 void NotNested() {
333 // If you hit this, you're trying to construct a Table/Vector/String
334 // during the construction of its parent table (between the MyTableBuilder
335 // and table.Finish().
336 // Move the creation of these sub-objects to above the MyTableBuilder to
337 // not get this assert.
338 // Ignoring this assert may appear to work in simple cases, but the reason
339 // it is here is that storing objects in-line may cause vtable offsets
340 // to not fit anymore. It also leads to vtable duplication.
341 FLATBUFFERS_ASSERT(!nested);
342 // If you hit this, fields were added outside the scope of a table.
343 FLATBUFFERS_ASSERT(!num_field_loc);
344 }
345
346 // From generated code (or from the parser), we call StartTable/EndTable
347 // with a sequence of AddElement calls in between.
StartTable()348 uoffset_t StartTable() {
349 NotNested();
350 nested = true;
351 return GetSize();
352 }
353
354 // This finishes one serialized object by generating the vtable if it's a
355 // table, comparing it against existing vtables, and writing the
356 // resulting vtable offset.
EndTable(uoffset_t start)357 uoffset_t EndTable(uoffset_t start) {
358 // If you get this assert, a corresponding StartTable wasn't called.
359 FLATBUFFERS_ASSERT(nested);
360 // Write the vtable offset, which is the start of any Table.
361 // We fill it's value later.
362 auto vtableoffsetloc = PushElement<soffset_t>(0);
363 // Write a vtable, which consists entirely of voffset_t elements.
364 // It starts with the number of offsets, followed by a type id, followed
365 // by the offsets themselves. In reverse:
366 // Include space for the last offset and ensure empty tables have a
367 // minimum size.
368 max_voffset_ =
369 (std::max)(static_cast<voffset_t>(max_voffset_ + sizeof(voffset_t)),
370 FieldIndexToOffset(0));
371 buf_.fill_big(max_voffset_);
372 auto table_object_size = vtableoffsetloc - start;
373 // Vtable use 16bit offsets.
374 FLATBUFFERS_ASSERT(table_object_size < 0x10000);
375 WriteScalar<voffset_t>(buf_.data() + sizeof(voffset_t),
376 static_cast<voffset_t>(table_object_size));
377 WriteScalar<voffset_t>(buf_.data(), max_voffset_);
378 // Write the offsets into the table
379 for (auto it = buf_.scratch_end() - num_field_loc * sizeof(FieldLoc);
380 it < buf_.scratch_end(); it += sizeof(FieldLoc)) {
381 auto field_location = reinterpret_cast<FieldLoc *>(it);
382 auto pos = static_cast<voffset_t>(vtableoffsetloc - field_location->off);
383 // If this asserts, it means you've set a field twice.
384 FLATBUFFERS_ASSERT(
385 !ReadScalar<voffset_t>(buf_.data() + field_location->id));
386 WriteScalar<voffset_t>(buf_.data() + field_location->id, pos);
387 }
388 ClearOffsets();
389 auto vt1 = reinterpret_cast<voffset_t *>(buf_.data());
390 auto vt1_size = ReadScalar<voffset_t>(vt1);
391 auto vt_use = GetSize();
392 // See if we already have generated a vtable with this exact same
393 // layout before. If so, make it point to the old one, remove this one.
394 if (dedup_vtables_) {
395 for (auto it = buf_.scratch_data(); it < buf_.scratch_end();
396 it += sizeof(uoffset_t)) {
397 auto vt_offset_ptr = reinterpret_cast<uoffset_t *>(it);
398 auto vt2 = reinterpret_cast<voffset_t *>(buf_.data_at(*vt_offset_ptr));
399 auto vt2_size = ReadScalar<voffset_t>(vt2);
400 if (vt1_size != vt2_size || 0 != memcmp(vt2, vt1, vt1_size)) continue;
401 vt_use = *vt_offset_ptr;
402 buf_.pop(GetSize() - vtableoffsetloc);
403 break;
404 }
405 }
406 // If this is a new vtable, remember it.
407 if (vt_use == GetSize()) { buf_.scratch_push_small(vt_use); }
408 // Fill the vtable offset we created above.
409 // The offset points from the beginning of the object to where the
410 // vtable is stored.
411 // Offsets default direction is downward in memory for future format
412 // flexibility (storing all vtables at the start of the file).
413 WriteScalar(buf_.data_at(vtableoffsetloc),
414 static_cast<soffset_t>(vt_use) -
415 static_cast<soffset_t>(vtableoffsetloc));
416
417 nested = false;
418 return vtableoffsetloc;
419 }
420
FLATBUFFERS_ATTRIBUTE()421 FLATBUFFERS_ATTRIBUTE([[deprecated("call the version above instead")]])
422 uoffset_t EndTable(uoffset_t start, voffset_t /*numfields*/) {
423 return EndTable(start);
424 }
425
426 // This checks a required field has been set in a given table that has
427 // just been constructed.
428 template<typename T> void Required(Offset<T> table, voffset_t field);
429
StartStruct(size_t alignment)430 uoffset_t StartStruct(size_t alignment) {
431 Align(alignment);
432 return GetSize();
433 }
434
EndStruct()435 uoffset_t EndStruct() { return GetSize(); }
436
ClearOffsets()437 void ClearOffsets() {
438 buf_.scratch_pop(num_field_loc * sizeof(FieldLoc));
439 num_field_loc = 0;
440 max_voffset_ = 0;
441 }
442
443 // Aligns such that when "len" bytes are written, an object can be written
444 // after it with "alignment" without padding.
PreAlign(size_t len,size_t alignment)445 void PreAlign(size_t len, size_t alignment) {
446 if (len == 0) return;
447 TrackMinAlign(alignment);
448 buf_.fill(PaddingBytes(GetSize() + len, alignment));
449 }
PreAlign(size_t len)450 template<typename T> void PreAlign(size_t len) {
451 AssertScalarT<T>();
452 PreAlign(len, sizeof(T));
453 }
454 /// @endcond
455
456 /// @brief Store a string in the buffer, which can contain any binary data.
457 /// @param[in] str A const char pointer to the data to be stored as a string.
458 /// @param[in] len The number of bytes that should be stored from `str`.
459 /// @return Returns the offset in the buffer where the string starts.
CreateString(const char * str,size_t len)460 Offset<String> CreateString(const char *str, size_t len) {
461 NotNested();
462 PreAlign<uoffset_t>(len + 1); // Always 0-terminated.
463 buf_.fill(1);
464 PushBytes(reinterpret_cast<const uint8_t *>(str), len);
465 PushElement(static_cast<uoffset_t>(len));
466 return Offset<String>(GetSize());
467 }
468
469 /// @brief Store a string in the buffer, which is null-terminated.
470 /// @param[in] str A const char pointer to a C-string to add to the buffer.
471 /// @return Returns the offset in the buffer where the string starts.
CreateString(const char * str)472 Offset<String> CreateString(const char *str) {
473 return CreateString(str, strlen(str));
474 }
475
476 /// @brief Store a string in the buffer, which is null-terminated.
477 /// @param[in] str A char pointer to a C-string to add to the buffer.
478 /// @return Returns the offset in the buffer where the string starts.
CreateString(char * str)479 Offset<String> CreateString(char *str) {
480 return CreateString(str, strlen(str));
481 }
482
483 /// @brief Store a string in the buffer, which can contain any binary data.
484 /// @param[in] str A const reference to a std::string to store in the buffer.
485 /// @return Returns the offset in the buffer where the string starts.
CreateString(const std::string & str)486 Offset<String> CreateString(const std::string &str) {
487 return CreateString(str.c_str(), str.length());
488 }
489
490 // clang-format off
491 #ifdef FLATBUFFERS_HAS_STRING_VIEW
492 /// @brief Store a string in the buffer, which can contain any binary data.
493 /// @param[in] str A const string_view to copy in to the buffer.
494 /// @return Returns the offset in the buffer where the string starts.
CreateString(flatbuffers::string_view str)495 Offset<String> CreateString(flatbuffers::string_view str) {
496 return CreateString(str.data(), str.size());
497 }
498 #endif // FLATBUFFERS_HAS_STRING_VIEW
499 // clang-format on
500
501 /// @brief Store a string in the buffer, which can contain any binary data.
502 /// @param[in] str A const pointer to a `String` struct to add to the buffer.
503 /// @return Returns the offset in the buffer where the string starts
CreateString(const String * str)504 Offset<String> CreateString(const String *str) {
505 return str ? CreateString(str->c_str(), str->size()) : 0;
506 }
507
508 /// @brief Store a string in the buffer, which can contain any binary data.
509 /// @param[in] str A const reference to a std::string like type with support
510 /// of T::c_str() and T::length() to store in the buffer.
511 /// @return Returns the offset in the buffer where the string starts.
CreateString(const T & str)512 template<typename T> Offset<String> CreateString(const T &str) {
513 return CreateString(str.c_str(), str.length());
514 }
515
516 /// @brief Store a string in the buffer, which can contain any binary data.
517 /// If a string with this exact contents has already been serialized before,
518 /// instead simply returns the offset of the existing string. This uses a map
519 /// stored on the heap, but only stores the numerical offsets.
520 /// @param[in] str A const char pointer to the data to be stored as a string.
521 /// @param[in] len The number of bytes that should be stored from `str`.
522 /// @return Returns the offset in the buffer where the string starts.
CreateSharedString(const char * str,size_t len)523 Offset<String> CreateSharedString(const char *str, size_t len) {
524 FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK);
525 if (!string_pool)
526 string_pool = new StringOffsetMap(StringOffsetCompare(buf_));
527 auto size_before_string = buf_.size();
528 // Must first serialize the string, since the set is all offsets into
529 // buffer.
530 auto off = CreateString(str, len);
531 auto it = string_pool->find(off);
532 // If it exists we reuse existing serialized data!
533 if (it != string_pool->end()) {
534 // We can remove the string we serialized.
535 buf_.pop(buf_.size() - size_before_string);
536 return *it;
537 }
538 // Record this string for future use.
539 string_pool->insert(off);
540 return off;
541 }
542
543 #ifdef FLATBUFFERS_HAS_STRING_VIEW
544 /// @brief Store a string in the buffer, which can contain any binary data.
545 /// If a string with this exact contents has already been serialized before,
546 /// instead simply returns the offset of the existing string. This uses a map
547 /// stored on the heap, but only stores the numerical offsets.
548 /// @param[in] str A const std::string_view to store in the buffer.
549 /// @return Returns the offset in the buffer where the string starts
CreateSharedString(const flatbuffers::string_view str)550 Offset<String> CreateSharedString(const flatbuffers::string_view str) {
551 return CreateSharedString(str.data(), str.size());
552 }
553 #else
554 /// @brief Store a string in the buffer, which null-terminated.
555 /// If a string with this exact contents has already been serialized before,
556 /// instead simply returns the offset of the existing string. This uses a map
557 /// stored on the heap, but only stores the numerical offsets.
558 /// @param[in] str A const char pointer to a C-string to add to the buffer.
559 /// @return Returns the offset in the buffer where the string starts.
CreateSharedString(const char * str)560 Offset<String> CreateSharedString(const char *str) {
561 return CreateSharedString(str, strlen(str));
562 }
563
564 /// @brief Store a string in the buffer, which can contain any binary data.
565 /// If a string with this exact contents has already been serialized before,
566 /// instead simply returns the offset of the existing string. This uses a map
567 /// stored on the heap, but only stores the numerical offsets.
568 /// @param[in] str A const reference to a std::string to store in the buffer.
569 /// @return Returns the offset in the buffer where the string starts.
CreateSharedString(const std::string & str)570 Offset<String> CreateSharedString(const std::string &str) {
571 return CreateSharedString(str.c_str(), str.length());
572 }
573 #endif
574
575 /// @brief Store a string in the buffer, which can contain any binary data.
576 /// If a string with this exact contents has already been serialized before,
577 /// instead simply returns the offset of the existing string. This uses a map
578 /// stored on the heap, but only stores the numerical offsets.
579 /// @param[in] str A const pointer to a `String` struct to add to the buffer.
580 /// @return Returns the offset in the buffer where the string starts
CreateSharedString(const String * str)581 Offset<String> CreateSharedString(const String *str) {
582 return CreateSharedString(str->c_str(), str->size());
583 }
584
585 /// @cond FLATBUFFERS_INTERNAL
EndVector(size_t len)586 uoffset_t EndVector(size_t len) {
587 FLATBUFFERS_ASSERT(nested); // Hit if no corresponding StartVector.
588 nested = false;
589 return PushElement(static_cast<uoffset_t>(len));
590 }
591
StartVector(size_t len,size_t elemsize)592 void StartVector(size_t len, size_t elemsize) {
593 NotNested();
594 nested = true;
595 PreAlign<uoffset_t>(len * elemsize);
596 PreAlign(len * elemsize, elemsize); // Just in case elemsize > uoffset_t.
597 }
598
599 // Call this right before StartVector/CreateVector if you want to force the
600 // alignment to be something different than what the element size would
601 // normally dictate.
602 // This is useful when storing a nested_flatbuffer in a vector of bytes,
603 // or when storing SIMD floats, etc.
ForceVectorAlignment(size_t len,size_t elemsize,size_t alignment)604 void ForceVectorAlignment(size_t len, size_t elemsize, size_t alignment) {
605 if (len == 0) return;
606 FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment));
607 PreAlign(len * elemsize, alignment);
608 }
609
610 // Similar to ForceVectorAlignment but for String fields.
ForceStringAlignment(size_t len,size_t alignment)611 void ForceStringAlignment(size_t len, size_t alignment) {
612 if (len == 0) return;
613 FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment));
614 PreAlign((len + 1) * sizeof(char), alignment);
615 }
616
617 /// @endcond
618
619 /// @brief Serialize an array into a FlatBuffer `vector`.
620 /// @tparam T The data type of the array elements.
621 /// @param[in] v A pointer to the array of type `T` to serialize into the
622 /// buffer as a `vector`.
623 /// @param[in] len The number of elements to serialize.
624 /// @return Returns a typed `Offset` into the serialized data indicating
625 /// where the vector is stored.
CreateVector(const T * v,size_t len)626 template<typename T> Offset<Vector<T>> CreateVector(const T *v, size_t len) {
627 // If this assert hits, you're specifying a template argument that is
628 // causing the wrong overload to be selected, remove it.
629 AssertScalarT<T>();
630 StartVector(len, sizeof(T));
631 if (len == 0) { return Offset<Vector<T>>(EndVector(len)); }
632 // clang-format off
633 #if FLATBUFFERS_LITTLEENDIAN
634 PushBytes(reinterpret_cast<const uint8_t *>(v), len * sizeof(T));
635 #else
636 if (sizeof(T) == 1) {
637 PushBytes(reinterpret_cast<const uint8_t *>(v), len);
638 } else {
639 for (auto i = len; i > 0; ) {
640 PushElement(v[--i]);
641 }
642 }
643 #endif
644 // clang-format on
645 return Offset<Vector<T>>(EndVector(len));
646 }
647
648 /// @brief Serialize an array like object into a FlatBuffer `vector`.
649 /// @tparam T The data type of the array elements.
650 /// @tparam C The type of the array.
651 /// @param[in] array A reference to an array like object of type `T` to
652 /// serialize into the buffer as a `vector`.
653 /// @return Returns a typed `Offset` into the serialized data indicating
654 /// where the vector is stored.
CreateVector(const C & array)655 template<typename T, class C> Offset<Vector<T>> CreateVector(const C &array) {
656 return CreateVector(array.data(), array.size());
657 }
658
659 /// @brief Serialize an initializer list into a FlatBuffer `vector`.
660 /// @tparam T The data type of the initializer list elements.
661 /// @param[in] v The value of the initializer list.
662 /// @return Returns a typed `Offset` into the serialized data indicating
663 /// where the vector is stored.
664 template<typename T>
CreateVector(std::initializer_list<T> v)665 Offset<Vector<T>> CreateVector(std::initializer_list<T> v) {
666 return CreateVector(v.begin(), v.size());
667 }
668
669 template<typename T>
CreateVector(const Offset<T> * v,size_t len)670 Offset<Vector<Offset<T>>> CreateVector(const Offset<T> *v, size_t len) {
671 StartVector(len, sizeof(Offset<T>));
672 for (auto i = len; i > 0;) { PushElement(v[--i]); }
673 return Offset<Vector<Offset<T>>>(EndVector(len));
674 }
675
676 /// @brief Serialize a `std::vector` into a FlatBuffer `vector`.
677 /// @tparam T The data type of the `std::vector` elements.
678 /// @param v A const reference to the `std::vector` to serialize into the
679 /// buffer as a `vector`.
680 /// @return Returns a typed `Offset` into the serialized data indicating
681 /// where the vector is stored.
682 template<typename T, typename Alloc = std::allocator<T>>
CreateVector(const std::vector<T,Alloc> & v)683 Offset<Vector<T>> CreateVector(const std::vector<T, Alloc> &v) {
684 return CreateVector(data(v), v.size());
685 }
686
687 // vector<bool> may be implemented using a bit-set, so we can't access it as
688 // an array. Instead, read elements manually.
689 // Background: https://isocpp.org/blog/2012/11/on-vectorbool
CreateVector(const std::vector<bool> & v)690 Offset<Vector<uint8_t>> CreateVector(const std::vector<bool> &v) {
691 StartVector(v.size(), sizeof(uint8_t));
692 for (auto i = v.size(); i > 0;) {
693 PushElement(static_cast<uint8_t>(v[--i]));
694 }
695 return Offset<Vector<uint8_t>>(EndVector(v.size()));
696 }
697
698 /// @brief Serialize values returned by a function into a FlatBuffer `vector`.
699 /// This is a convenience function that takes care of iteration for you.
700 /// @tparam T The data type of the `std::vector` elements.
701 /// @param f A function that takes the current iteration 0..vector_size-1 and
702 /// returns any type that you can construct a FlatBuffers vector out of.
703 /// @return Returns a typed `Offset` into the serialized data indicating
704 /// where the vector is stored.
705 template<typename T>
CreateVector(size_t vector_size,const std::function<T (size_t i)> & f)706 Offset<Vector<T>> CreateVector(size_t vector_size,
707 const std::function<T(size_t i)> &f) {
708 FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK);
709 std::vector<T> elems(vector_size);
710 for (size_t i = 0; i < vector_size; i++) elems[i] = f(i);
711 return CreateVector(elems);
712 }
713
714 /// @brief Serialize values returned by a function into a FlatBuffer `vector`.
715 /// This is a convenience function that takes care of iteration for you. This
716 /// uses a vector stored on the heap to store the intermediate results of the
717 /// iteration.
718 /// @tparam T The data type of the `std::vector` elements.
719 /// @param f A function that takes the current iteration 0..vector_size-1,
720 /// and the state parameter returning any type that you can construct a
721 /// FlatBuffers vector out of.
722 /// @param state State passed to f.
723 /// @return Returns a typed `Offset` into the serialized data indicating
724 /// where the vector is stored.
725 template<typename T, typename F, typename S>
CreateVector(size_t vector_size,F f,S * state)726 Offset<Vector<T>> CreateVector(size_t vector_size, F f, S *state) {
727 FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK);
728 std::vector<T> elems(vector_size);
729 for (size_t i = 0; i < vector_size; i++) elems[i] = f(i, state);
730 return CreateVector(elems);
731 }
732
733 /// @brief Serialize a `std::vector<StringType>` into a FlatBuffer `vector`.
734 /// whereas StringType is any type that is accepted by the CreateString()
735 /// overloads.
736 /// This is a convenience function for a common case.
737 /// @param v A const reference to the `std::vector` to serialize into the
738 /// buffer as a `vector`.
739 /// @return Returns a typed `Offset` into the serialized data indicating
740 /// where the vector is stored.
741 template<typename StringType = std::string,
742 typename Alloc = std::allocator<StringType>>
CreateVectorOfStrings(const std::vector<StringType,Alloc> & v)743 Offset<Vector<Offset<String>>> CreateVectorOfStrings(
744 const std::vector<StringType, Alloc> &v) {
745 return CreateVectorOfStrings(v.cbegin(), v.cend());
746 }
747
748 /// @brief Serialize a collection of Strings into a FlatBuffer `vector`.
749 /// This is a convenience function for a common case.
750 /// @param begin The begining iterator of the collection
751 /// @param end The ending iterator of the collection
752 /// @return Returns a typed `Offset` into the serialized data indicating
753 /// where the vector is stored.
754 template<class It>
CreateVectorOfStrings(It begin,It end)755 Offset<Vector<Offset<String>>> CreateVectorOfStrings(It begin, It end) {
756 auto size = std::distance(begin, end);
757 auto scratch_buffer_usage = size * sizeof(Offset<String>);
758 // If there is not enough space to store the offsets, there definitely won't
759 // be enough space to store all the strings. So ensuring space for the
760 // scratch region is OK, for it it fails, it would have failed later.
761 buf_.ensure_space(scratch_buffer_usage);
762 for (auto it = begin; it != end; ++it) {
763 buf_.scratch_push_small(CreateString(*it));
764 }
765 StartVector(size, sizeof(Offset<String>));
766 for (auto i = 1; i <= size; i++) {
767 // Note we re-evaluate the buf location each iteration to account for any
768 // underlying buffer resizing that may occur.
769 PushElement(*reinterpret_cast<Offset<String> *>(
770 buf_.scratch_end() - i * sizeof(Offset<String>)));
771 }
772 buf_.scratch_pop(scratch_buffer_usage);
773 return Offset<Vector<Offset<String>>>(EndVector(size));
774 }
775
776 /// @brief Serialize an array of structs into a FlatBuffer `vector`.
777 /// @tparam T The data type of the struct array elements.
778 /// @param[in] v A pointer to the array of type `T` to serialize into the
779 /// buffer as a `vector`.
780 /// @param[in] len The number of elements to serialize.
781 /// @return Returns a typed `Offset` into the serialized data indicating
782 /// where the vector is stored.
783 template<typename T>
CreateVectorOfStructs(const T * v,size_t len)784 Offset<Vector<const T *>> CreateVectorOfStructs(const T *v, size_t len) {
785 StartVector(len * sizeof(T) / AlignOf<T>(), AlignOf<T>());
786 if (len > 0) {
787 PushBytes(reinterpret_cast<const uint8_t *>(v), sizeof(T) * len);
788 }
789 return Offset<Vector<const T *>>(EndVector(len));
790 }
791
792 /// @brief Serialize an array of native structs into a FlatBuffer `vector`.
793 /// @tparam T The data type of the struct array elements.
794 /// @tparam S The data type of the native struct array elements.
795 /// @param[in] v A pointer to the array of type `S` to serialize into the
796 /// buffer as a `vector`.
797 /// @param[in] len The number of elements to serialize.
798 /// @param[in] pack_func Pointer to a function to convert the native struct
799 /// to the FlatBuffer struct.
800 /// @return Returns a typed `Offset` into the serialized data indicating
801 /// where the vector is stored.
802 template<typename T, typename S>
CreateVectorOfNativeStructs(const S * v,size_t len,T (* const pack_func)(const S &))803 Offset<Vector<const T *>> CreateVectorOfNativeStructs(
804 const S *v, size_t len, T (*const pack_func)(const S &)) {
805 FLATBUFFERS_ASSERT(pack_func);
806 auto structs = StartVectorOfStructs<T>(len);
807 for (size_t i = 0; i < len; i++) { structs[i] = pack_func(v[i]); }
808 return EndVectorOfStructs<T>(len);
809 }
810
811 /// @brief Serialize an array of native structs into a FlatBuffer `vector`.
812 /// @tparam T The data type of the struct array elements.
813 /// @tparam S The data type of the native struct array elements.
814 /// @param[in] v A pointer to the array of type `S` to serialize into the
815 /// buffer as a `vector`.
816 /// @param[in] len The number of elements to serialize.
817 /// @return Returns a typed `Offset` into the serialized data indicating
818 /// where the vector is stored.
819 template<typename T, typename S>
CreateVectorOfNativeStructs(const S * v,size_t len)820 Offset<Vector<const T *>> CreateVectorOfNativeStructs(const S *v,
821 size_t len) {
822 extern T Pack(const S &);
823 return CreateVectorOfNativeStructs(v, len, Pack);
824 }
825
826 /// @brief Serialize an array of structs into a FlatBuffer `vector`.
827 /// @tparam T The data type of the struct array elements.
828 /// @param[in] filler A function that takes the current iteration
829 /// 0..vector_size-1 and a pointer to the struct that must be filled.
830 /// @return Returns a typed `Offset` into the serialized data indicating
831 /// where the vector is stored.
832 /// This is mostly useful when flatbuffers are generated with mutation
833 /// accessors.
834 template<typename T>
CreateVectorOfStructs(size_t vector_size,const std::function<void (size_t i,T *)> & filler)835 Offset<Vector<const T *>> CreateVectorOfStructs(
836 size_t vector_size, const std::function<void(size_t i, T *)> &filler) {
837 T *structs = StartVectorOfStructs<T>(vector_size);
838 for (size_t i = 0; i < vector_size; i++) {
839 filler(i, structs);
840 structs++;
841 }
842 return EndVectorOfStructs<T>(vector_size);
843 }
844
845 /// @brief Serialize an array of structs into a FlatBuffer `vector`.
846 /// @tparam T The data type of the struct array elements.
847 /// @param[in] f A function that takes the current iteration 0..vector_size-1,
848 /// a pointer to the struct that must be filled and the state argument.
849 /// @param[in] state Arbitrary state to pass to f.
850 /// @return Returns a typed `Offset` into the serialized data indicating
851 /// where the vector is stored.
852 /// This is mostly useful when flatbuffers are generated with mutation
853 /// accessors.
854 template<typename T, typename F, typename S>
CreateVectorOfStructs(size_t vector_size,F f,S * state)855 Offset<Vector<const T *>> CreateVectorOfStructs(size_t vector_size, F f,
856 S *state) {
857 T *structs = StartVectorOfStructs<T>(vector_size);
858 for (size_t i = 0; i < vector_size; i++) {
859 f(i, structs, state);
860 structs++;
861 }
862 return EndVectorOfStructs<T>(vector_size);
863 }
864
865 /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`.
866 /// @tparam T The data type of the `std::vector` struct elements.
867 /// @param[in] v A const reference to the `std::vector` of structs to
868 /// serialize into the buffer as a `vector`.
869 /// @return Returns a typed `Offset` into the serialized data indicating
870 /// where the vector is stored.
871 template<typename T, typename Alloc = std::allocator<T>>
CreateVectorOfStructs(const std::vector<T,Alloc> & v)872 Offset<Vector<const T *>> CreateVectorOfStructs(
873 const std::vector<T, Alloc> &v) {
874 return CreateVectorOfStructs(data(v), v.size());
875 }
876
877 /// @brief Serialize a `std::vector` of native structs into a FlatBuffer
878 /// `vector`.
879 /// @tparam T The data type of the `std::vector` struct elements.
880 /// @tparam S The data type of the `std::vector` native struct elements.
881 /// @param[in] v A const reference to the `std::vector` of structs to
882 /// serialize into the buffer as a `vector`.
883 /// @param[in] pack_func Pointer to a function to convert the native struct
884 /// to the FlatBuffer struct.
885 /// @return Returns a typed `Offset` into the serialized data indicating
886 /// where the vector is stored.
887 template<typename T, typename S, typename Alloc = std::allocator<T>>
CreateVectorOfNativeStructs(const std::vector<S,Alloc> & v,T (* const pack_func)(const S &))888 Offset<Vector<const T *>> CreateVectorOfNativeStructs(
889 const std::vector<S, Alloc> &v, T (*const pack_func)(const S &)) {
890 return CreateVectorOfNativeStructs<T, S>(data(v), v.size(), pack_func);
891 }
892
893 /// @brief Serialize a `std::vector` of native structs into a FlatBuffer
894 /// `vector`.
895 /// @tparam T The data type of the `std::vector` struct elements.
896 /// @tparam S The data type of the `std::vector` native struct elements.
897 /// @param[in] v A const reference to the `std::vector` of structs to
898 /// serialize into the buffer as a `vector`.
899 /// @return Returns a typed `Offset` into the serialized data indicating
900 /// where the vector is stored.
901 template<typename T, typename S, typename Alloc = std::allocator<S>>
CreateVectorOfNativeStructs(const std::vector<S,Alloc> & v)902 Offset<Vector<const T *>> CreateVectorOfNativeStructs(
903 const std::vector<S, Alloc> &v) {
904 return CreateVectorOfNativeStructs<T, S>(data(v), v.size());
905 }
906
907 /// @cond FLATBUFFERS_INTERNAL
908 template<typename T> struct StructKeyComparator {
operatorStructKeyComparator909 bool operator()(const T &a, const T &b) const {
910 return a.KeyCompareLessThan(&b);
911 }
912 };
913 /// @endcond
914
915 /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`
916 /// in sorted order.
917 /// @tparam T The data type of the `std::vector` struct elements.
918 /// @param[in] v A const reference to the `std::vector` of structs to
919 /// serialize into the buffer as a `vector`.
920 /// @return Returns a typed `Offset` into the serialized data indicating
921 /// where the vector is stored.
922 template<typename T, typename Alloc = std::allocator<T>>
CreateVectorOfSortedStructs(std::vector<T,Alloc> * v)923 Offset<Vector<const T *>> CreateVectorOfSortedStructs(
924 std::vector<T, Alloc> *v) {
925 return CreateVectorOfSortedStructs(data(*v), v->size());
926 }
927
928 /// @brief Serialize a `std::vector` of native structs into a FlatBuffer
929 /// `vector` in sorted order.
930 /// @tparam T The data type of the `std::vector` struct elements.
931 /// @tparam S The data type of the `std::vector` native struct elements.
932 /// @param[in] v A const reference to the `std::vector` of structs to
933 /// serialize into the buffer as a `vector`.
934 /// @return Returns a typed `Offset` into the serialized data indicating
935 /// where the vector is stored.
936 template<typename T, typename S, typename Alloc = std::allocator<T>>
CreateVectorOfSortedNativeStructs(std::vector<S,Alloc> * v)937 Offset<Vector<const T *>> CreateVectorOfSortedNativeStructs(
938 std::vector<S, Alloc> *v) {
939 return CreateVectorOfSortedNativeStructs<T, S>(data(*v), v->size());
940 }
941
942 /// @brief Serialize an array of structs into a FlatBuffer `vector` in sorted
943 /// order.
944 /// @tparam T The data type of the struct array elements.
945 /// @param[in] v A pointer to the array of type `T` to serialize into the
946 /// buffer as a `vector`.
947 /// @param[in] len The number of elements to serialize.
948 /// @return Returns a typed `Offset` into the serialized data indicating
949 /// where the vector is stored.
950 template<typename T>
CreateVectorOfSortedStructs(T * v,size_t len)951 Offset<Vector<const T *>> CreateVectorOfSortedStructs(T *v, size_t len) {
952 std::stable_sort(v, v + len, StructKeyComparator<T>());
953 return CreateVectorOfStructs(v, len);
954 }
955
956 /// @brief Serialize an array of native structs into a FlatBuffer `vector` in
957 /// sorted order.
958 /// @tparam T The data type of the struct array elements.
959 /// @tparam S The data type of the native struct array elements.
960 /// @param[in] v A pointer to the array of type `S` to serialize into the
961 /// buffer as a `vector`.
962 /// @param[in] len The number of elements to serialize.
963 /// @return Returns a typed `Offset` into the serialized data indicating
964 /// where the vector is stored.
965 template<typename T, typename S>
CreateVectorOfSortedNativeStructs(S * v,size_t len)966 Offset<Vector<const T *>> CreateVectorOfSortedNativeStructs(S *v,
967 size_t len) {
968 extern T Pack(const S &);
969 auto structs = StartVectorOfStructs<T>(len);
970 for (size_t i = 0; i < len; i++) { structs[i] = Pack(v[i]); }
971 std::stable_sort(structs, structs + len, StructKeyComparator<T>());
972 return EndVectorOfStructs<T>(len);
973 }
974
975 /// @cond FLATBUFFERS_INTERNAL
976 template<typename T> struct TableKeyComparator {
TableKeyComparatorTableKeyComparator977 TableKeyComparator(vector_downward &buf) : buf_(buf) {}
TableKeyComparatorTableKeyComparator978 TableKeyComparator(const TableKeyComparator &other) : buf_(other.buf_) {}
operatorTableKeyComparator979 bool operator()(const Offset<T> &a, const Offset<T> &b) const {
980 auto table_a = reinterpret_cast<T *>(buf_.data_at(a.o));
981 auto table_b = reinterpret_cast<T *>(buf_.data_at(b.o));
982 return table_a->KeyCompareLessThan(table_b);
983 }
984 vector_downward &buf_;
985
986 private:
987 FLATBUFFERS_DELETE_FUNC(
988 TableKeyComparator &operator=(const TableKeyComparator &other));
989 };
990 /// @endcond
991
992 /// @brief Serialize an array of `table` offsets as a `vector` in the buffer
993 /// in sorted order.
994 /// @tparam T The data type that the offset refers to.
995 /// @param[in] v An array of type `Offset<T>` that contains the `table`
996 /// offsets to store in the buffer in sorted order.
997 /// @param[in] len The number of elements to store in the `vector`.
998 /// @return Returns a typed `Offset` into the serialized data indicating
999 /// where the vector is stored.
1000 template<typename T>
CreateVectorOfSortedTables(Offset<T> * v,size_t len)1001 Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(Offset<T> *v,
1002 size_t len) {
1003 std::stable_sort(v, v + len, TableKeyComparator<T>(buf_));
1004 return CreateVector(v, len);
1005 }
1006
1007 /// @brief Serialize an array of `table` offsets as a `vector` in the buffer
1008 /// in sorted order.
1009 /// @tparam T The data type that the offset refers to.
1010 /// @param[in] v An array of type `Offset<T>` that contains the `table`
1011 /// offsets to store in the buffer in sorted order.
1012 /// @return Returns a typed `Offset` into the serialized data indicating
1013 /// where the vector is stored.
1014 template<typename T, typename Alloc = std::allocator<T>>
CreateVectorOfSortedTables(std::vector<Offset<T>,Alloc> * v)1015 Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(
1016 std::vector<Offset<T>, Alloc> *v) {
1017 return CreateVectorOfSortedTables(data(*v), v->size());
1018 }
1019
1020 /// @brief Specialized version of `CreateVector` for non-copying use cases.
1021 /// Write the data any time later to the returned buffer pointer `buf`.
1022 /// @param[in] len The number of elements to store in the `vector`.
1023 /// @param[in] elemsize The size of each element in the `vector`.
1024 /// @param[out] buf A pointer to a `uint8_t` pointer that can be
1025 /// written to at a later time to serialize the data into a `vector`
1026 /// in the buffer.
CreateUninitializedVector(size_t len,size_t elemsize,uint8_t ** buf)1027 uoffset_t CreateUninitializedVector(size_t len, size_t elemsize,
1028 uint8_t **buf) {
1029 NotNested();
1030 StartVector(len, elemsize);
1031 buf_.make_space(len * elemsize);
1032 auto vec_start = GetSize();
1033 auto vec_end = EndVector(len);
1034 *buf = buf_.data_at(vec_start);
1035 return vec_end;
1036 }
1037
1038 /// @brief Specialized version of `CreateVector` for non-copying use cases.
1039 /// Write the data any time later to the returned buffer pointer `buf`.
1040 /// @tparam T The data type of the data that will be stored in the buffer
1041 /// as a `vector`.
1042 /// @param[in] len The number of elements to store in the `vector`.
1043 /// @param[out] buf A pointer to a pointer of type `T` that can be
1044 /// written to at a later time to serialize the data into a `vector`
1045 /// in the buffer.
1046 template<typename T>
CreateUninitializedVector(size_t len,T ** buf)1047 Offset<Vector<T>> CreateUninitializedVector(size_t len, T **buf) {
1048 AssertScalarT<T>();
1049 return CreateUninitializedVector(len, sizeof(T),
1050 reinterpret_cast<uint8_t **>(buf));
1051 }
1052
1053 template<typename T>
CreateUninitializedVectorOfStructs(size_t len,T ** buf)1054 Offset<Vector<const T *>> CreateUninitializedVectorOfStructs(size_t len,
1055 T **buf) {
1056 return CreateUninitializedVector(len, sizeof(T),
1057 reinterpret_cast<uint8_t **>(buf));
1058 }
1059
1060 // @brief Create a vector of scalar type T given as input a vector of scalar
1061 // type U, useful with e.g. pre "enum class" enums, or any existing scalar
1062 // data of the wrong type.
1063 template<typename T, typename U>
CreateVectorScalarCast(const U * v,size_t len)1064 Offset<Vector<T>> CreateVectorScalarCast(const U *v, size_t len) {
1065 AssertScalarT<T>();
1066 AssertScalarT<U>();
1067 StartVector(len, sizeof(T));
1068 for (auto i = len; i > 0;) { PushElement(static_cast<T>(v[--i])); }
1069 return Offset<Vector<T>>(EndVector(len));
1070 }
1071
1072 /// @brief Write a struct by itself, typically to be part of a union.
CreateStruct(const T & structobj)1073 template<typename T> Offset<const T *> CreateStruct(const T &structobj) {
1074 NotNested();
1075 Align(AlignOf<T>());
1076 buf_.push_small(structobj);
1077 return Offset<const T *>(GetSize());
1078 }
1079
1080 /// @brief Finish serializing a buffer by writing the root offset.
1081 /// @param[in] file_identifier If a `file_identifier` is given, the buffer
1082 /// will be prefixed with a standard FlatBuffers file header.
1083 template<typename T>
1084 void Finish(Offset<T> root, const char *file_identifier = nullptr) {
1085 Finish(root.o, file_identifier, false);
1086 }
1087
1088 /// @brief Finish a buffer with a 32 bit size field pre-fixed (size of the
1089 /// buffer following the size field). These buffers are NOT compatible
1090 /// with standard buffers created by Finish, i.e. you can't call GetRoot
1091 /// on them, you have to use GetSizePrefixedRoot instead.
1092 /// All >32 bit quantities in this buffer will be aligned when the whole
1093 /// size pre-fixed buffer is aligned.
1094 /// These kinds of buffers are useful for creating a stream of FlatBuffers.
1095 template<typename T>
1096 void FinishSizePrefixed(Offset<T> root,
1097 const char *file_identifier = nullptr) {
1098 Finish(root.o, file_identifier, true);
1099 }
1100
SwapBufAllocator(FlatBufferBuilder & other)1101 void SwapBufAllocator(FlatBufferBuilder &other) {
1102 buf_.swap_allocator(other.buf_);
1103 }
1104
1105 /// @brief The length of a FlatBuffer file header.
1106 static const size_t kFileIdentifierLength =
1107 ::flatbuffers::kFileIdentifierLength;
1108
1109 protected:
1110 // You shouldn't really be copying instances of this class.
1111 FlatBufferBuilder(const FlatBufferBuilder &);
1112 FlatBufferBuilder &operator=(const FlatBufferBuilder &);
1113
Finish(uoffset_t root,const char * file_identifier,bool size_prefix)1114 void Finish(uoffset_t root, const char *file_identifier, bool size_prefix) {
1115 NotNested();
1116 buf_.clear_scratch();
1117 // This will cause the whole buffer to be aligned.
1118 PreAlign((size_prefix ? sizeof(uoffset_t) : 0) + sizeof(uoffset_t) +
1119 (file_identifier ? kFileIdentifierLength : 0),
1120 minalign_);
1121 if (file_identifier) {
1122 FLATBUFFERS_ASSERT(strlen(file_identifier) == kFileIdentifierLength);
1123 PushBytes(reinterpret_cast<const uint8_t *>(file_identifier),
1124 kFileIdentifierLength);
1125 }
1126 PushElement(ReferTo(root)); // Location of root.
1127 if (size_prefix) { PushElement(GetSize()); }
1128 finished = true;
1129 }
1130
1131 struct FieldLoc {
1132 uoffset_t off;
1133 voffset_t id;
1134 };
1135
1136 vector_downward buf_;
1137
1138 // Accumulating offsets of table members while it is being built.
1139 // We store these in the scratch pad of buf_, after the vtable offsets.
1140 uoffset_t num_field_loc;
1141 // Track how much of the vtable is in use, so we can output the most compact
1142 // possible vtable.
1143 voffset_t max_voffset_;
1144
1145 // Ensure objects are not nested.
1146 bool nested;
1147
1148 // Ensure the buffer is finished before it is being accessed.
1149 bool finished;
1150
1151 size_t minalign_;
1152
1153 bool force_defaults_; // Serialize values equal to their defaults anyway.
1154
1155 bool dedup_vtables_;
1156
1157 struct StringOffsetCompare {
StringOffsetCompareStringOffsetCompare1158 StringOffsetCompare(const vector_downward &buf) : buf_(&buf) {}
operatorStringOffsetCompare1159 bool operator()(const Offset<String> &a, const Offset<String> &b) const {
1160 auto stra = reinterpret_cast<const String *>(buf_->data_at(a.o));
1161 auto strb = reinterpret_cast<const String *>(buf_->data_at(b.o));
1162 return StringLessThan(stra->data(), stra->size(), strb->data(),
1163 strb->size());
1164 }
1165 const vector_downward *buf_;
1166 };
1167
1168 // For use with CreateSharedString. Instantiated on first use only.
1169 typedef std::set<Offset<String>, StringOffsetCompare> StringOffsetMap;
1170 StringOffsetMap *string_pool;
1171
1172 private:
1173 // Allocates space for a vector of structures.
1174 // Must be completed with EndVectorOfStructs().
StartVectorOfStructs(size_t vector_size)1175 template<typename T> T *StartVectorOfStructs(size_t vector_size) {
1176 StartVector(vector_size * sizeof(T) / AlignOf<T>(), AlignOf<T>());
1177 return reinterpret_cast<T *>(buf_.make_space(vector_size * sizeof(T)));
1178 }
1179
1180 // End the vector of structures in the flatbuffers.
1181 // Vector should have previously be started with StartVectorOfStructs().
1182 template<typename T>
EndVectorOfStructs(size_t vector_size)1183 Offset<Vector<const T *>> EndVectorOfStructs(size_t vector_size) {
1184 return Offset<Vector<const T *>>(EndVector(vector_size));
1185 }
1186 };
1187 /// @}
1188
1189 /// Helpers to get a typed pointer to objects that are currently being built.
1190 /// @warning Creating new objects will lead to reallocations and invalidates
1191 /// the pointer!
1192 template<typename T>
GetMutableTemporaryPointer(FlatBufferBuilder & fbb,Offset<T> offset)1193 T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb, Offset<T> offset) {
1194 return reinterpret_cast<T *>(fbb.GetCurrentBufferPointer() + fbb.GetSize() -
1195 offset.o);
1196 }
1197
1198 template<typename T>
GetTemporaryPointer(FlatBufferBuilder & fbb,Offset<T> offset)1199 const T *GetTemporaryPointer(FlatBufferBuilder &fbb, Offset<T> offset) {
1200 return GetMutableTemporaryPointer<T>(fbb, offset);
1201 }
1202
1203 template<typename T>
Required(Offset<T> table,voffset_t field)1204 void FlatBufferBuilder::Required(Offset<T> table, voffset_t field) {
1205 auto table_ptr = reinterpret_cast<const Table *>(buf_.data_at(table.o));
1206 bool ok = table_ptr->GetOptionalFieldOffset(field) != 0;
1207 // If this fails, the caller will show what field needs to be set.
1208 FLATBUFFERS_ASSERT(ok);
1209 (void)ok;
1210 }
1211
1212 } // namespace flatbuffers
1213
1214 #endif // FLATBUFFERS_VECTOR_DOWNWARD_H_
1215