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