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