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