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