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