1 /*
2 * Copyright 2017 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_FLEXBUFFERS_H_
18 #define FLATBUFFERS_FLEXBUFFERS_H_
19
20 // We use the basic binary writing functions from the regular FlatBuffers.
21 #include "flatbuffers/flatbuffers.h"
22 #include "flatbuffers/util.h"
23
24 #ifdef _MSC_VER
25 #include <intrin.h>
26 #endif
27
28 namespace flexbuffers {
29
30 class Reference;
31 class Map;
32
33 // These are used in the lower 2 bits of a type field to determine the size of
34 // the elements (and or size field) of the item pointed to (e.g. vector).
35 enum BitWidth {
36 BIT_WIDTH_8 = 0,
37 BIT_WIDTH_16 = 1,
38 BIT_WIDTH_32 = 2,
39 BIT_WIDTH_64 = 3,
40 };
41
42 // These are used as the upper 6 bits of a type field to indicate the actual
43 // type.
44 enum Type {
45 TYPE_NULL = 0,
46 TYPE_INT = 1,
47 TYPE_UINT = 2,
48 TYPE_FLOAT = 3,
49 // Types above stored inline, types below store an offset.
50 TYPE_KEY = 4,
51 TYPE_STRING = 5,
52 TYPE_INDIRECT_INT = 6,
53 TYPE_INDIRECT_UINT = 7,
54 TYPE_INDIRECT_FLOAT = 8,
55 TYPE_MAP = 9,
56 TYPE_VECTOR = 10, // Untyped.
57 TYPE_VECTOR_INT = 11, // Typed any size (stores no type table).
58 TYPE_VECTOR_UINT = 12,
59 TYPE_VECTOR_FLOAT = 13,
60 TYPE_VECTOR_KEY = 14,
61 TYPE_VECTOR_STRING = 15,
62 TYPE_VECTOR_INT2 = 16, // Typed tuple (no type table, no size field).
63 TYPE_VECTOR_UINT2 = 17,
64 TYPE_VECTOR_FLOAT2 = 18,
65 TYPE_VECTOR_INT3 = 19, // Typed triple (no type table, no size field).
66 TYPE_VECTOR_UINT3 = 20,
67 TYPE_VECTOR_FLOAT3 = 21,
68 TYPE_VECTOR_INT4 = 22, // Typed quad (no type table, no size field).
69 TYPE_VECTOR_UINT4 = 23,
70 TYPE_VECTOR_FLOAT4 = 24,
71 TYPE_BLOB = 25,
72 };
73
IsInline(Type t)74 inline bool IsInline(Type t) { return t <= TYPE_FLOAT; }
75
IsTypedVectorElementType(Type t)76 inline bool IsTypedVectorElementType(Type t) {
77 return t >= TYPE_INT && t <= TYPE_STRING;
78 }
79
IsTypedVector(Type t)80 inline bool IsTypedVector(Type t) {
81 return t >= TYPE_VECTOR_INT && t <= TYPE_VECTOR_STRING;
82 }
83
IsFixedTypedVector(Type t)84 inline bool IsFixedTypedVector(Type t) {
85 return t >= TYPE_VECTOR_INT2 && t <= TYPE_VECTOR_FLOAT4;
86 }
87
88 inline Type ToTypedVector(Type t, int fixed_len = 0) {
89 assert(IsTypedVectorElementType(t));
90 switch (fixed_len) {
91 case 0: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT);
92 case 2: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT2);
93 case 3: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT3);
94 case 4: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT4);
95 default: assert(0); return TYPE_NULL;
96 }
97 }
98
ToTypedVectorElementType(Type t)99 inline Type ToTypedVectorElementType(Type t) {
100 assert(IsTypedVector(t));
101 return static_cast<Type>(t - TYPE_VECTOR_INT + TYPE_INT);
102 }
103
ToFixedTypedVectorElementType(Type t,uint8_t * len)104 inline Type ToFixedTypedVectorElementType(Type t, uint8_t *len) {
105 assert(IsFixedTypedVector(t));
106 auto fixed_type = t - TYPE_VECTOR_INT2;
107 *len = fixed_type / 3 + 2; // 3 types each, starting from length 2.
108 return static_cast<Type>(fixed_type % 3 + TYPE_INT);
109 }
110
111 // TODO: implement proper support for 8/16bit floats, or decide not to
112 // support them.
113 typedef int16_t half;
114 typedef int8_t quarter;
115
116 // TODO: can we do this without conditionals using intrinsics or inline asm
117 // on some platforms? Given branch prediction the method below should be
118 // decently quick, but it is the most frequently executed function.
119 // We could do an (unaligned) 64-bit read if we ifdef out the platforms for
120 // which that doesn't work (or where we'd read into un-owned memory).
121 template <typename R, typename T1, typename T2, typename T4, typename T8>
ReadSizedScalar(const uint8_t * data,uint8_t byte_width)122 R ReadSizedScalar(const uint8_t *data, uint8_t byte_width) {
123 return byte_width < 4
124 ? (byte_width < 2 ? static_cast<R>(flatbuffers::ReadScalar<T1>(data))
125 : static_cast<R>(flatbuffers::ReadScalar<T2>(data)))
126 : (byte_width < 8 ? static_cast<R>(flatbuffers::ReadScalar<T4>(data))
127 : static_cast<R>(flatbuffers::ReadScalar<T8>(data)));
128 }
129
130
ReadInt64(const uint8_t * data,uint8_t byte_width)131 inline int64_t ReadInt64(const uint8_t *data, uint8_t byte_width) {
132 return ReadSizedScalar<int64_t, int8_t, int16_t, int32_t, int64_t>(data,
133 byte_width);
134 }
135
ReadUInt64(const uint8_t * data,uint8_t byte_width)136 inline uint64_t ReadUInt64(const uint8_t *data, uint8_t byte_width) {
137 // This is the "hottest" function (all offset lookups use this), so worth
138 // optimizing if possible.
139 // TODO: GCC apparently replaces memcpy by a rep movsb, but only if count is a
140 // constant, which here it isn't. Test if memcpy is still faster than
141 // the conditionals in ReadSizedScalar. Can also use inline asm.
142 #ifdef _MSC_VER
143 uint64_t u = 0;
144 __movsb(reinterpret_cast<uint8_t *>(&u),
145 reinterpret_cast<const uint8_t *>(data), byte_width);
146 return flatbuffers::EndianScalar(u);
147 #else
148 return ReadSizedScalar<uint64_t, uint8_t, uint16_t, uint32_t, uint64_t>(
149 data, byte_width);
150 #endif
151 }
152
ReadDouble(const uint8_t * data,uint8_t byte_width)153 inline double ReadDouble(const uint8_t *data, uint8_t byte_width) {
154 return ReadSizedScalar<double, quarter, half, float, double>(data,
155 byte_width);
156 }
157
Indirect(const uint8_t * offset,uint8_t byte_width)158 const uint8_t *Indirect(const uint8_t *offset, uint8_t byte_width) {
159 return offset - ReadUInt64(offset, byte_width);
160 }
161
Indirect(const uint8_t * offset)162 template<typename T> const uint8_t *Indirect(const uint8_t *offset) {
163 return offset - flatbuffers::ReadScalar<T>(offset);
164 }
165
WidthU(uint64_t u)166 static BitWidth WidthU(uint64_t u) {
167 #define FLATBUFFERS_GET_FIELD_BIT_WIDTH(value, width) { \
168 if (!((u) & ~((1ULL << (width)) - 1ULL))) return BIT_WIDTH_##width; \
169 }
170 FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 8);
171 FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 16);
172 FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 32);
173 #undef FLATBUFFERS_GET_FIELD_BIT_WIDTH
174 return BIT_WIDTH_64;
175 }
176
WidthI(int64_t i)177 static BitWidth WidthI(int64_t i) {
178 auto u = static_cast<uint64_t>(i) << 1;
179 return WidthU(i >= 0 ? u : ~u);
180 }
181
WidthF(double f)182 static BitWidth WidthF(double f) {
183 return static_cast<double>(static_cast<float>(f)) == f ? BIT_WIDTH_32
184 : BIT_WIDTH_64;
185 }
186
187 // Base class of all types below.
188 // Points into the data buffer and allows access to one type.
189 class Object {
190 public:
Object(const uint8_t * data,uint8_t byte_width)191 Object(const uint8_t *data, uint8_t byte_width)
192 : data_(data), byte_width_(byte_width) {}
193
194 protected:
195 const uint8_t *data_;
196 uint8_t byte_width_;
197 };
198
199 // Stores size in `byte_width_` bytes before data_ pointer.
200 class Sized : public Object {
201 public:
Sized(const uint8_t * data,uint8_t byte_width)202 Sized(const uint8_t *data, uint8_t byte_width) : Object(data, byte_width) {}
size()203 size_t size() const {
204 return static_cast<size_t>(ReadUInt64(data_ - byte_width_, byte_width_));
205 }
206 };
207
208 class String : public Sized {
209 public:
String(const uint8_t * data,uint8_t byte_width)210 String(const uint8_t *data, uint8_t byte_width)
211 : Sized(data, byte_width) {}
212
length()213 size_t length() const { return size(); }
c_str()214 const char *c_str() const { return reinterpret_cast<const char *>(data_); }
215
EmptyString()216 static String EmptyString() {
217 static const uint8_t empty_string[] = { 0/*len*/, 0/*terminator*/ };
218 return String(empty_string + 1, 1);
219 }
IsTheEmptyString()220 bool IsTheEmptyString() const { return data_ == EmptyString().data_; }
221 };
222
223 class Blob : public Sized {
224 public:
Blob(const uint8_t * data,uint8_t byte_width)225 Blob(const uint8_t *data, uint8_t byte_width)
226 : Sized(data, byte_width) {}
227
EmptyBlob()228 static Blob EmptyBlob() {
229 static const uint8_t empty_blob[] = { 0/*len*/ };
230 return Blob(empty_blob + 1, 1);
231 }
IsTheEmptyBlob()232 bool IsTheEmptyBlob() const { return data_ == EmptyBlob().data_; }
233 };
234
235 class Vector : public Sized {
236 public:
Vector(const uint8_t * data,uint8_t byte_width)237 Vector(const uint8_t *data, uint8_t byte_width)
238 : Sized(data, byte_width) {}
239
240 Reference operator[](size_t i) const;
241
EmptyVector()242 static Vector EmptyVector() {
243 static const uint8_t empty_vector[] = { 0/*len*/ };
244 return Vector(empty_vector + 1, 1);
245 }
IsTheEmptyVector()246 bool IsTheEmptyVector() const { return data_ == EmptyVector().data_; }
247 };
248
249 class TypedVector : public Sized {
250 public:
TypedVector(const uint8_t * data,uint8_t byte_width,Type element_type)251 TypedVector(const uint8_t *data, uint8_t byte_width, Type element_type)
252 : Sized(data, byte_width), type_(element_type) {}
253
254 Reference operator[](size_t i) const;
255
EmptyTypedVector()256 static TypedVector EmptyTypedVector() {
257 static const uint8_t empty_typed_vector[] = { 0/*len*/ };
258 return TypedVector(empty_typed_vector + 1, 1, TYPE_INT);
259 }
IsTheEmptyVector()260 bool IsTheEmptyVector() const {
261 return data_ == TypedVector::EmptyTypedVector().data_;
262 }
263
ElementType()264 Type ElementType() { return type_; }
265
266 private:
267 Type type_;
268
269 friend Map;
270 };
271
272 class FixedTypedVector : public Object {
273 public:
FixedTypedVector(const uint8_t * data,uint8_t byte_width,Type element_type,uint8_t len)274 FixedTypedVector(const uint8_t *data, uint8_t byte_width, Type element_type,
275 uint8_t len)
276 : Object(data, byte_width), type_(element_type), len_(len) {}
277
278 Reference operator[](size_t i) const;
279
EmptyFixedTypedVector()280 static FixedTypedVector EmptyFixedTypedVector() {
281 static const uint8_t fixed_empty_vector[] = { 0/* unused */ };
282 return FixedTypedVector(fixed_empty_vector, 1, TYPE_INT, 0);
283 }
IsTheEmptyFixedTypedVector()284 bool IsTheEmptyFixedTypedVector() const {
285 return data_ == FixedTypedVector::EmptyFixedTypedVector().data_;
286 }
287
ElementType()288 Type ElementType() { return type_; }
size()289 uint8_t size() { return len_; }
290
291 private:
292 Type type_;
293 uint8_t len_;
294 };
295
296 class Map : public Vector {
297 public:
Map(const uint8_t * data,uint8_t byte_width)298 Map(const uint8_t *data, uint8_t byte_width)
299 : Vector(data, byte_width) {}
300
301 Reference operator[](const char *key) const;
302 Reference operator[](const std::string &key) const;
303
Values()304 Vector Values() const { return Vector(data_, byte_width_); }
305
Keys()306 TypedVector Keys() const {
307 const size_t num_prefixed_fields = 3;
308 auto keys_offset = data_ - byte_width_ * num_prefixed_fields;
309 return TypedVector(Indirect(keys_offset, byte_width_),
310 static_cast<uint8_t>(
311 ReadUInt64(keys_offset + byte_width_, byte_width_)),
312 TYPE_KEY);
313 }
314
EmptyMap()315 static Map EmptyMap() {
316 static const uint8_t empty_map[] = {
317 0/*keys_len*/, 0/*keys_offset*/, 1/*keys_width*/, 0/*len*/
318 };
319 return Map(empty_map + 4, 1);
320 }
321
IsTheEmptyMap()322 bool IsTheEmptyMap() const {
323 return data_ == EmptyMap().data_;
324 }
325 };
326
327 class Reference {
328 public:
Reference(const uint8_t * data,uint8_t parent_width,uint8_t byte_width,Type type)329 Reference(const uint8_t *data, uint8_t parent_width, uint8_t byte_width,
330 Type type)
331 : data_(data), parent_width_(parent_width), byte_width_(byte_width),
332 type_(type) {}
333
Reference(const uint8_t * data,uint8_t parent_width,uint8_t packed_type)334 Reference(const uint8_t *data, uint8_t parent_width, uint8_t packed_type)
335 : data_(data), parent_width_(parent_width) {
336 byte_width_ = 1U << static_cast<BitWidth>(packed_type & 3);
337 type_ = static_cast<Type>(packed_type >> 2);
338 }
339
GetType()340 Type GetType() const { return type_; }
341
IsNull()342 bool IsNull() const { return type_ == TYPE_NULL; }
IsInt()343 bool IsInt() const { return type_ == TYPE_INT ||
344 type_ == TYPE_INDIRECT_INT; }
IsUInt()345 bool IsUInt() const { return type_ == TYPE_UINT||
346 type_ == TYPE_INDIRECT_UINT;; }
IsIntOrUint()347 bool IsIntOrUint() const { return IsInt() || IsUInt(); }
IsFloat()348 bool IsFloat() const { return type_ == TYPE_FLOAT ||
349 type_ == TYPE_INDIRECT_FLOAT; }
IsNumeric()350 bool IsNumeric() const { return IsIntOrUint() || IsFloat(); }
IsString()351 bool IsString() const { return type_ == TYPE_STRING; }
IsKey()352 bool IsKey() const { return type_ == TYPE_KEY; }
IsVector()353 bool IsVector() const { return type_ == TYPE_VECTOR || type_ == TYPE_MAP; }
IsMap()354 bool IsMap() const { return type_ == TYPE_MAP; }
355
356 // Reads any type as a int64_t. Never fails, does most sensible conversion.
357 // Truncates floats, strings are attempted to be parsed for a number,
358 // vectors/maps return their size. Returns 0 if all else fails.
AsInt64()359 int64_t AsInt64() const {
360 if (type_ == TYPE_INT) {
361 // A fast path for the common case.
362 return ReadInt64(data_, parent_width_);
363 } else switch (type_) {
364 case TYPE_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_);
365 case TYPE_UINT: return ReadUInt64(data_, parent_width_);
366 case TYPE_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_);
367 case TYPE_FLOAT: return static_cast<int64_t>(
368 ReadDouble(data_, parent_width_));
369 case TYPE_INDIRECT_FLOAT: return static_cast<int64_t>(
370 ReadDouble(Indirect(), byte_width_));
371 case TYPE_NULL: return 0;
372 case TYPE_STRING: return flatbuffers::StringToInt(AsString().c_str());
373 case TYPE_VECTOR: return static_cast<int64_t>(AsVector().size());
374 default:
375 // Convert other things to int.
376 return 0;
377 }
378 }
379
380 // TODO: could specialize these to not use AsInt64() if that saves
381 // extension ops in generated code, and use a faster op than ReadInt64.
AsInt32()382 int32_t AsInt32() const { return static_cast<int32_t>(AsInt64()); }
AsInt16()383 int16_t AsInt16() const { return static_cast<int16_t>(AsInt64()); }
AsInt8()384 int8_t AsInt8() const { return static_cast<int8_t> (AsInt64()); }
385
AsUInt64()386 uint64_t AsUInt64() const {
387 if (type_ == TYPE_UINT) {
388 // A fast path for the common case.
389 return ReadUInt64(data_, parent_width_);
390 } else switch (type_) {
391 case TYPE_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_);
392 case TYPE_INT: return ReadInt64(data_, parent_width_);
393 case TYPE_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_);
394 case TYPE_FLOAT: return static_cast<uint64_t>(
395 ReadDouble(data_, parent_width_));
396 case TYPE_INDIRECT_FLOAT: return static_cast<uint64_t>(
397 ReadDouble(Indirect(), byte_width_));
398 case TYPE_NULL: return 0;
399 case TYPE_STRING: return flatbuffers::StringToUInt(AsString().c_str());
400 case TYPE_VECTOR: return static_cast<uint64_t>(AsVector().size());
401 default:
402 // Convert other things to uint.
403 return 0;
404 }
405 }
406
AsUInt32()407 uint32_t AsUInt32() const { return static_cast<uint32_t>(AsUInt64()); }
AsUInt16()408 uint16_t AsUInt16() const { return static_cast<uint16_t>(AsUInt64()); }
AsUInt8()409 uint8_t AsUInt8() const { return static_cast<uint8_t> (AsUInt64()); }
410
AsDouble()411 double AsDouble() const {
412 if (type_ == TYPE_FLOAT) {
413 // A fast path for the common case.
414 return ReadDouble(data_, parent_width_);
415 } else switch (type_) {
416 case TYPE_INDIRECT_FLOAT: return ReadDouble(Indirect(), byte_width_);
417 case TYPE_INT: return static_cast<double>(
418 ReadInt64(data_, parent_width_));
419 case TYPE_UINT: return static_cast<double>(
420 ReadUInt64(data_, parent_width_));
421 case TYPE_INDIRECT_INT: return static_cast<double>(
422 ReadInt64(Indirect(), byte_width_));
423 case TYPE_INDIRECT_UINT: return static_cast<double>(
424 ReadUInt64(Indirect(), byte_width_));
425 case TYPE_NULL: return 0.0;
426 case TYPE_STRING: return strtod(AsString().c_str(), nullptr);
427 case TYPE_VECTOR: return static_cast<double>(AsVector().size());
428 default:
429 // Convert strings and other things to float.
430 return 0;
431 }
432 }
433
AsFloat()434 float AsFloat() const { return static_cast<float>(AsDouble()); }
435
AsKey()436 const char *AsKey() const {
437 if (type_ == TYPE_KEY) {
438 return reinterpret_cast<const char *>(Indirect());
439 } else {
440 return "";
441 }
442 }
443
444 // This function returns the empty string if you try to read a not-string.
AsString()445 String AsString() const {
446 if (type_ == TYPE_STRING) {
447 return String(Indirect(), byte_width_);
448 } else {
449 return String::EmptyString();
450 }
451 }
452
453 // Unlike AsString(), this will convert any type to a std::string.
ToString()454 std::string ToString() const {
455 if (type_ == TYPE_STRING) {
456 return String(Indirect(), byte_width_).c_str();
457 } else if (IsKey()) {
458 return AsKey();
459 } else if (IsInt()) {
460 return flatbuffers::NumToString(AsInt64());
461 } else if (IsUInt()) {
462 return flatbuffers::NumToString(AsUInt64());
463 } else if (IsFloat()) {
464 return flatbuffers::NumToString(AsDouble());
465 } else if (IsNull()) {
466 return "null";
467 } else if (IsMap()) {
468 return "{..}"; // TODO: show elements.
469 } else if (IsVector()) {
470 return "[..]"; // TODO: show elements.
471 } else {
472 return "(?)";
473 }
474 }
475
476 // This function returns the empty blob if you try to read a not-blob.
477 // Strings can be viewed as blobs too.
AsBlob()478 Blob AsBlob() const {
479 if (type_ == TYPE_BLOB || type_ == TYPE_STRING) {
480 return Blob(Indirect(), byte_width_);
481 } else {
482 return Blob::EmptyBlob();
483 }
484 }
485
486 // This function returns the empty vector if you try to read a not-vector.
487 // Maps can be viewed as vectors too.
AsVector()488 Vector AsVector() const {
489 if (type_ == TYPE_VECTOR || type_ == TYPE_MAP) {
490 return Vector(Indirect(), byte_width_);
491 } else {
492 return Vector::EmptyVector();
493 }
494 }
495
AsTypedVector()496 TypedVector AsTypedVector() const {
497 if (IsTypedVector(type_)) {
498 return TypedVector(Indirect(), byte_width_,
499 ToTypedVectorElementType(type_));
500 } else {
501 return TypedVector::EmptyTypedVector();
502 }
503 }
504
AsFixedTypedVector()505 FixedTypedVector AsFixedTypedVector() const {
506 if (IsFixedTypedVector(type_)) {
507 uint8_t len = 0;
508 auto vtype = ToFixedTypedVectorElementType(type_, &len);
509 return FixedTypedVector(Indirect(), byte_width_, vtype, len);
510 } else {
511 return FixedTypedVector::EmptyFixedTypedVector();
512 }
513 }
514
AsMap()515 Map AsMap() const {
516 if (type_ == TYPE_MAP) {
517 return Map(Indirect(), byte_width_);
518 } else {
519 return Map::EmptyMap();
520 }
521 }
522
523 // Experimental: Mutation functions.
524 // These allow scalars in an already created buffer to be updated in-place.
525 // Since by default scalars are stored in the smallest possible space,
526 // the new value may not fit, in which case these functions return false.
527 // To avoid this, you can construct the values you intend to mutate using
528 // Builder::ForceMinimumBitWidth.
MutateInt(int64_t i)529 bool MutateInt(int64_t i) {
530 if (type_ == TYPE_INT) {
531 return Mutate(data_, i, parent_width_, WidthI(i));
532 } else if (type_ == TYPE_INDIRECT_INT) {
533 return Mutate(Indirect(), i, byte_width_, WidthI(i));
534 } else if (type_ == TYPE_UINT) {
535 auto u = static_cast<uint64_t>(i);
536 return Mutate(data_, u, parent_width_, WidthU(u));
537 } else if (type_ == TYPE_INDIRECT_UINT) {
538 auto u = static_cast<uint64_t>(i);
539 return Mutate(Indirect(), u, byte_width_, WidthU(u));
540 } else {
541 return false;
542 }
543 }
544
MutateUInt(uint64_t u)545 bool MutateUInt(uint64_t u) {
546 if (type_ == TYPE_UINT) {
547 return Mutate(data_, u, parent_width_, WidthU(u));
548 } else if (type_ == TYPE_INDIRECT_UINT) {
549 return Mutate(Indirect(), u, byte_width_, WidthU(u));
550 } else if (type_ == TYPE_INT) {
551 auto i = static_cast<int64_t>(u);
552 return Mutate(data_, i, parent_width_, WidthI(i));
553 } else if (type_ == TYPE_INDIRECT_INT) {
554 auto i = static_cast<int64_t>(u);
555 return Mutate(Indirect(), i, byte_width_, WidthI(i));
556 } else {
557 return false;
558 }
559 }
560
MutateFloat(float f)561 bool MutateFloat(float f) {
562 if (type_ == TYPE_FLOAT) {
563 return MutateF(data_, f, parent_width_, BIT_WIDTH_32);
564 } else if (type_ == TYPE_INDIRECT_FLOAT) {
565 return MutateF(Indirect(), f, byte_width_, BIT_WIDTH_32);
566 } else {
567 return false;
568 }
569 }
570
MutateFloat(double d)571 bool MutateFloat(double d) {
572 if (type_ == TYPE_FLOAT) {
573 return MutateF(data_, d, parent_width_, WidthF(d));
574 } else if (type_ == TYPE_INDIRECT_FLOAT) {
575 return MutateF(Indirect(), d, byte_width_, WidthF(d));
576 } else {
577 return false;
578 }
579 }
580
MutateString(const char * str,size_t len)581 bool MutateString(const char *str, size_t len) {
582 auto s = AsString();
583 if (s.IsTheEmptyString()) return false;
584 // This is very strict, could allow shorter strings, but that creates
585 // garbage.
586 if (s.length() != len) return false;
587 memcpy(const_cast<char *>(s.c_str()), str, len);
588 return true;
589 }
MutateString(const char * str)590 bool MutateString(const char *str) {
591 return MutateString(str, strlen(str));
592 }
MutateString(const std::string & str)593 bool MutateString(const std::string &str) {
594 return MutateString(str.data(), str.length());
595 }
596
597 private:
Indirect()598 const uint8_t *Indirect() const {
599 return flexbuffers::Indirect(data_, parent_width_);
600 }
601
Mutate(const uint8_t * dest,T t,size_t byte_width,BitWidth value_width)602 template<typename T> bool Mutate(const uint8_t *dest, T t, size_t byte_width,
603 BitWidth value_width) {
604 auto fits = (1U << value_width) <= byte_width;
605 if (fits) {
606 t = flatbuffers::EndianScalar(t);
607 memcpy(const_cast<uint8_t *>(dest), &t, byte_width);
608 }
609 return fits;
610 }
611
MutateF(const uint8_t * dest,T t,size_t byte_width,BitWidth value_width)612 template<typename T> bool MutateF(const uint8_t *dest, T t, size_t byte_width,
613 BitWidth value_width) {
614 if (byte_width == sizeof(double))
615 return Mutate(dest, static_cast<double>(t), byte_width, value_width);
616 if (byte_width == sizeof(float))
617 return Mutate(dest, static_cast<float>(t), byte_width, value_width);
618 assert(false);
619 return false;
620 }
621
622 const uint8_t *data_;
623 uint8_t parent_width_;
624 uint8_t byte_width_;
625 Type type_;
626 };
627
PackedType(BitWidth bit_width,Type type)628 inline uint8_t PackedType(BitWidth bit_width, Type type) {
629 return static_cast<uint8_t>(bit_width | (type << 2));
630 }
631
NullPackedType()632 inline uint8_t NullPackedType() {
633 return PackedType(BIT_WIDTH_8, TYPE_NULL);
634 }
635
636 // Vector accessors.
637 // Note: if you try to access outside of bounds, you get a Null value back
638 // instead. Normally this would be an assert, but since this is "dynamically
639 // typed" data, you may not want that (someone sends you a 2d vector and you
640 // wanted 3d).
641 // The Null converts seamlessly into a default value for any other type.
642 // TODO(wvo): Could introduce an #ifdef that makes this into an assert?
643 inline Reference Vector::operator[](size_t i) const {
644 auto len = size();
645 if (i >= len) return Reference(nullptr, 1, NullPackedType());
646 auto packed_type = (data_ + len * byte_width_)[i];
647 auto elem = data_ + i * byte_width_;
648 return Reference(elem, byte_width_, packed_type);
649 }
650
651 inline Reference TypedVector::operator[](size_t i) const {
652 auto len = size();
653 if (i >= len) return Reference(nullptr, 1, NullPackedType());
654 auto elem = data_ + i * byte_width_;
655 return Reference(elem, byte_width_, 1, type_);
656 }
657
658 inline Reference FixedTypedVector::operator[](size_t i) const {
659 if (i >= len_) return Reference(nullptr, 1, NullPackedType());
660 auto elem = data_ + i * byte_width_;
661 return Reference(elem, byte_width_, 1, type_);
662 }
663
KeyCompare(const void * key,const void * elem)664 template<typename T> int KeyCompare(const void *key, const void *elem) {
665 auto str_elem = reinterpret_cast<const char *>(
666 Indirect<T>(reinterpret_cast<const uint8_t *>(elem)));
667 auto skey = reinterpret_cast<const char *>(key);
668 return strcmp(skey, str_elem);
669 }
670
671 inline Reference Map::operator[](const char *key) const {
672 auto keys = Keys();
673 // We can't pass keys.byte_width_ to the comparison function, so we have
674 // to pick the right one ahead of time.
675 int (*comp)(const void *, const void *) = nullptr;
676 switch (keys.byte_width_) {
677 case 1: comp = KeyCompare<uint8_t>; break;
678 case 2: comp = KeyCompare<uint16_t>; break;
679 case 4: comp = KeyCompare<uint32_t>; break;
680 case 8: comp = KeyCompare<uint64_t>; break;
681 }
682 auto res = std::bsearch(key, keys.data_, keys.size(), keys.byte_width_, comp);
683 if (!res)
684 return Reference(nullptr, 1, NullPackedType());
685 auto i = (reinterpret_cast<uint8_t *>(res) - keys.data_) / keys.byte_width_;
686 return (*static_cast<const Vector *>(this))[i];
687 }
688
689 inline Reference Map::operator[](const std::string &key) const {
690 return (*this)[key.c_str()];
691 }
692
GetRoot(const uint8_t * buffer,size_t size)693 inline Reference GetRoot(const uint8_t *buffer, size_t size) {
694 // See Finish() below for the serialization counterpart of this.
695 // The root starts at the end of the buffer, so we parse backwards from there.
696 auto end = buffer + size;
697 auto byte_width = *--end;
698 auto packed_type = *--end;
699 end -= byte_width; // The root data item.
700 return Reference(end, byte_width, packed_type);
701 }
702
GetRoot(const std::vector<uint8_t> & buffer)703 inline Reference GetRoot(const std::vector<uint8_t> &buffer) {
704 return GetRoot(buffer.data(), buffer.size());
705 }
706
707 // Flags that configure how the Builder behaves.
708 // The "Share" flags determine if the Builder automatically tries to pool
709 // this type. Pooling can reduce the size of serialized data if there are
710 // multiple maps of the same kind, at the expense of slightly slower
711 // serialization (the cost of lookups) and more memory use (std::set).
712 // By default this is on for keys, but off for strings.
713 // Turn keys off if you have e.g. only one map.
714 // Turn strings on if you expect many non-unique string values.
715 // Additionally, sharing key vectors can save space if you have maps with
716 // identical field populations.
717 enum BuilderFlag {
718 BUILDER_FLAG_NONE = 0,
719 BUILDER_FLAG_SHARE_KEYS = 1,
720 BUILDER_FLAG_SHARE_STRINGS = 2,
721 BUILDER_FLAG_SHARE_KEYS_AND_STRINGS = 3,
722 BUILDER_FLAG_SHARE_KEY_VECTORS = 4,
723 BUILDER_FLAG_SHARE_ALL = 7,
724 };
725
726 class Builder FLATBUFFERS_FINAL_CLASS {
727 public:
728 Builder(size_t initial_size = 256,
729 BuilderFlag flags = BUILDER_FLAG_SHARE_KEYS)
buf_(initial_size)730 : buf_(initial_size), finished_(false), flags_(flags),
731 force_min_bit_width_(BIT_WIDTH_8), key_pool(KeyOffsetCompare(buf_)),
732 string_pool(StringOffsetCompare(buf_)) {
733 buf_.clear();
734 }
735
736 /// @brief Get the serialized buffer (after you call `Finish()`).
737 /// @return Returns a vector owned by this class.
GetBuffer()738 const std::vector<uint8_t> &GetBuffer() const {
739 Finished();
740 return buf_;
741 }
742
743 // All value constructing functions below have two versions: one that
744 // takes a key (for placement inside a map) and one that doesn't (for inside
745 // vectors and elsewhere).
746
Null()747 void Null() { stack_.push_back(Value()); }
Null(const char * key)748 void Null(const char *key) { Key(key); Null(); }
749
Int(int64_t i)750 void Int(int64_t i) { stack_.push_back(Value(i, TYPE_INT, WidthI(i))); }
Int(const char * key,int64_t i)751 void Int(const char *key, int64_t i) { Key(key); Int(i); }
752
UInt(uint64_t u)753 void UInt(uint64_t u) { stack_.push_back(Value(u, TYPE_UINT, WidthU(u))); }
UInt(const char * key,uint64_t u)754 void UInt(const char *key, uint64_t u) { Key(key); Int(u); }
755
Float(float f)756 void Float(float f) { stack_.push_back(Value(f)); }
Float(const char * key,float f)757 void Float(const char *key, float f) { Key(key); Float(f); }
758
Double(double f)759 void Double(double f) { stack_.push_back(Value(f)); }
Double(const char * key,double d)760 void Double(const char *key, double d) { Key(key); Double(d); }
761
Bool(bool b)762 void Bool(bool b) { Int(static_cast<int64_t>(b)); }
Bool(const char * key,bool b)763 void Bool(const char *key, bool b) { Key(key); Bool(b); }
764
IndirectInt(int64_t i)765 void IndirectInt(int64_t i) {
766 PushIndirect(i, TYPE_INDIRECT_INT, WidthI(i));
767 }
IndirectInt(const char * key,int64_t i)768 void IndirectInt(const char *key, int64_t i) {
769 Key(key);
770 IndirectInt(i);
771 }
772
IndirectUInt(uint64_t u)773 void IndirectUInt(uint64_t u) {
774 PushIndirect(u, TYPE_INDIRECT_UINT, WidthU(u));
775 }
IndirectUInt(const char * key,uint64_t u)776 void IndirectUInt(const char *key, uint64_t u) {
777 Key(key);
778 IndirectUInt(u);
779 }
780
IndirectFloat(float f)781 void IndirectFloat(float f) {
782 PushIndirect(f, TYPE_INDIRECT_FLOAT, BIT_WIDTH_32);
783 }
IndirectFloat(const char * key,float f)784 void IndirectFloat(const char *key, float f) {
785 Key(key);
786 IndirectFloat(f);
787 }
788
IndirectDouble(double f)789 void IndirectDouble(double f) {
790 PushIndirect(f, TYPE_INDIRECT_FLOAT, WidthF(f));
791 }
IndirectDouble(const char * key,double d)792 void IndirectDouble(const char *key, double d) {
793 Key(key);
794 IndirectDouble(d);
795 }
796
Key(const char * str,size_t len)797 size_t Key(const char *str, size_t len) {
798 auto sloc = buf_.size();
799 WriteBytes(str, len + 1);
800 if (flags_ & BUILDER_FLAG_SHARE_KEYS) {
801 auto it = key_pool.find(sloc);
802 if (it != key_pool.end()) {
803 // Already in the buffer. Remove key we just serialized, and use
804 // existing offset instead.
805 buf_.resize(sloc);
806 sloc = *it;
807 } else {
808 key_pool.insert(sloc);
809 }
810 }
811 stack_.push_back(Value(static_cast<uint64_t>(sloc), TYPE_KEY, BIT_WIDTH_8));
812 return sloc;
813 }
814
Key(const char * str)815 size_t Key(const char *str) { return Key(str, strlen(str)); }
Key(const std::string & str)816 size_t Key(const std::string &str) { return Key(str.c_str(), str.size()); }
817
String(const char * str,size_t len)818 size_t String(const char *str, size_t len) {
819 auto reset_to = buf_.size();
820 auto sloc = CreateBlob(str, len, 1, TYPE_STRING);
821 if (flags_ & BUILDER_FLAG_SHARE_STRINGS) {
822 StringOffset so(sloc, len);
823 auto it = string_pool.find(so);
824 if (it != string_pool.end()) {
825 // Already in the buffer. Remove string we just serialized, and use
826 // existing offset instead.
827 buf_.resize(reset_to);
828 sloc = it->first;
829 stack_.back().u_ = sloc;
830 } else {
831 string_pool.insert(so);
832 }
833 }
834 return sloc;
835 }
String(const char * str)836 size_t String(const char *str) {
837 return String(str, strlen(str));
838 }
String(const std::string & str)839 size_t String(const std::string &str) {
840 return String(str.c_str(), str.size());
841 }
String(const flexbuffers::String & str)842 void String(const flexbuffers::String &str) {
843 String(str.c_str(), str.length());
844 }
845
String(const char * key,const char * str)846 void String(const char *key, const char *str) {
847 Key(key);
848 String(str);
849 }
String(const char * key,const std::string & str)850 void String(const char *key, const std::string &str) {
851 Key(key);
852 String(str);
853 }
String(const char * key,const flexbuffers::String & str)854 void String(const char *key, const flexbuffers::String &str) {
855 Key(key);
856 String(str);
857 }
858
Blob(const void * data,size_t len)859 size_t Blob(const void *data, size_t len) {
860 return CreateBlob(data, len, 0, TYPE_BLOB);
861 }
Blob(const std::vector<uint8_t> & v)862 size_t Blob(const std::vector<uint8_t> &v) {
863 return CreateBlob(v.data(), v.size(), 0, TYPE_BLOB);
864 }
865
866 // TODO(wvo): support all the FlexBuffer types (like flexbuffers::String),
867 // e.g. Vector etc. Also in overloaded versions.
868 // Also some FlatBuffers types?
869
StartVector()870 size_t StartVector() { return stack_.size(); }
StartVector(const char * key)871 size_t StartVector(const char *key) { Key(key); return stack_.size(); }
StartMap()872 size_t StartMap() { return stack_.size(); }
StartMap(const char * key)873 size_t StartMap(const char *key) { Key(key); return stack_.size(); }
874
875 // TODO(wvo): allow this to specify an aligment greater than the natural
876 // alignment.
EndVector(size_t start,bool typed,bool fixed)877 size_t EndVector(size_t start, bool typed, bool fixed) {
878 auto vec = CreateVector(start, stack_.size() - start, 1, typed, fixed);
879 // Remove temp elements and return vector.
880 stack_.resize(start);
881 stack_.push_back(vec);
882 return static_cast<size_t>(vec.u_);
883 }
884
EndMap(size_t start)885 size_t EndMap(size_t start) {
886 // We should have interleaved keys and values on the stack.
887 // Make sure it is an even number:
888 auto len = stack_.size() - start;
889 assert(!(len & 1));
890 len /= 2;
891 // Make sure keys are all strings:
892 for (auto key = start; key < stack_.size(); key += 2) {
893 assert(stack_[key].type_ == TYPE_KEY);
894 }
895 // Now sort values, so later we can do a binary seach lookup.
896 // We want to sort 2 array elements at a time.
897 struct TwoValue { Value key; Value val; };
898 // TODO(wvo): strict aliasing?
899 // TODO(wvo): allow the caller to indicate the data is already sorted
900 // for maximum efficiency? With an assert to check sortedness to make sure
901 // we're not breaking binary search.
902 // Or, we can track if the map is sorted as keys are added which would be
903 // be quite cheap (cheaper than checking it here), so we can skip this
904 // step automatically when appliccable, and encourage people to write in
905 // sorted fashion.
906 // std::sort is typically already a lot faster on sorted data though.
907 auto dict = reinterpret_cast<TwoValue *>(stack_.data() + start);
908 std::sort(dict, dict + len,
909 [&](const TwoValue &a, const TwoValue &b) -> bool {
910 auto as = reinterpret_cast<const char *>(buf_.data() + a.key.u_);
911 auto bs = reinterpret_cast<const char *>(buf_.data() + b.key.u_);
912 auto comp = strcmp(as, bs);
913 // If this assertion hits, you've added two keys with the same value to
914 // this map.
915 // TODO: Have to check for pointer equality, as some sort implementation
916 // apparently call this function with the same element?? Why?
917 assert(comp || &a == &b);
918 return comp < 0;
919 });
920 // First create a vector out of all keys.
921 // TODO(wvo): if kBuilderFlagShareKeyVectors is true, see if we can share
922 // the first vector.
923 auto keys = CreateVector(start, len, 2, true, false);
924 auto vec = CreateVector(start + 1, len, 2, false, false, &keys);
925 // Remove temp elements and return map.
926 stack_.resize(start);
927 stack_.push_back(vec);
928 return static_cast<size_t>(vec.u_);
929 }
930
Vector(F f)931 template<typename F> size_t Vector(F f) {
932 auto start = StartVector();
933 f();
934 return EndVector(start, false, false);
935 }
Vector(const char * key,F f)936 template<typename F> size_t Vector(const char *key, F f) {
937 auto start = StartVector(key);
938 f();
939 return EndVector(start, false, false);
940 }
Vector(const T * elems,size_t len)941 template<typename T> void Vector(const T *elems, size_t len) {
942 if (std::is_scalar<T>::value) {
943 // This path should be a lot quicker and use less space.
944 ScalarVector(elems, len, false);
945 } else {
946 auto start = StartVector();
947 for (size_t i = 0; i < len; i++) Add(elems[i]);
948 EndVector(start, false, false);
949 }
950 }
Vector(const char * key,const T * elems,size_t len)951 template<typename T> void Vector(const char *key, const T *elems,
952 size_t len) {
953 Key(key);
954 Vector(elems, len);
955 }
Vector(const std::vector<T> & vec)956 template<typename T> void Vector(const std::vector<T> &vec) {
957 Vector(vec.data(), vec.size());
958 }
959
TypedVector(F f)960 template<typename F> size_t TypedVector(F f) {
961 auto start = StartVector();
962 f();
963 return EndVector(start, true, false);
964 }
TypedVector(const char * key,F f)965 template<typename F> size_t TypedVector(const char *key, F f) {
966 auto start = StartVector(key);
967 f();
968 return EndVector(start, true, false);
969 }
970
FixedTypedVector(const T * elems,size_t len)971 template<typename T> size_t FixedTypedVector(const T *elems, size_t len) {
972 // We only support a few fixed vector lengths. Anything bigger use a
973 // regular typed vector.
974 assert(len >= 2 && len <= 4);
975 // And only scalar values.
976 assert(std::is_scalar<T>::value);
977 return ScalarVector(elems, len, true);
978 }
979
FixedTypedVector(const char * key,const T * elems,size_t len)980 template<typename T> size_t FixedTypedVector(const char *key, const T *elems,
981 size_t len) {
982 Key(key);
983 return FixedTypedVector(elems, len);
984 }
985
Map(F f)986 template<typename F> size_t Map(F f) {
987 auto start = StartMap();
988 f();
989 return EndMap(start);
990 }
Map(const char * key,F f)991 template<typename F> size_t Map(const char *key, F f) {
992 auto start = StartMap(key);
993 f();
994 return EndMap(start);
995 }
Map(const std::map<std::string,T> & map)996 template<typename T> void Map(const std::map<std::string, T> &map) {
997 auto start = StartMap();
998 for (auto it = map.begin(); it != map.end(); ++it)
999 Add(it->first.c_str(), it->second);
1000 EndMap(start);
1001 }
1002
1003 // Overloaded Add that tries to call the correct function above.
Add(int8_t i)1004 void Add(int8_t i) { Int(i); }
Add(int16_t i)1005 void Add(int16_t i) { Int(i); }
Add(int32_t i)1006 void Add(int32_t i) { Int(i); }
Add(int64_t i)1007 void Add(int64_t i) { Int(i); }
Add(uint8_t u)1008 void Add(uint8_t u) { UInt(u); }
Add(uint16_t u)1009 void Add(uint16_t u) { UInt(u); }
Add(uint32_t u)1010 void Add(uint32_t u) { UInt(u); }
Add(uint64_t u)1011 void Add(uint64_t u) { UInt(u); }
Add(float f)1012 void Add(float f) { Float(f); }
Add(double d)1013 void Add(double d) { Double(d); }
Add(bool b)1014 void Add(bool b) { Bool(b); }
Add(const char * str)1015 void Add(const char *str) { String(str); }
Add(const std::string & str)1016 void Add(const std::string &str) { String(str); }
Add(const flexbuffers::String & str)1017 void Add(const flexbuffers::String &str) { String(str); }
1018
Add(const std::vector<T> & vec)1019 template<typename T> void Add(const std::vector<T> &vec) {
1020 Vector(vec);
1021 }
1022
Add(const char * key,const T & t)1023 template<typename T> void Add(const char *key, const T &t) {
1024 Key(key);
1025 Add(t);
1026 }
1027
Add(const std::map<std::string,T> & map)1028 template<typename T> void Add(const std::map<std::string, T> &map) {
1029 Map(map);
1030 }
1031
1032 template<typename T> void operator+=(const T &t) {
1033 Add(t);
1034 }
1035
1036 // This function is useful in combination with the Mutate* functions above.
1037 // It forces elements of vectors and maps to have a minimum size, such that
1038 // they can later be updated without failing.
1039 // Call with no arguments to reset.
1040 void ForceMinimumBitWidth(BitWidth bw = BIT_WIDTH_8) {
1041 force_min_bit_width_ = bw;
1042 }
1043
Finish()1044 void Finish() {
1045 // If you hit this assert, you likely have objects that were never included
1046 // in a parent. You need to have exactly one root to finish a buffer.
1047 // Check your Start/End calls are matched, and all objects are inside
1048 // some other object.
1049 assert(stack_.size() == 1);
1050
1051 // Write root value.
1052 auto byte_width = Align(stack_[0].ElemWidth(buf_.size(), 0));
1053 WriteAny(stack_[0], byte_width);
1054 // Write root type.
1055 Write(stack_[0].StoredPackedType(), 1);
1056 // Write root size. Normally determined by parent, but root has no parent :)
1057 Write(byte_width, 1);
1058
1059 finished_ = true;
1060 }
1061
1062 private:
Finished()1063 void Finished() const {
1064 // If you get this assert, you're attempting to get access a buffer
1065 // which hasn't been finished yet. Be sure to call
1066 // Builder::Finish with your root object.
1067 assert(finished_);
1068 }
1069
1070 // Align to prepare for writing a scalar with a certain size.
Align(BitWidth alignment)1071 uint8_t Align(BitWidth alignment) {
1072 auto byte_width = 1U << alignment;
1073 buf_.insert(buf_.end(), flatbuffers::PaddingBytes(buf_.size(), byte_width),
1074 0);
1075 return byte_width;
1076 }
1077
WriteBytes(const void * val,size_t size)1078 void WriteBytes(const void *val, size_t size) {
1079 buf_.insert(buf_.end(),
1080 reinterpret_cast<const uint8_t *>(val),
1081 reinterpret_cast<const uint8_t *>(val) + size);
1082 }
1083
1084 // For values T >= byte_width
Write(T val,uint8_t byte_width)1085 template<typename T> void Write(T val, uint8_t byte_width) {
1086 val = flatbuffers::EndianScalar(val);
1087 WriteBytes(&val, byte_width);
1088 }
1089
WriteDouble(double f,uint8_t byte_width)1090 void WriteDouble(double f, uint8_t byte_width) {
1091 switch (byte_width) {
1092 case 8: Write(f, byte_width); break;
1093 case 4: Write(static_cast<float>(f), byte_width); break;
1094 //case 2: Write(static_cast<half>(f), byte_width); break;
1095 //case 1: Write(static_cast<quarter>(f), byte_width); break;
1096 default: assert(0);
1097 }
1098 }
1099
WriteOffset(uint64_t o,uint8_t byte_width)1100 void WriteOffset(uint64_t o, uint8_t byte_width) {
1101 auto reloff = buf_.size() - o;
1102 assert(reloff < 1ULL << (byte_width * 8) || byte_width == 8);
1103 Write(reloff, byte_width);
1104 }
1105
PushIndirect(T val,Type type,BitWidth bit_width)1106 template<typename T> void PushIndirect(T val, Type type, BitWidth bit_width) {
1107 auto byte_width = Align(bit_width);
1108 auto iloc = buf_.size();
1109 Write(val, byte_width);
1110 stack_.push_back(Value(static_cast<uint64_t>(iloc), type, bit_width));
1111 }
1112
WidthB(size_t byte_width)1113 static BitWidth WidthB(size_t byte_width) {
1114 switch (byte_width) {
1115 case 1: return BIT_WIDTH_8;
1116 case 2: return BIT_WIDTH_16;
1117 case 4: return BIT_WIDTH_32;
1118 case 8: return BIT_WIDTH_64;
1119 default: assert(false); return BIT_WIDTH_64;
1120 }
1121 }
1122
GetScalarType()1123 template<typename T> static Type GetScalarType() {
1124 assert(std::is_scalar<T>::value);
1125 return std::is_floating_point<T>::value
1126 ? TYPE_FLOAT
1127 : (std::is_unsigned<T>::value ? TYPE_UINT : TYPE_INT);
1128 }
1129
1130 struct Value {
1131 union {
1132 int64_t i_;
1133 uint64_t u_;
1134 double f_;
1135 };
1136
1137 Type type_;
1138
1139 // For scalars: of itself, for vector: of its elements, for string: length.
1140 BitWidth min_bit_width_;
1141
ValueValue1142 Value() : i_(0), type_(TYPE_NULL), min_bit_width_(BIT_WIDTH_8) {}
1143
ValueValue1144 Value(int64_t i, Type t, BitWidth bw)
1145 : i_(i), type_(t), min_bit_width_(bw) {}
ValueValue1146 Value(uint64_t u, Type t, BitWidth bw)
1147 : u_(u), type_(t), min_bit_width_(bw) {}
1148
ValueValue1149 Value(float f)
1150 : f_(f), type_(TYPE_FLOAT), min_bit_width_(BIT_WIDTH_32) {}
ValueValue1151 Value(double f)
1152 : f_(f), type_(TYPE_FLOAT), min_bit_width_(WidthF(f)) {}
1153
1154 uint8_t StoredPackedType(BitWidth parent_bit_width_= BIT_WIDTH_8) const {
1155 return PackedType(StoredWidth(parent_bit_width_), type_);
1156 }
1157
ElemWidthValue1158 BitWidth ElemWidth(size_t buf_size, size_t elem_index) const {
1159 if (IsInline(type_)) {
1160 return min_bit_width_;
1161 } else {
1162 // We have an absolute offset, but want to store a relative offset
1163 // elem_index elements beyond the current buffer end. Since whether
1164 // the relative offset fits in a certain byte_width depends on
1165 // the size of the elements before it (and their alignment), we have
1166 // to test for each size in turn.
1167 for (size_t byte_width = 1;
1168 byte_width <= sizeof(flatbuffers::largest_scalar_t);
1169 byte_width *= 2) {
1170 // Where are we going to write this offset?
1171 auto offset_loc =
1172 buf_size +
1173 flatbuffers::PaddingBytes(buf_size, byte_width) +
1174 elem_index * byte_width;
1175 // Compute relative offset.
1176 auto offset = offset_loc - u_;
1177 // Does it fit?
1178 auto bit_width = WidthU(offset);
1179 if (1U << bit_width == byte_width) return bit_width;
1180 }
1181 assert(false); // Must match one of the sizes above.
1182 return BIT_WIDTH_64;
1183 }
1184 }
1185
1186 BitWidth StoredWidth(BitWidth parent_bit_width_ = BIT_WIDTH_8) const {
1187 if (IsInline(type_)) {
1188 return std::max(min_bit_width_, parent_bit_width_);
1189 } else {
1190 return min_bit_width_;
1191 }
1192 }
1193 };
1194
WriteAny(const Value & val,uint8_t byte_width)1195 void WriteAny(const Value &val, uint8_t byte_width) {
1196 switch (val.type_) {
1197 case TYPE_NULL:
1198 case TYPE_INT:
1199 Write(val.i_, byte_width);
1200 break;
1201 case TYPE_UINT:
1202 Write(val.u_, byte_width);
1203 break;
1204 case TYPE_FLOAT:
1205 WriteDouble(val.f_, byte_width);
1206 break;
1207 default:
1208 WriteOffset(val.u_, byte_width);
1209 break;
1210 }
1211 }
1212
CreateBlob(const void * data,size_t len,size_t trailing,Type type)1213 size_t CreateBlob(const void *data, size_t len, size_t trailing, Type type) {
1214 auto bit_width = WidthU(len);
1215 auto byte_width = Align(bit_width);
1216 Write<uint64_t>(len, byte_width);
1217 auto sloc = buf_.size();
1218 WriteBytes(data, len + trailing);
1219 stack_.push_back(Value(static_cast<uint64_t>(sloc), type, bit_width));
1220 return sloc;
1221 }
1222
ScalarVector(const T * elems,size_t len,bool fixed)1223 template<typename T> size_t ScalarVector(const T *elems, size_t len,
1224 bool fixed) {
1225 auto vector_type = GetScalarType<T>();
1226 auto byte_width = sizeof(T);
1227 auto bit_width = WidthB(byte_width);
1228 // If you get this assert, you're trying to write a vector with a size
1229 // field that is bigger than the scalars you're trying to write (e.g. a
1230 // byte vector > 255 elements). For such types, write a "blob" instead.
1231 // TODO: instead of asserting, could write vector with larger elements
1232 // instead, though that would be wasteful.
1233 assert(WidthU(len) <= bit_width);
1234 if (!fixed) Write(len, byte_width);
1235 auto vloc = buf_.size();
1236 for (size_t i = 0; i < len; i++) Write(elems[i], byte_width);
1237 stack_.push_back(Value(static_cast<uint64_t>(vloc),
1238 ToTypedVector(vector_type, fixed ? len : 0),
1239 bit_width));
1240 return vloc;
1241 }
1242
1243 Value CreateVector(size_t start, size_t vec_len, size_t step, bool typed,
1244 bool fixed, const Value *keys = nullptr) {
1245 // Figure out smallest bit width we can store this vector with.
1246 auto bit_width = std::max(force_min_bit_width_, WidthU(vec_len));
1247 auto prefix_elems = 1;
1248 if (keys) {
1249 // If this vector is part of a map, we will pre-fix an offset to the keys
1250 // to this vector.
1251 bit_width = std::max(bit_width, keys->ElemWidth(buf_.size(), 0));
1252 prefix_elems += 2;
1253 }
1254 Type vector_type = TYPE_KEY;
1255 // Check bit widths and types for all elements.
1256 for (size_t i = start; i < stack_.size(); i += step) {
1257 auto elem_width = stack_[i].ElemWidth(buf_.size(), i + prefix_elems);
1258 bit_width = std::max(bit_width, elem_width);
1259 if (typed) {
1260 if (i == start) {
1261 vector_type = stack_[i].type_;
1262 } else {
1263 // If you get this assert, you are writing a typed vector with
1264 // elements that are not all the same type.
1265 assert(vector_type == stack_[i].type_);
1266 }
1267 }
1268 }
1269 // If you get this assert, your fixed types are not one of:
1270 // Int / UInt / Float / Key.
1271 assert(IsTypedVectorElementType(vector_type));
1272 auto byte_width = Align(bit_width);
1273 // Write vector. First the keys width/offset if available, and size.
1274 if (keys) {
1275 WriteOffset(keys->u_, byte_width);
1276 Write(1U << keys->min_bit_width_, byte_width);
1277 }
1278 if (!fixed) Write(vec_len, byte_width);
1279 // Then the actual data.
1280 auto vloc = buf_.size();
1281 for (size_t i = start; i < stack_.size(); i += step) {
1282 WriteAny(stack_[i], byte_width);
1283 }
1284 // Then the types.
1285 if (!typed) {
1286 for (size_t i = start; i < stack_.size(); i += step) {
1287 buf_.push_back(stack_[i].StoredPackedType(bit_width));
1288 }
1289 }
1290 return Value(static_cast<uint64_t>(vloc), keys
1291 ? TYPE_MAP
1292 : (typed
1293 ? ToTypedVector(vector_type, fixed ? vec_len : 0)
1294 : TYPE_VECTOR),
1295 bit_width);
1296 }
1297
1298 // You shouldn't really be copying instances of this class.
1299 Builder(const Builder &);
1300 Builder &operator=(const Builder &);
1301
1302 std::vector<uint8_t> buf_;
1303 std::vector<Value> stack_;
1304
1305 bool finished_;
1306
1307 BuilderFlag flags_;
1308
1309 BitWidth force_min_bit_width_;
1310
1311 struct KeyOffsetCompare {
KeyOffsetCompareKeyOffsetCompare1312 KeyOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
operatorKeyOffsetCompare1313 bool operator() (size_t a, size_t b) const {
1314 auto stra = reinterpret_cast<const char *>(buf_->data() + a);
1315 auto strb = reinterpret_cast<const char *>(buf_->data() + b);
1316 return strcmp(stra, strb) < 0;
1317 }
1318 const std::vector<uint8_t> *buf_;
1319 };
1320
1321 typedef std::pair<size_t, size_t> StringOffset;
1322 struct StringOffsetCompare {
StringOffsetCompareStringOffsetCompare1323 StringOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
operatorStringOffsetCompare1324 bool operator() (const StringOffset &a, const StringOffset &b) const {
1325 auto stra = reinterpret_cast<const char *>(buf_->data() + a.first);
1326 auto strb = reinterpret_cast<const char *>(buf_->data() + b.first);
1327 return strncmp(stra, strb, std::min(a.second, b.second) + 1) < 0;
1328 }
1329 const std::vector<uint8_t> *buf_;
1330 };
1331
1332 typedef std::set<size_t, KeyOffsetCompare> KeyOffsetMap;
1333 typedef std::set<StringOffset, StringOffsetCompare> StringOffsetMap;
1334
1335 KeyOffsetMap key_pool;
1336 StringOffsetMap string_pool;
1337 };
1338
1339 } // namespace flexbuffers
1340
1341 #endif // FLATBUFFERS_FLEXBUFFERS_H_
1342