Line data Source code
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.
40 132230 : inline voffset_t FieldIndexToOffset(voffset_t field_id) {
41 : // Should correspond to what EndTable() below builds up.
42 132230 : const int fixed_fields = 2; // Vtable size and Object Size.
43 132230 : return static_cast<voffset_t>((field_id + fixed_fields) * sizeof(voffset_t));
44 : }
45 :
46 : template<typename T, typename Alloc = std::allocator<T>>
47 1157 : 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 1157 : return v.empty() ? reinterpret_cast<const T *>(&t) : &v.front();
52 : }
53 : template<typename T, typename Alloc = std::allocator<T>>
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 559 : 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>())
87 559 : : 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 559 : string_pool(nullptr) {
96 559 : EndianCheck();
97 559 : }
98 :
99 : /// @brief Move constructor for FlatBufferBuilder.
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 :
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 :
138 559 : ~FlatBufferBuilder() {
139 559 : if (string_pool) delete string_pool;
140 559 : }
141 :
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.
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.
160 1855160 : 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.
165 509 : uint8_t *GetBufferPointer() const {
166 509 : Finished();
167 509 : 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.
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.
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.
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.
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..
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.
218 : size_t GetBufferMinAlignment() const {
219 : Finished();
220 : return minalign_;
221 : }
222 :
223 : /// @cond FLATBUFFERS_INTERNAL
224 509 : 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 509 : FLATBUFFERS_ASSERT(finished);
231 509 : }
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.
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.
243 : void DedupVtables(bool dedup) { dedup_vtables_ = dedup; }
244 :
245 : /// @cond FLATBUFFERS_INTERNAL
246 : void Pad(size_t num_bytes) { buf_.fill(num_bytes); }
247 :
248 1194590 : void TrackMinAlign(size_t elem_size) {
249 1194590 : if (elem_size > minalign_) minalign_ = elem_size;
250 1194590 : }
251 :
252 1059880 : void Align(size_t elem_size) {
253 1059880 : TrackMinAlign(elem_size);
254 1059880 : buf_.fill(PaddingBytes(buf_.size(), elem_size));
255 1059880 : }
256 :
257 : void PushFlatBuffer(const uint8_t *bytes, size_t size) {
258 : PushBytes(bytes, size);
259 : finished = true;
260 : }
261 :
262 132549 : void PushBytes(const uint8_t *bytes, size_t size) { buf_.push(bytes, size); }
263 :
264 : void PopBytes(size_t amount) { buf_.pop(amount); }
265 :
266 928442 : 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 928442 : }
270 :
271 : // Write a single aligned scalar to the buffer
272 794736 : template<typename T> uoffset_t PushElement(T element) {
273 794736 : AssertScalarT<T>();
274 794736 : Align(sizeof(T));
275 794736 : buf_.push_small(EndianScalar(element));
276 794736 : return GetSize();
277 : }
278 :
279 131512 : template<typename T> uoffset_t PushElement(Offset<T> off) {
280 : // Special case for offsets: see ReferTo below.
281 131512 : return PushElement(ReferTo(off.o));
282 : }
283 :
284 : // When writing fields, we track where they are, so we can create correct
285 : // vtables later.
286 397061 : void TrackField(voffset_t field, uoffset_t off) {
287 397061 : FieldLoc fl = { off, field };
288 397061 : buf_.scratch_push_small(fl);
289 397061 : num_field_loc++;
290 397061 : if (field > max_voffset_) { max_voffset_ = field; }
291 397061 : }
292 :
293 : // Like PushElement, but additionally tracks the field this represents.
294 1055420 : template<typename T> void AddElement(voffset_t field, T e, T def) {
295 : // We don't serialize values equal to the default.
296 1055420 : if (IsTheSameAs(e, def) && !force_defaults_) return;
297 397061 : TrackField(field, PushElement(e));
298 : }
299 :
300 : template<typename T> void AddElement(voffset_t field, T e) {
301 : TrackField(field, PushElement(e));
302 : }
303 :
304 530584 : template<typename T> void AddOffset(voffset_t field, Offset<T> off) {
305 530584 : if (off.IsNull()) return; // Don't store.
306 133124 : AddElement(field, ReferTo(off.o), static_cast<uoffset_t>(0));
307 : }
308 :
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 :
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.
323 265145 : uoffset_t ReferTo(uoffset_t off) {
324 : // Align to ensure GetSize() below is correct.
325 265145 : Align(sizeof(uoffset_t));
326 : // Offset must refer to something already in buffer.
327 265145 : const uoffset_t size = GetSize();
328 265145 : FLATBUFFERS_ASSERT(off && off <= size);
329 265145 : return size - off + static_cast<uoffset_t>(sizeof(uoffset_t));
330 : }
331 :
332 265654 : 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 265654 : FLATBUFFERS_ASSERT(!nested);
342 : // If you hit this, fields were added outside the scope of a table.
343 265654 : FLATBUFFERS_ASSERT(!num_field_loc);
344 265654 : }
345 :
346 : // From generated code (or from the parser), we call StartTable/EndTable
347 : // with a sequence of AddElement calls in between.
348 132230 : uoffset_t StartTable() {
349 132230 : NotNested();
350 132230 : nested = true;
351 132230 : 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.
357 132230 : uoffset_t EndTable(uoffset_t start) {
358 : // If you get this assert, a corresponding StartTable wasn't called.
359 132230 : FLATBUFFERS_ASSERT(nested);
360 : // Write the vtable offset, which is the start of any Table.
361 : // We fill it's value later.
362 132230 : 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 132230 : max_voffset_ =
369 264460 : (std::max)(static_cast<voffset_t>(max_voffset_ + sizeof(voffset_t)),
370 132230 : FieldIndexToOffset(0));
371 132230 : buf_.fill_big(max_voffset_);
372 132230 : auto table_object_size = vtableoffsetloc - start;
373 : // Vtable use 16bit offsets.
374 132230 : FLATBUFFERS_ASSERT(table_object_size < 0x10000);
375 132230 : WriteScalar<voffset_t>(buf_.data() + sizeof(voffset_t),
376 : static_cast<voffset_t>(table_object_size));
377 132230 : WriteScalar<voffset_t>(buf_.data(), max_voffset_);
378 : // Write the offsets into the table
379 132230 : for (auto it = buf_.scratch_end() - num_field_loc * sizeof(FieldLoc);
380 529291 : it < buf_.scratch_end(); it += sizeof(FieldLoc)) {
381 397061 : auto field_location = reinterpret_cast<FieldLoc *>(it);
382 397061 : auto pos = static_cast<voffset_t>(vtableoffsetloc - field_location->off);
383 : // If this asserts, it means you've set a field twice.
384 397061 : FLATBUFFERS_ASSERT(
385 : !ReadScalar<voffset_t>(buf_.data() + field_location->id));
386 397061 : WriteScalar<voffset_t>(buf_.data() + field_location->id, pos);
387 : }
388 132230 : ClearOffsets();
389 132230 : auto vt1 = reinterpret_cast<voffset_t *>(buf_.data());
390 132230 : auto vt1_size = ReadScalar<voffset_t>(vt1);
391 132230 : 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 132230 : if (dedup_vtables_) {
395 132835 : for (auto it = buf_.scratch_data(); it < buf_.scratch_end();
396 605 : it += sizeof(uoffset_t)) {
397 131897 : auto vt_offset_ptr = reinterpret_cast<uoffset_t *>(it);
398 131897 : auto vt2 = reinterpret_cast<voffset_t *>(buf_.data_at(*vt_offset_ptr));
399 131897 : auto vt2_size = ReadScalar<voffset_t>(vt2);
400 131897 : if (vt1_size != vt2_size || 0 != memcmp(vt2, vt1, vt1_size)) continue;
401 131292 : vt_use = *vt_offset_ptr;
402 131292 : buf_.pop(GetSize() - vtableoffsetloc);
403 131292 : break;
404 : }
405 : }
406 : // If this is a new vtable, remember it.
407 132230 : 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 132230 : WriteScalar(buf_.data_at(vtableoffsetloc),
414 132230 : static_cast<soffset_t>(vt_use) -
415 132230 : static_cast<soffset_t>(vtableoffsetloc));
416 :
417 132230 : nested = false;
418 132230 : return vtableoffsetloc;
419 : }
420 :
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 :
430 : uoffset_t StartStruct(size_t alignment) {
431 : Align(alignment);
432 : return GetSize();
433 : }
434 :
435 : uoffset_t EndStruct() { return GetSize(); }
436 :
437 132230 : void ClearOffsets() {
438 132230 : buf_.scratch_pop(num_field_loc * sizeof(FieldLoc));
439 132230 : num_field_loc = 0;
440 132230 : max_voffset_ = 0;
441 132230 : }
442 :
443 : // Aligns such that when "len" bytes are written, an object can be written
444 : // after it with "alignment" without padding.
445 134581 : void PreAlign(size_t len, size_t alignment) {
446 134581 : if (len == 0) return;
447 134147 : TrackMinAlign(alignment);
448 134147 : buf_.fill(PaddingBytes(GetSize() + len, alignment));
449 : }
450 132915 : template<typename T> void PreAlign(size_t len) {
451 132915 : AssertScalarT<T>();
452 132915 : PreAlign(len, sizeof(T));
453 132915 : }
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.
460 131758 : Offset<String> CreateString(const char *str, size_t len) {
461 131758 : NotNested();
462 131758 : PreAlign<uoffset_t>(len + 1); // Always 0-terminated.
463 131758 : buf_.fill(1);
464 131758 : PushBytes(reinterpret_cast<const uint8_t *>(str), len);
465 131758 : PushElement(static_cast<uoffset_t>(len));
466 131758 : 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.
472 131758 : Offset<String> CreateString(const char *str) {
473 131758 : 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.
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.
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.
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
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.
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.
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
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.
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.
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
581 : Offset<String> CreateSharedString(const String *str) {
582 : return CreateSharedString(str->c_str(), str->size());
583 : }
584 :
585 : /// @cond FLATBUFFERS_INTERNAL
586 1157 : uoffset_t EndVector(size_t len) {
587 1157 : FLATBUFFERS_ASSERT(nested); // Hit if no corresponding StartVector.
588 1157 : nested = false;
589 1157 : return PushElement(static_cast<uoffset_t>(len));
590 : }
591 :
592 1157 : void StartVector(size_t len, size_t elemsize) {
593 1157 : NotNested();
594 1157 : nested = true;
595 1157 : PreAlign<uoffset_t>(len * elemsize);
596 1157 : PreAlign(len * elemsize, elemsize); // Just in case elemsize > uoffset_t.
597 1157 : }
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.
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.
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.
626 791 : 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 791 : AssertScalarT<T>();
630 791 : StartVector(len, sizeof(T));
631 791 : if (len == 0) { return Offset<Vector<T>>(EndVector(len)); }
632 : // clang-format off
633 : #if FLATBUFFERS_LITTLEENDIAN
634 791 : 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 791 : 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.
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>
665 : Offset<Vector<T>> CreateVector(std::initializer_list<T> v) {
666 : return CreateVector(v.begin(), v.size());
667 : }
668 :
669 : template<typename T>
670 366 : Offset<Vector<Offset<T>>> CreateVector(const Offset<T> *v, size_t len) {
671 366 : StartVector(len, sizeof(Offset<T>));
672 131878 : for (auto i = len; i > 0;) { PushElement(v[--i]); }
673 366 : 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>>
683 1157 : Offset<Vector<T>> CreateVector(const std::vector<T, Alloc> &v) {
684 1157 : 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
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>
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>
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>>
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 beginning 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>
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>
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>
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>
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>
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>
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>>
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>>
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>>
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 {
909 : 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>>
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>>
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>
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>
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 {
977 : TableKeyComparator(vector_downward &buf) : buf_(buf) {}
978 : TableKeyComparator(const TableKeyComparator &other) : buf_(other.buf_) {}
979 : 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>
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>>
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.
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>
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>
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>
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.
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 509 : void FinishSizePrefixed(Offset<T> root,
1097 : const char *file_identifier = nullptr) {
1098 509 : Finish(root.o, file_identifier, true);
1099 509 : }
1100 :
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 :
1114 509 : void Finish(uoffset_t root, const char *file_identifier, bool size_prefix) {
1115 509 : NotNested();
1116 509 : buf_.clear_scratch();
1117 : // This will cause the whole buffer to be aligned.
1118 1018 : PreAlign((size_prefix ? sizeof(uoffset_t) : 0) + sizeof(uoffset_t) +
1119 509 : (file_identifier ? kFileIdentifierLength : 0),
1120 : minalign_);
1121 509 : if (file_identifier) {
1122 0 : FLATBUFFERS_ASSERT(strlen(file_identifier) == kFileIdentifierLength);
1123 0 : PushBytes(reinterpret_cast<const uint8_t *>(file_identifier),
1124 : kFileIdentifierLength);
1125 : }
1126 509 : PushElement(ReferTo(root)); // Location of root.
1127 509 : if (size_prefix) { PushElement(GetSize()); }
1128 509 : finished = true;
1129 509 : }
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 {
1158 : StringOffsetCompare(const vector_downward &buf) : buf_(&buf) {}
1159 : 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().
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>
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>
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>
1199 : const T *GetTemporaryPointer(FlatBufferBuilder &fbb, Offset<T> offset) {
1200 : return GetMutableTemporaryPointer<T>(fbb, offset);
1201 : }
1202 :
1203 : template<typename T>
1204 131402 : void FlatBufferBuilder::Required(Offset<T> table, voffset_t field) {
1205 131402 : auto table_ptr = reinterpret_cast<const Table *>(buf_.data_at(table.o));
1206 131402 : bool ok = table_ptr->GetOptionalFieldOffset(field) != 0;
1207 : // If this fails, the caller will show what field needs to be set.
1208 131402 : FLATBUFFERS_ASSERT(ok);
1209 : (void)ok;
1210 131402 : }
1211 :
1212 : } // namespace flatbuffers
1213 :
1214 : #endif // FLATBUFFERS_VECTOR_DOWNWARD_H_
|