Coverage Report

Created: 2026-05-16 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/flatbuffers/include/flatbuffers/flexbuffers.h
Line
Count
Source
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
#include <algorithm>
21
#include <map>
22
// Used to select STL variant.
23
#include "flatbuffers/base.h"
24
// We use the basic binary writing functions from the regular FlatBuffers.
25
#include "flatbuffers/util.h"
26
27
#ifdef _MSC_VER
28
#include <intrin.h>
29
#endif
30
31
#if defined(_MSC_VER)
32
#pragma warning(push)
33
#pragma warning(disable : 4127)  // C4127: conditional expression is constant
34
#endif
35
36
namespace flexbuffers {
37
38
class Reference;
39
class Map;
40
41
// These are used in the lower 2 bits of a type field to determine the size of
42
// the elements (and or size field) of the item pointed to (e.g. vector).
43
enum BitWidth {
44
  BIT_WIDTH_8 = 0,
45
  BIT_WIDTH_16 = 1,
46
  BIT_WIDTH_32 = 2,
47
  BIT_WIDTH_64 = 3,
48
};
49
50
// These are used as the upper 6 bits of a type field to indicate the actual
51
// type.
52
enum Type {
53
  FBT_NULL = 0,
54
  FBT_INT = 1,
55
  FBT_UINT = 2,
56
  FBT_FLOAT = 3,
57
  // Types above stored inline, types below (except FBT_BOOL) store an offset.
58
  FBT_KEY = 4,
59
  FBT_STRING = 5,
60
  FBT_INDIRECT_INT = 6,
61
  FBT_INDIRECT_UINT = 7,
62
  FBT_INDIRECT_FLOAT = 8,
63
  FBT_MAP = 9,
64
  FBT_VECTOR = 10,      // Untyped.
65
  FBT_VECTOR_INT = 11,  // Typed any size (stores no type table).
66
  FBT_VECTOR_UINT = 12,
67
  FBT_VECTOR_FLOAT = 13,
68
  FBT_VECTOR_KEY = 14,
69
  // DEPRECATED, use FBT_VECTOR or FBT_VECTOR_KEY instead.
70
  // Read test.cpp/FlexBuffersDeprecatedTest() for details on why.
71
  FBT_VECTOR_STRING_DEPRECATED = 15,
72
  FBT_VECTOR_INT2 = 16,  // Typed tuple (no type table, no size field).
73
  FBT_VECTOR_UINT2 = 17,
74
  FBT_VECTOR_FLOAT2 = 18,
75
  FBT_VECTOR_INT3 = 19,  // Typed triple (no type table, no size field).
76
  FBT_VECTOR_UINT3 = 20,
77
  FBT_VECTOR_FLOAT3 = 21,
78
  FBT_VECTOR_INT4 = 22,  // Typed quad (no type table, no size field).
79
  FBT_VECTOR_UINT4 = 23,
80
  FBT_VECTOR_FLOAT4 = 24,
81
  FBT_BLOB = 25,
82
  FBT_BOOL = 26,
83
  FBT_VECTOR_BOOL =
84
      36,  // To Allow the same type of conversion of type to vector type
85
86
  FBT_MAX_TYPE = 37
87
};
88
89
6.80M
inline bool IsInline(Type t) { return t <= FBT_FLOAT || t == FBT_BOOL; }
90
91
152k
inline bool IsTypedVectorElementType(Type t) {
92
152k
  return (t >= FBT_INT && t <= FBT_STRING) || t == FBT_BOOL;
93
152k
}
94
95
0
inline bool IsTypedVector(Type t) {
96
0
  return (t >= FBT_VECTOR_INT && t <= FBT_VECTOR_STRING_DEPRECATED) ||
97
0
         t == FBT_VECTOR_BOOL;
98
0
}
99
100
0
inline bool IsFixedTypedVector(Type t) {
101
0
  return t >= FBT_VECTOR_INT2 && t <= FBT_VECTOR_FLOAT4;
102
0
}
103
104
76.4k
inline Type ToTypedVector(Type t, size_t fixed_len = 0) {
105
76.4k
  FLATBUFFERS_ASSERT(IsTypedVectorElementType(t));
106
76.4k
  switch (fixed_len) {
107
76.4k
    case 0:
108
76.4k
      return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT);
109
0
    case 2:
110
0
      return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT2);
111
0
    case 3:
112
0
      return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT3);
113
0
    case 4:
114
0
      return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT4);
115
0
    default:
116
0
      FLATBUFFERS_ASSERT(0);
117
0
      return FBT_NULL;
118
76.4k
  }
119
76.4k
}
120
121
0
inline Type ToTypedVectorElementType(Type t) {
122
0
  FLATBUFFERS_ASSERT(IsTypedVector(t));
123
0
  return static_cast<Type>(t - FBT_VECTOR_INT + FBT_INT);
124
0
}
125
126
0
inline Type ToFixedTypedVectorElementType(Type t, uint8_t* len) {
127
0
  FLATBUFFERS_ASSERT(IsFixedTypedVector(t));
128
0
  auto fixed_type = t - FBT_VECTOR_INT2;
129
0
  *len = static_cast<uint8_t>(fixed_type / 3 +
130
0
                              2);  // 3 types each, starting from length 2.
131
0
  return static_cast<Type>(fixed_type % 3 + FBT_INT);
132
0
}
133
134
// TODO: implement proper support for 8/16bit floats, or decide not to
135
// support them.
136
typedef int16_t half;
137
typedef int8_t quarter;
138
139
// TODO: can we do this without conditionals using intrinsics or inline asm
140
// on some platforms? Given branch prediction the method below should be
141
// decently quick, but it is the most frequently executed function.
142
// We could do an (unaligned) 64-bit read if we ifdef out the platforms for
143
// which that doesn't work (or where we'd read into un-owned memory).
144
template <typename R, typename T1, typename T2, typename T4, typename T8>
145
6.35M
R ReadSizedScalar(const uint8_t* data, uint8_t byte_width) {
146
6.35M
  return byte_width < 4
147
6.35M
             ? (byte_width < 2
148
1.05M
                    ? static_cast<R>(flatbuffers::ReadScalar<T1>(data))
149
1.05M
                    : static_cast<R>(flatbuffers::ReadScalar<T2>(data)))
150
6.35M
             : (byte_width < 8
151
5.30M
                    ? static_cast<R>(flatbuffers::ReadScalar<T4>(data))
152
5.30M
                    : static_cast<R>(flatbuffers::ReadScalar<T8>(data)));
153
6.35M
}
unsigned long flexbuffers::ReadSizedScalar<unsigned long, unsigned char, unsigned short, unsigned int, unsigned long>(unsigned char const*, unsigned char)
Line
Count
Source
145
5.28M
R ReadSizedScalar(const uint8_t* data, uint8_t byte_width) {
146
5.28M
  return byte_width < 4
147
5.28M
             ? (byte_width < 2
148
1.02M
                    ? static_cast<R>(flatbuffers::ReadScalar<T1>(data))
149
1.02M
                    : static_cast<R>(flatbuffers::ReadScalar<T2>(data)))
150
5.28M
             : (byte_width < 8
151
4.25M
                    ? static_cast<R>(flatbuffers::ReadScalar<T4>(data))
152
4.25M
                    : static_cast<R>(flatbuffers::ReadScalar<T8>(data)));
153
5.28M
}
long flexbuffers::ReadSizedScalar<long, signed char, short, int, long>(unsigned char const*, unsigned char)
Line
Count
Source
145
345k
R ReadSizedScalar(const uint8_t* data, uint8_t byte_width) {
146
345k
  return byte_width < 4
147
345k
             ? (byte_width < 2
148
29.0k
                    ? static_cast<R>(flatbuffers::ReadScalar<T1>(data))
149
29.0k
                    : static_cast<R>(flatbuffers::ReadScalar<T2>(data)))
150
345k
             : (byte_width < 8
151
316k
                    ? static_cast<R>(flatbuffers::ReadScalar<T4>(data))
152
316k
                    : static_cast<R>(flatbuffers::ReadScalar<T8>(data)));
153
345k
}
double flexbuffers::ReadSizedScalar<double, signed char, short, float, double>(unsigned char const*, unsigned char)
Line
Count
Source
145
728k
R ReadSizedScalar(const uint8_t* data, uint8_t byte_width) {
146
728k
  return byte_width < 4
147
728k
             ? (byte_width < 2
148
0
                    ? static_cast<R>(flatbuffers::ReadScalar<T1>(data))
149
0
                    : static_cast<R>(flatbuffers::ReadScalar<T2>(data)))
150
728k
             : (byte_width < 8
151
728k
                    ? static_cast<R>(flatbuffers::ReadScalar<T4>(data))
152
728k
                    : static_cast<R>(flatbuffers::ReadScalar<T8>(data)));
153
728k
}
154
155
345k
inline int64_t ReadInt64(const uint8_t* data, uint8_t byte_width) {
156
345k
  return ReadSizedScalar<int64_t, int8_t, int16_t, int32_t, int64_t>(
157
345k
      data, byte_width);
158
345k
}
159
160
5.28M
inline uint64_t ReadUInt64(const uint8_t* data, uint8_t byte_width) {
161
  // This is the "hottest" function (all offset lookups use this), so worth
162
  // optimizing if possible.
163
  // TODO: GCC apparently replaces memcpy by a rep movsb, but only if count is a
164
  // constant, which here it isn't. Test if memcpy is still faster than
165
  // the conditionals in ReadSizedScalar. Can also use inline asm.
166
167
  // clang-format off
168
  #if defined(_MSC_VER) && defined(_M_X64) && !defined(_M_ARM64EC)
169
  // This is 64-bit Windows only, __movsb does not work on 32-bit Windows.
170
    uint64_t u = 0;
171
    __movsb(reinterpret_cast<uint8_t *>(&u),
172
            reinterpret_cast<const uint8_t *>(data), byte_width);
173
    return flatbuffers::EndianScalar(u);
174
  #else
175
5.28M
    return ReadSizedScalar<uint64_t, uint8_t, uint16_t, uint32_t, uint64_t>(
176
5.28M
             data, byte_width);
177
5.28M
  #endif
178
  // clang-format on
179
5.28M
}
180
181
728k
inline double ReadDouble(const uint8_t* data, uint8_t byte_width) {
182
728k
  return ReadSizedScalar<double, quarter, half, float, double>(data,
183
728k
                                                               byte_width);
184
728k
}
185
186
1.69M
inline const uint8_t* Indirect(const uint8_t* offset, uint8_t byte_width) {
187
1.69M
  return offset - ReadUInt64(offset, byte_width);
188
1.69M
}
189
190
template <typename T>
191
0
const uint8_t* Indirect(const uint8_t* offset) {
192
0
  return offset - flatbuffers::ReadScalar<T>(offset);
193
0
}
Unexecuted instantiation: unsigned char const* flexbuffers::Indirect<unsigned char>(unsigned char const*)
Unexecuted instantiation: unsigned char const* flexbuffers::Indirect<unsigned short>(unsigned char const*)
Unexecuted instantiation: unsigned char const* flexbuffers::Indirect<unsigned int>(unsigned char const*)
Unexecuted instantiation: unsigned char const* flexbuffers::Indirect<unsigned long>(unsigned char const*)
194
195
3.70M
inline BitWidth WidthU(uint64_t u) {
196
3.70M
#define FLATBUFFERS_GET_FIELD_BIT_WIDTH(value, width)                   \
197
5.55M
  {                                                                     \
198
5.55M
    if (!((u) & ~((1ULL << (width)) - 1ULL))) return BIT_WIDTH_##width; \
199
5.55M
  }
200
3.70M
  FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 8);
201
1.84M
  FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 16);
202
12.4k
  FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 32);
203
1.37k
#undef FLATBUFFERS_GET_FIELD_BIT_WIDTH
204
1.37k
  return BIT_WIDTH_64;
205
12.4k
}
206
207
678k
inline BitWidth WidthI(int64_t i) {
208
678k
  auto u = static_cast<uint64_t>(i) << 1;
209
678k
  return WidthU(i >= 0 ? u : ~u);
210
678k
}
211
212
770k
inline BitWidth WidthF(double f) {
213
770k
  return static_cast<double>(static_cast<float>(f)) == f ? BIT_WIDTH_32
214
770k
                                                         : BIT_WIDTH_64;
215
770k
}
216
217
// Base class of all types below.
218
// Points into the data buffer and allows access to one type.
219
class Object {
220
 public:
221
  Object(const uint8_t* data, uint8_t byte_width)
222
2.59M
      : data_(data), byte_width_(byte_width) {}
223
224
 protected:
225
  const uint8_t* data_;
226
  uint8_t byte_width_;
227
};
228
229
// Object that has a size, obtained either from size prefix, or elsewhere.
230
class Sized : public Object {
231
 public:
232
  // Size prefix.
233
  Sized(const uint8_t* data, uint8_t byte_width)
234
2.59M
      : Object(data, byte_width), size_(read_size()) {}
235
  // Manual size.
236
  Sized(const uint8_t* data, uint8_t byte_width, size_t sz)
237
0
      : Object(data, byte_width), size_(sz) {}
238
7.28M
  size_t size() const { return size_; }
239
  // Access size stored in `byte_width_` bytes before data_ pointer.
240
2.59M
  size_t read_size() const {
241
2.59M
    return static_cast<size_t>(ReadUInt64(data_ - byte_width_, byte_width_));
242
2.59M
  }
243
244
 protected:
245
  size_t size_;
246
};
247
248
class String : public Sized {
249
 public:
250
  // Size prefix.
251
35.9k
  String(const uint8_t* data, uint8_t byte_width) : Sized(data, byte_width) {}
252
  // Manual size.
253
  String(const uint8_t* data, uint8_t byte_width, size_t sz)
254
0
      : Sized(data, byte_width, sz) {}
255
256
17.9k
  size_t length() const { return size(); }
257
35.9k
  const char* c_str() const { return reinterpret_cast<const char*>(data_); }
258
0
  std::string str() const { return std::string(c_str(), size()); }
259
260
0
  static String EmptyString() {
261
0
    static const char* empty_string = "";
262
0
    return String(reinterpret_cast<const uint8_t*>(empty_string), 1, 0);
263
0
  }
264
0
  bool IsTheEmptyString() const { return data_ == EmptyString().data_; }
265
};
266
267
class Blob : public Sized {
268
 public:
269
  Blob(const uint8_t* data_buf, uint8_t byte_width)
270
0
      : Sized(data_buf, byte_width) {}
271
272
0
  static Blob EmptyBlob() {
273
0
    static const uint8_t empty_blob[] = {0 /*len*/};
274
0
    return Blob(empty_blob + 1, 1);
275
0
  }
276
0
  bool IsTheEmptyBlob() const { return data_ == EmptyBlob().data_; }
277
0
  const uint8_t* data() const { return data_; }
278
};
279
280
class Vector : public Sized {
281
 public:
282
1.58M
  Vector(const uint8_t* data, uint8_t byte_width) : Sized(data, byte_width) {}
283
284
  Reference operator[](size_t i) const;
285
286
0
  static Vector EmptyVector() {
287
0
    static const uint8_t empty_vector[] = {0 /*len*/};
288
0
    return Vector(empty_vector + 1, 1);
289
0
  }
290
0
  bool IsTheEmptyVector() const { return data_ == EmptyVector().data_; }
291
};
292
293
class TypedVector : public Sized {
294
 public:
295
  TypedVector(const uint8_t* data, uint8_t byte_width, Type element_type)
296
125k
      : Sized(data, byte_width), type_(element_type) {}
297
298
  Reference operator[](size_t i) const;
299
300
0
  static TypedVector EmptyTypedVector() {
301
0
    static const uint8_t empty_typed_vector[] = {0 /*len*/};
302
0
    return TypedVector(empty_typed_vector + 1, 1, FBT_INT);
303
0
  }
304
0
  bool IsTheEmptyVector() const {
305
0
    return data_ == TypedVector::EmptyTypedVector().data_;
306
0
  }
307
308
0
  Type ElementType() { return type_; }
309
310
  friend Reference;
311
312
 private:
313
  Type type_;
314
315
  friend Map;
316
};
317
318
class FixedTypedVector : public Object {
319
 public:
320
  FixedTypedVector(const uint8_t* data, uint8_t byte_width, Type element_type,
321
                   uint8_t len)
322
0
      : Object(data, byte_width), type_(element_type), len_(len) {}
323
324
  Reference operator[](size_t i) const;
325
326
0
  static FixedTypedVector EmptyFixedTypedVector() {
327
0
    static const uint8_t fixed_empty_vector[] = {0 /* unused */};
328
0
    return FixedTypedVector(fixed_empty_vector, 1, FBT_INT, 0);
329
0
  }
330
0
  bool IsTheEmptyFixedTypedVector() const {
331
0
    return data_ == FixedTypedVector::EmptyFixedTypedVector().data_;
332
0
  }
333
334
0
  Type ElementType() const { return type_; }
335
0
  uint8_t size() const { return len_; }
336
337
 private:
338
  Type type_;
339
  uint8_t len_;
340
};
341
342
class Map : public Vector {
343
 public:
344
62.7k
  Map(const uint8_t* data, uint8_t byte_width) : Vector(data, byte_width) {}
345
346
  Reference operator[](const char* key) const;
347
  Reference operator[](const std::string& key) const;
348
349
62.7k
  Vector Values() const { return Vector(data_, byte_width_); }
350
351
62.7k
  TypedVector Keys() const {
352
62.7k
    const size_t num_prefixed_fields = 3;
353
62.7k
    auto keys_offset = data_ - byte_width_ * num_prefixed_fields;
354
62.7k
    return TypedVector(Indirect(keys_offset, byte_width_),
355
62.7k
                       static_cast<uint8_t>(
356
62.7k
                           ReadUInt64(keys_offset + byte_width_, byte_width_)),
357
62.7k
                       FBT_KEY);
358
62.7k
  }
359
360
0
  static Map EmptyMap() {
361
0
    static const uint8_t empty_map[] = {
362
0
        0 /*keys_len*/, 0 /*keys_offset*/, 1 /*keys_width*/, 0 /*len*/
363
0
    };
364
0
    return Map(empty_map + 4, 1);
365
0
  }
366
367
0
  bool IsTheEmptyMap() const { return data_ == EmptyMap().data_; }
368
};
369
370
inline void IndentString(std::string& s, int indent,
371
0
                         const char* indent_string) {
372
0
  for (int i = 0; i < indent; i++) s += indent_string;
373
0
}
374
375
template <typename T>
376
void AppendToString(std::string& s, T&& v, bool keys_quoted, bool indented,
377
                    int cur_indent, const char* indent_string,
378
700k
                    bool natural_utf8) {
379
700k
  s += "[";
380
700k
  s += indented ? "\n" : " ";
381
2.52M
  for (size_t i = 0; i < v.size(); i++) {
382
1.82M
    if (i) {
383
1.13M
      s += ",";
384
1.13M
      s += indented ? "\n" : " ";
385
1.13M
    }
386
1.82M
    if (indented) IndentString(s, cur_indent, indent_string);
387
1.82M
    v[i].ToString(true, keys_quoted, s, indented, cur_indent, indent_string,
388
1.82M
                  natural_utf8);
389
1.82M
  }
390
700k
  if (indented) {
391
0
    s += "\n";
392
0
    IndentString(s, cur_indent - 1, indent_string);
393
700k
  } else {
394
700k
    s += " ";
395
700k
  }
396
700k
  s += "]";
397
700k
}
void flexbuffers::AppendToString<flexbuffers::Vector>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, flexbuffers::Vector&&, bool, bool, int, char const*, bool)
Line
Count
Source
378
700k
                    bool natural_utf8) {
379
700k
  s += "[";
380
700k
  s += indented ? "\n" : " ";
381
2.52M
  for (size_t i = 0; i < v.size(); i++) {
382
1.82M
    if (i) {
383
1.13M
      s += ",";
384
1.13M
      s += indented ? "\n" : " ";
385
1.13M
    }
386
1.82M
    if (indented) IndentString(s, cur_indent, indent_string);
387
1.82M
    v[i].ToString(true, keys_quoted, s, indented, cur_indent, indent_string,
388
1.82M
                  natural_utf8);
389
1.82M
  }
390
700k
  if (indented) {
391
0
    s += "\n";
392
0
    IndentString(s, cur_indent - 1, indent_string);
393
700k
  } else {
394
700k
    s += " ";
395
700k
  }
396
700k
  s += "]";
397
700k
}
Unexecuted instantiation: void flexbuffers::AppendToString<flexbuffers::TypedVector>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, flexbuffers::TypedVector&&, bool, bool, int, char const*, bool)
Unexecuted instantiation: void flexbuffers::AppendToString<flexbuffers::FixedTypedVector>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, flexbuffers::FixedTypedVector&&, bool, bool, int, char const*, bool)
398
399
template <typename T>
400
void AppendToString(std::string& s, T&& v, bool keys_quoted) {
401
  AppendToString(s, v, keys_quoted);
402
}
403
404
class Reference {
405
 public:
406
  Reference()
407
11.8k
      : data_(nullptr), parent_width_(0), byte_width_(0), type_(FBT_NULL) {}
408
409
  Reference(const uint8_t* data, uint8_t parent_width, uint8_t byte_width,
410
            Type type)
411
135k
      : data_(data),
412
135k
        parent_width_(parent_width),
413
135k
        byte_width_(byte_width),
414
135k
        type_(type) {}
415
416
  Reference(const uint8_t* data, uint8_t parent_width, uint8_t packed_type)
417
3.71M
      : data_(data),
418
3.71M
        parent_width_(parent_width),
419
3.71M
        byte_width_(static_cast<uint8_t>(1 << (packed_type & 3))),
420
3.71M
        type_(static_cast<Type>(packed_type >> 2)) {}
421
422
0
  Type GetType() const { return type_; }
423
424
766k
  bool IsNull() const { return type_ == FBT_NULL; }
425
765k
  bool IsBool() const { return type_ == FBT_BOOL; }
426
1.84M
  bool IsInt() const { return type_ == FBT_INT || type_ == FBT_INDIRECT_INT; }
427
1.49M
  bool IsUInt() const {
428
1.49M
    return type_ == FBT_UINT || type_ == FBT_INDIRECT_UINT;
429
1.49M
  }
430
0
  bool IsIntOrUint() const { return IsInt() || IsUInt(); }
431
1.49M
  bool IsFloat() const {
432
1.49M
    return type_ == FBT_FLOAT || type_ == FBT_INDIRECT_FLOAT;
433
1.49M
  }
434
0
  bool IsNumeric() const { return IsIntOrUint() || IsFloat(); }
435
0
  bool IsString() const { return type_ == FBT_STRING; }
436
1.86M
  bool IsKey() const { return type_ == FBT_KEY; }
437
700k
  bool IsVector() const { return type_ == FBT_VECTOR || type_ == FBT_MAP; }
438
0
  bool IsUntypedVector() const { return type_ == FBT_VECTOR; }
439
0
  bool IsTypedVector() const { return flexbuffers::IsTypedVector(type_); }
440
0
  bool IsFixedTypedVector() const {
441
0
    return flexbuffers::IsFixedTypedVector(type_);
442
0
  }
443
0
  bool IsAnyVector() const {
444
0
    return (IsTypedVector() || IsFixedTypedVector() || IsVector());
445
0
  }
446
762k
  bool IsMap() const { return type_ == FBT_MAP; }
447
0
  bool IsBlob() const { return type_ == FBT_BLOB; }
448
2.56k
  bool AsBool() const {
449
2.56k
    return (type_ == FBT_BOOL ? ReadUInt64(data_, parent_width_)
450
2.56k
                              : AsUInt64()) != 0;
451
2.56k
  }
452
453
  // Reads any type as a int64_t. Never fails, does most sensible conversion.
454
  // Truncates floats, strings are attempted to be parsed for a number,
455
  // vectors/maps return their size. Returns 0 if all else fails.
456
345k
  int64_t AsInt64() const {
457
345k
    if (type_ == FBT_INT) {
458
      // A fast path for the common case.
459
345k
      return ReadInt64(data_, parent_width_);
460
345k
    } else
461
0
      switch (type_) {
462
0
        case FBT_INDIRECT_INT:
463
0
          return ReadInt64(Indirect(), byte_width_);
464
0
        case FBT_UINT:
465
0
          return ReadUInt64(data_, parent_width_);
466
0
        case FBT_INDIRECT_UINT:
467
0
          return ReadUInt64(Indirect(), byte_width_);
468
0
        case FBT_FLOAT:
469
0
          return static_cast<int64_t>(ReadDouble(data_, parent_width_));
470
0
        case FBT_INDIRECT_FLOAT:
471
0
          return static_cast<int64_t>(ReadDouble(Indirect(), byte_width_));
472
0
        case FBT_NULL:
473
0
          return 0;
474
0
        case FBT_STRING:
475
0
          return flatbuffers::StringToInt(AsString().c_str());
476
0
        case FBT_VECTOR:
477
0
          return static_cast<int64_t>(AsVector().size());
478
0
        case FBT_BOOL:
479
0
          return ReadInt64(data_, parent_width_);
480
0
        default:
481
          // Convert other things to int.
482
0
          return 0;
483
0
      }
484
345k
  }
485
486
  // TODO: could specialize these to not use AsInt64() if that saves
487
  // extension ops in generated code, and use a faster op than ReadInt64.
488
0
  int32_t AsInt32() const { return static_cast<int32_t>(AsInt64()); }
489
0
  int16_t AsInt16() const { return static_cast<int16_t>(AsInt64()); }
490
0
  int8_t AsInt8() const { return static_cast<int8_t>(AsInt64()); }
491
492
0
  uint64_t AsUInt64() const {
493
0
    if (type_ == FBT_UINT) {
494
      // A fast path for the common case.
495
0
      return ReadUInt64(data_, parent_width_);
496
0
    } else
497
0
      switch (type_) {
498
0
        case FBT_INDIRECT_UINT:
499
0
          return ReadUInt64(Indirect(), byte_width_);
500
0
        case FBT_INT:
501
0
          return ReadInt64(data_, parent_width_);
502
0
        case FBT_INDIRECT_INT:
503
0
          return ReadInt64(Indirect(), byte_width_);
504
0
        case FBT_FLOAT:
505
0
          return static_cast<uint64_t>(ReadDouble(data_, parent_width_));
506
0
        case FBT_INDIRECT_FLOAT:
507
0
          return static_cast<uint64_t>(ReadDouble(Indirect(), byte_width_));
508
0
        case FBT_NULL:
509
0
          return 0;
510
0
        case FBT_STRING:
511
0
          return flatbuffers::StringToUInt(AsString().c_str());
512
0
        case FBT_VECTOR:
513
0
          return static_cast<uint64_t>(AsVector().size());
514
0
        case FBT_BOOL:
515
0
          return ReadUInt64(data_, parent_width_);
516
0
        default:
517
          // Convert other things to uint.
518
0
          return 0;
519
0
      }
520
0
  }
521
522
0
  uint32_t AsUInt32() const { return static_cast<uint32_t>(AsUInt64()); }
523
0
  uint16_t AsUInt16() const { return static_cast<uint16_t>(AsUInt64()); }
524
0
  uint8_t AsUInt8() const { return static_cast<uint8_t>(AsUInt64()); }
525
526
728k
  double AsDouble() const {
527
728k
    if (type_ == FBT_FLOAT) {
528
      // A fast path for the common case.
529
728k
      return ReadDouble(data_, parent_width_);
530
728k
    } else
531
0
      switch (type_) {
532
0
        case FBT_INDIRECT_FLOAT:
533
0
          return ReadDouble(Indirect(), byte_width_);
534
0
        case FBT_INT:
535
0
          return static_cast<double>(ReadInt64(data_, parent_width_));
536
0
        case FBT_UINT:
537
0
          return static_cast<double>(ReadUInt64(data_, parent_width_));
538
0
        case FBT_INDIRECT_INT:
539
0
          return static_cast<double>(ReadInt64(Indirect(), byte_width_));
540
0
        case FBT_INDIRECT_UINT:
541
0
          return static_cast<double>(ReadUInt64(Indirect(), byte_width_));
542
0
        case FBT_NULL:
543
0
          return 0.0;
544
0
        case FBT_STRING: {
545
0
          double d;
546
0
          flatbuffers::StringToNumber(AsString().c_str(), &d);
547
0
          return d;
548
0
        }
549
0
        case FBT_VECTOR:
550
0
          return static_cast<double>(AsVector().size());
551
0
        case FBT_BOOL:
552
0
          return static_cast<double>(ReadUInt64(data_, parent_width_));
553
0
        default:
554
          // Convert strings and other things to float.
555
0
          return 0;
556
0
      }
557
728k
  }
558
559
0
  float AsFloat() const { return static_cast<float>(AsDouble()); }
560
561
48.7k
  const char* AsKey() const {
562
48.7k
    if (type_ == FBT_KEY || type_ == FBT_STRING) {
563
48.7k
      return reinterpret_cast<const char*>(Indirect());
564
48.7k
    } else {
565
0
      return "";
566
0
    }
567
48.7k
  }
568
569
  // This function returns the empty string if you try to read something that
570
  // is not a string or key.
571
0
  String AsString() const {
572
0
    if (type_ == FBT_STRING) {
573
0
      return String(Indirect(), byte_width_);
574
0
    } else if (type_ == FBT_KEY) {
575
0
      auto key = Indirect();
576
0
      return String(key, byte_width_,
577
0
                    strlen(reinterpret_cast<const char*>(key)));
578
0
    } else {
579
0
      return String::EmptyString();
580
0
    }
581
0
  }
582
583
  // Unlike AsString(), this will convert any type to a std::string.
584
0
  std::string ToString() const {
585
0
    std::string s;
586
0
    ToString(false, false, s);
587
0
    return s;
588
0
  }
589
590
  // Convert any type to a JSON-like string. strings_quoted determines if
591
  // string values at the top level receive "" quotes (inside other values
592
  // they always do). keys_quoted determines if keys are quoted, at any level.
593
35.6k
  void ToString(bool strings_quoted, bool keys_quoted, std::string& s) const {
594
35.6k
    ToString(strings_quoted, keys_quoted, s, false, 0, "", false);
595
35.6k
  }
596
597
  // This version additionally allow you to specify if you want indentation.
598
  void ToString(bool strings_quoted, bool keys_quoted, std::string& s,
599
                bool indented, int cur_indent, const char* indent_string,
600
1.88M
                bool natural_utf8 = false) const {
601
1.88M
    if (type_ == FBT_STRING) {
602
17.9k
      String str(Indirect(), byte_width_);
603
17.9k
      if (strings_quoted) {
604
17.9k
        flatbuffers::EscapeString(str.c_str(), str.length(), &s, true,
605
17.9k
                                  natural_utf8);
606
17.9k
      } else {
607
0
        s.append(str.c_str(), str.length());
608
0
      }
609
1.86M
    } else if (IsKey()) {
610
24.4k
      auto str = AsKey();
611
24.4k
      if (keys_quoted) {
612
3.37k
        flatbuffers::EscapeString(str, strlen(str), &s, true, natural_utf8);
613
21.0k
      } else {
614
21.0k
        s += str;
615
21.0k
      }
616
1.84M
    } else if (IsInt()) {
617
345k
      s += flatbuffers::NumToString(AsInt64());
618
1.49M
    } else if (IsUInt()) {
619
0
      s += flatbuffers::NumToString(AsUInt64());
620
1.49M
    } else if (IsFloat()) {
621
728k
      s += flatbuffers::NumToString(AsDouble());
622
766k
    } else if (IsNull()) {
623
1.54k
      s += "null";
624
765k
    } else if (IsBool()) {
625
2.56k
      s += AsBool() ? "true" : "false";
626
762k
    } else if (IsMap()) {
627
62.7k
      s += "{";
628
62.7k
      s += indented ? "\n" : " ";
629
62.7k
      auto m = AsMap();
630
62.7k
      auto keys = m.Keys();
631
62.7k
      auto vals = m.Values();
632
87.1k
      for (size_t i = 0; i < keys.size(); i++) {
633
24.4k
        bool kq = keys_quoted;
634
24.4k
        if (!kq) {
635
          // FlexBuffers keys may contain arbitrary characters, only allow
636
          // unquoted if it looks like an "identifier":
637
24.3k
          const char* p = keys[i].AsKey();
638
24.3k
          if (!flatbuffers::is_alpha(*p) && *p != '_') {
639
1.85k
            kq = true;
640
22.4k
          } else {
641
84.9k
            while (*++p) {
642
63.8k
              if (!flatbuffers::is_alnum(*p) && *p != '_') {
643
1.41k
                kq = true;
644
1.41k
                break;
645
1.41k
              }
646
63.8k
            }
647
22.4k
          }
648
24.3k
        }
649
24.4k
        if (indented) IndentString(s, cur_indent + 1, indent_string);
650
24.4k
        keys[i].ToString(true, kq, s);
651
24.4k
        s += ": ";
652
24.4k
        vals[i].ToString(true, keys_quoted, s, indented, cur_indent + 1,
653
24.4k
                         indent_string, natural_utf8);
654
24.4k
        if (i < keys.size() - 1) {
655
17.7k
          s += ",";
656
17.7k
          if (!indented) s += " ";
657
17.7k
        }
658
24.4k
        if (indented) s += "\n";
659
24.4k
      }
660
62.7k
      if (!indented) s += " ";
661
62.7k
      if (indented) IndentString(s, cur_indent, indent_string);
662
62.7k
      s += "}";
663
700k
    } else if (IsVector()) {
664
700k
      AppendToString<Vector>(s, AsVector(), keys_quoted, indented,
665
700k
                             cur_indent + 1, indent_string, natural_utf8);
666
700k
    } else if (IsTypedVector()) {
667
0
      AppendToString<TypedVector>(s, AsTypedVector(), keys_quoted, indented,
668
0
                                  cur_indent + 1, indent_string, natural_utf8);
669
0
    } else if (IsFixedTypedVector()) {
670
0
      AppendToString<FixedTypedVector>(s, AsFixedTypedVector(), keys_quoted,
671
0
                                       indented, cur_indent + 1, indent_string,
672
0
                                       natural_utf8);
673
0
    } else if (IsBlob()) {
674
0
      auto blob = AsBlob();
675
0
      flatbuffers::EscapeString(reinterpret_cast<const char*>(blob.data()),
676
0
                                blob.size(), &s, true, false);
677
0
    } else {
678
0
      s += "(?)";
679
0
    }
680
1.88M
  }
681
682
  // This function returns the empty blob if you try to read a not-blob.
683
  // Strings can be viewed as blobs too.
684
0
  Blob AsBlob() const {
685
0
    if (type_ == FBT_BLOB || type_ == FBT_STRING) {
686
0
      return Blob(Indirect(), byte_width_);
687
0
    } else {
688
0
      return Blob::EmptyBlob();
689
0
    }
690
0
  }
691
692
  // This function returns the empty vector if you try to read a not-vector.
693
  // Maps can be viewed as vectors too.
694
700k
  Vector AsVector() const {
695
700k
    if (type_ == FBT_VECTOR || type_ == FBT_MAP) {
696
700k
      return Vector(Indirect(), byte_width_);
697
700k
    } else {
698
0
      return Vector::EmptyVector();
699
0
    }
700
700k
  }
701
702
0
  TypedVector AsTypedVector() const {
703
0
    if (IsTypedVector()) {
704
0
      auto tv =
705
0
          TypedVector(Indirect(), byte_width_, ToTypedVectorElementType(type_));
706
0
      if (tv.type_ == FBT_STRING) {
707
        // These can't be accessed as strings, since we don't know the bit-width
708
        // of the size field, see the declaration of
709
        // FBT_VECTOR_STRING_DEPRECATED above for details.
710
        // We change the type here to be keys, which are a subtype of strings,
711
        // and will ignore the size field. This will truncate strings with
712
        // embedded nulls.
713
0
        tv.type_ = FBT_KEY;
714
0
      }
715
0
      return tv;
716
0
    } else {
717
0
      return TypedVector::EmptyTypedVector();
718
0
    }
719
0
  }
720
721
0
  FixedTypedVector AsFixedTypedVector() const {
722
0
    if (IsFixedTypedVector()) {
723
0
      uint8_t len = 0;
724
0
      auto vtype = ToFixedTypedVectorElementType(type_, &len);
725
0
      return FixedTypedVector(Indirect(), byte_width_, vtype, len);
726
0
    } else {
727
0
      return FixedTypedVector::EmptyFixedTypedVector();
728
0
    }
729
0
  }
730
731
62.7k
  Map AsMap() const {
732
62.7k
    if (type_ == FBT_MAP) {
733
62.7k
      return Map(Indirect(), byte_width_);
734
62.7k
    } else {
735
0
      return Map::EmptyMap();
736
0
    }
737
62.7k
  }
738
739
  template <typename T>
740
  T As() const;
741
742
  // Experimental: Mutation functions.
743
  // These allow scalars in an already created buffer to be updated in-place.
744
  // Since by default scalars are stored in the smallest possible space,
745
  // the new value may not fit, in which case these functions return false.
746
  // To avoid this, you can construct the values you intend to mutate using
747
  // Builder::ForceMinimumBitWidth.
748
0
  bool MutateInt(int64_t i) {
749
0
    if (type_ == FBT_INT) {
750
0
      return Mutate(data_, i, parent_width_, WidthI(i));
751
0
    } else if (type_ == FBT_INDIRECT_INT) {
752
0
      return Mutate(Indirect(), i, byte_width_, WidthI(i));
753
0
    } else if (type_ == FBT_UINT) {
754
0
      auto u = static_cast<uint64_t>(i);
755
0
      return Mutate(data_, u, parent_width_, WidthU(u));
756
0
    } else if (type_ == FBT_INDIRECT_UINT) {
757
0
      auto u = static_cast<uint64_t>(i);
758
0
      return Mutate(Indirect(), u, byte_width_, WidthU(u));
759
0
    } else {
760
0
      return false;
761
0
    }
762
0
  }
763
764
0
  bool MutateBool(bool b) {
765
0
    return type_ == FBT_BOOL && Mutate(data_, b, parent_width_, BIT_WIDTH_8);
766
0
  }
767
768
0
  bool MutateUInt(uint64_t u) {
769
0
    if (type_ == FBT_UINT) {
770
0
      return Mutate(data_, u, parent_width_, WidthU(u));
771
0
    } else if (type_ == FBT_INDIRECT_UINT) {
772
0
      return Mutate(Indirect(), u, byte_width_, WidthU(u));
773
0
    } else if (type_ == FBT_INT) {
774
0
      auto i = static_cast<int64_t>(u);
775
0
      return Mutate(data_, i, parent_width_, WidthI(i));
776
0
    } else if (type_ == FBT_INDIRECT_INT) {
777
0
      auto i = static_cast<int64_t>(u);
778
0
      return Mutate(Indirect(), i, byte_width_, WidthI(i));
779
0
    } else {
780
0
      return false;
781
0
    }
782
0
  }
783
784
0
  bool MutateFloat(float f) {
785
0
    if (type_ == FBT_FLOAT) {
786
0
      return MutateF(data_, f, parent_width_, BIT_WIDTH_32);
787
0
    } else if (type_ == FBT_INDIRECT_FLOAT) {
788
0
      return MutateF(Indirect(), f, byte_width_, BIT_WIDTH_32);
789
0
    } else {
790
0
      return false;
791
0
    }
792
0
  }
793
794
0
  bool MutateFloat(double d) {
795
0
    if (type_ == FBT_FLOAT) {
796
0
      return MutateF(data_, d, parent_width_, WidthF(d));
797
0
    } else if (type_ == FBT_INDIRECT_FLOAT) {
798
0
      return MutateF(Indirect(), d, byte_width_, WidthF(d));
799
0
    } else {
800
0
      return false;
801
0
    }
802
0
  }
803
804
0
  bool MutateString(const char* str, size_t len) {
805
0
    auto s = AsString();
806
0
    if (s.IsTheEmptyString()) return false;
807
0
    // This is very strict, could allow shorter strings, but that creates
808
0
    // garbage.
809
0
    if (s.length() != len) return false;
810
0
    memcpy(const_cast<char*>(s.c_str()), str, len);
811
0
    return true;
812
0
  }
813
0
  bool MutateString(const char* str) { return MutateString(str, strlen(str)); }
814
0
  bool MutateString(const std::string& str) {
815
0
    return MutateString(str.data(), str.length());
816
0
  }
817
818
 private:
819
1.63M
  const uint8_t* Indirect() const {
820
1.63M
    return flexbuffers::Indirect(data_, parent_width_);
821
1.63M
  }
822
823
  template <typename T>
824
  bool Mutate(const uint8_t* dest, T t, size_t byte_width,
825
0
              BitWidth value_width) {
826
0
    auto fits = static_cast<size_t>(static_cast<size_t>(1U) << value_width) <=
827
0
                byte_width;
828
0
    if (fits) {
829
0
      t = flatbuffers::EndianScalar(t);
830
0
      memcpy(const_cast<uint8_t*>(dest), &t, byte_width);
831
0
    }
832
0
    return fits;
833
0
  }
Unexecuted instantiation: bool flexbuffers::Reference::Mutate<long>(unsigned char const*, long, unsigned long, flexbuffers::BitWidth)
Unexecuted instantiation: bool flexbuffers::Reference::Mutate<unsigned long>(unsigned char const*, unsigned long, unsigned long, flexbuffers::BitWidth)
Unexecuted instantiation: bool flexbuffers::Reference::Mutate<bool>(unsigned char const*, bool, unsigned long, flexbuffers::BitWidth)
Unexecuted instantiation: bool flexbuffers::Reference::Mutate<double>(unsigned char const*, double, unsigned long, flexbuffers::BitWidth)
Unexecuted instantiation: bool flexbuffers::Reference::Mutate<float>(unsigned char const*, float, unsigned long, flexbuffers::BitWidth)
834
835
  template <typename T>
836
  bool MutateF(const uint8_t* dest, T t, size_t byte_width,
837
0
               BitWidth value_width) {
838
0
    if (byte_width == sizeof(double))
839
0
      return Mutate(dest, static_cast<double>(t), byte_width, value_width);
840
0
    if (byte_width == sizeof(float))
841
0
      return Mutate(dest, static_cast<float>(t), byte_width, value_width);
842
0
    FLATBUFFERS_ASSERT(false);
843
0
    return false;
844
0
  }
Unexecuted instantiation: bool flexbuffers::Reference::MutateF<float>(unsigned char const*, float, unsigned long, flexbuffers::BitWidth)
Unexecuted instantiation: bool flexbuffers::Reference::MutateF<double>(unsigned char const*, double, unsigned long, flexbuffers::BitWidth)
845
846
  friend class Verifier;
847
848
  const uint8_t* data_;
849
  uint8_t parent_width_;
850
  uint8_t byte_width_;
851
  Type type_;
852
};
853
854
// Template specialization for As().
855
template <>
856
0
inline bool Reference::As<bool>() const {
857
0
  return AsBool();
858
0
}
859
860
template <>
861
0
inline int8_t Reference::As<int8_t>() const {
862
0
  return AsInt8();
863
0
}
864
template <>
865
0
inline int16_t Reference::As<int16_t>() const {
866
0
  return AsInt16();
867
0
}
868
template <>
869
0
inline int32_t Reference::As<int32_t>() const {
870
0
  return AsInt32();
871
0
}
872
template <>
873
0
inline int64_t Reference::As<int64_t>() const {
874
0
  return AsInt64();
875
0
}
876
877
template <>
878
0
inline uint8_t Reference::As<uint8_t>() const {
879
0
  return AsUInt8();
880
0
}
881
template <>
882
0
inline uint16_t Reference::As<uint16_t>() const {
883
0
  return AsUInt16();
884
0
}
885
template <>
886
0
inline uint32_t Reference::As<uint32_t>() const {
887
0
  return AsUInt32();
888
0
}
889
template <>
890
0
inline uint64_t Reference::As<uint64_t>() const {
891
0
  return AsUInt64();
892
0
}
893
894
template <>
895
0
inline double Reference::As<double>() const {
896
0
  return AsDouble();
897
0
}
898
template <>
899
0
inline float Reference::As<float>() const {
900
0
  return AsFloat();
901
0
}
902
903
template <>
904
0
inline String Reference::As<String>() const {
905
0
  return AsString();
906
0
}
907
template <>
908
0
inline std::string Reference::As<std::string>() const {
909
0
  return AsString().str();
910
0
}
911
912
template <>
913
0
inline Blob Reference::As<Blob>() const {
914
0
  return AsBlob();
915
0
}
916
template <>
917
0
inline Vector Reference::As<Vector>() const {
918
0
  return AsVector();
919
0
}
920
template <>
921
0
inline TypedVector Reference::As<TypedVector>() const {
922
0
  return AsTypedVector();
923
0
}
924
template <>
925
0
inline FixedTypedVector Reference::As<FixedTypedVector>() const {
926
0
  return AsFixedTypedVector();
927
0
}
928
template <>
929
0
inline Map Reference::As<Map>() const {
930
0
  return AsMap();
931
0
}
932
933
2.27M
inline uint8_t PackedType(BitWidth bit_width, Type type) {
934
2.27M
  return static_cast<uint8_t>(bit_width | (type << 2));
935
2.27M
}
936
937
0
inline uint8_t NullPackedType() { return PackedType(BIT_WIDTH_8, FBT_NULL); }
938
939
// Vector accessors.
940
// Note: if you try to access outside of bounds, you get a Null value back
941
// instead. Normally this would be an assert, but since this is "dynamically
942
// typed" data, you may not want that (someone sends you a 2d vector and you
943
// wanted 3d).
944
// The Null converts seamlessly into a default value for any other type.
945
// TODO(wvo): Could introduce an #ifdef that makes this into an assert?
946
3.69M
inline Reference Vector::operator[](size_t i) const {
947
3.69M
  auto len = size();
948
3.69M
  if (i >= len) return Reference(nullptr, 1, NullPackedType());
949
3.69M
  auto packed_type = (data_ + len * byte_width_)[i];
950
3.69M
  auto elem = data_ + i * byte_width_;
951
3.69M
  return Reference(elem, byte_width_, packed_type);
952
3.69M
}
953
954
73.1k
inline Reference TypedVector::operator[](size_t i) const {
955
73.1k
  auto len = size();
956
73.1k
  if (i >= len) return Reference(nullptr, 1, NullPackedType());
957
73.1k
  auto elem = data_ + i * byte_width_;
958
73.1k
  return Reference(elem, byte_width_, 1, type_);
959
73.1k
}
960
961
0
inline Reference FixedTypedVector::operator[](size_t i) const {
962
0
  if (i >= len_) return Reference(nullptr, 1, NullPackedType());
963
0
  auto elem = data_ + i * byte_width_;
964
0
  return Reference(elem, byte_width_, 1, type_);
965
0
}
966
967
template <typename T>
968
0
int KeyCompare(const void* key, const void* elem) {
969
0
  auto str_elem = reinterpret_cast<const char*>(
970
0
      Indirect<T>(reinterpret_cast<const uint8_t*>(elem)));
971
0
  auto skey = reinterpret_cast<const char*>(key);
972
0
  return strcmp(skey, str_elem);
973
0
}
Unexecuted instantiation: int flexbuffers::KeyCompare<unsigned char>(void const*, void const*)
Unexecuted instantiation: int flexbuffers::KeyCompare<unsigned short>(void const*, void const*)
Unexecuted instantiation: int flexbuffers::KeyCompare<unsigned int>(void const*, void const*)
Unexecuted instantiation: int flexbuffers::KeyCompare<unsigned long>(void const*, void const*)
974
975
0
inline Reference Map::operator[](const char* key) const {
976
0
  auto keys = Keys();
977
0
  // We can't pass keys.byte_width_ to the comparison function, so we have
978
0
  // to pick the right one ahead of time.
979
0
  int (*comp)(const void*, const void*) = nullptr;
980
0
  switch (keys.byte_width_) {
981
0
    case 1:
982
0
      comp = KeyCompare<uint8_t>;
983
0
      break;
984
0
    case 2:
985
0
      comp = KeyCompare<uint16_t>;
986
0
      break;
987
0
    case 4:
988
0
      comp = KeyCompare<uint32_t>;
989
0
      break;
990
0
    case 8:
991
0
      comp = KeyCompare<uint64_t>;
992
0
      break;
993
0
    default:
994
0
      FLATBUFFERS_ASSERT(false);
995
0
      return Reference();
996
0
  }
997
0
  auto res = std::bsearch(key, keys.data_, keys.size(), keys.byte_width_, comp);
998
0
  if (!res) return Reference(nullptr, 1, NullPackedType());
999
0
  auto i = (reinterpret_cast<uint8_t*>(res) - keys.data_) / keys.byte_width_;
1000
0
  return (*static_cast<const Vector*>(this))[i];
1001
0
}
1002
1003
0
inline Reference Map::operator[](const std::string& key) const {
1004
0
  return (*this)[key.c_str()];
1005
0
}
1006
1007
11.2k
inline Reference GetRoot(const uint8_t* buffer, size_t size) {
1008
  // See Finish() below for the serialization counterpart of this.
1009
  // The root starts at the end of the buffer, so we parse backwards from there.
1010
11.2k
  auto end = buffer + size;
1011
11.2k
  auto byte_width = *--end;
1012
11.2k
  auto packed_type = *--end;
1013
11.2k
  end -= byte_width;  // The root data item.
1014
11.2k
  return Reference(end, byte_width, packed_type);
1015
11.2k
}
1016
1017
0
inline Reference GetRoot(const std::vector<uint8_t>& buffer) {
1018
0
  return GetRoot(buffer.data(), buffer.size());
1019
0
}
1020
1021
// Flags that configure how the Builder behaves.
1022
// The "Share" flags determine if the Builder automatically tries to pool
1023
// this type. Pooling can reduce the size of serialized data if there are
1024
// multiple maps of the same kind, at the expense of slightly slower
1025
// serialization (the cost of lookups) and more memory use (std::set).
1026
// By default this is on for keys, but off for strings.
1027
// Turn keys off if you have e.g. only one map.
1028
// Turn strings on if you expect many non-unique string values.
1029
// Additionally, sharing key vectors can save space if you have maps with
1030
// identical field populations.
1031
enum BuilderFlag {
1032
  BUILDER_FLAG_NONE = 0,
1033
  BUILDER_FLAG_SHARE_KEYS = 1,
1034
  BUILDER_FLAG_SHARE_STRINGS = 2,
1035
  BUILDER_FLAG_SHARE_KEYS_AND_STRINGS = 3,
1036
  BUILDER_FLAG_SHARE_KEY_VECTORS = 4,
1037
  BUILDER_FLAG_SHARE_ALL = 7,
1038
};
1039
1040
class Builder FLATBUFFERS_FINAL_CLASS {
1041
 public:
1042
  Builder(size_t initial_size = 256,
1043
          BuilderFlag flags = BUILDER_FLAG_SHARE_KEYS)
1044
30.2k
      : buf_(initial_size),
1045
30.2k
        finished_(false),
1046
30.2k
        has_duplicate_keys_(false),
1047
30.2k
        flags_(flags),
1048
30.2k
        force_min_bit_width_(BIT_WIDTH_8),
1049
30.2k
        key_pool(KeyOffsetCompare(buf_)),
1050
30.2k
        string_pool(StringOffsetCompare(buf_)) {
1051
30.2k
    buf_.clear();
1052
30.2k
  }
1053
1054
#ifdef FLATBUFFERS_DEFAULT_DECLARATION
1055
  Builder(Builder&&) = default;
1056
  Builder& operator=(Builder&&) = default;
1057
#endif
1058
1059
  /// @brief Get the serialized buffer (after you call `Finish()`).
1060
  /// @return Returns a vector owned by this class.
1061
14.5k
  const std::vector<uint8_t>& GetBuffer() const {
1062
14.5k
    Finished();
1063
14.5k
    return buf_;
1064
14.5k
  }
1065
1066
  // Size of the buffer. Does not include unfinished values.
1067
14.5k
  size_t GetSize() const { return buf_.size(); }
1068
1069
  // Reset all state so we can re-use the buffer.
1070
0
  void Clear() {
1071
0
    buf_.clear();
1072
0
    stack_.clear();
1073
0
    finished_ = false;
1074
0
    // flags_ remains as-is;
1075
0
    force_min_bit_width_ = BIT_WIDTH_8;
1076
0
    key_pool.clear();
1077
0
    string_pool.clear();
1078
0
  }
1079
1080
  // All value constructing functions below have two versions: one that
1081
  // takes a key (for placement inside a map) and one that doesn't (for inside
1082
  // vectors and elsewhere).
1083
1084
1.62k
  void Null() { stack_.push_back(Value()); }
1085
0
  void Null(const char* key) {
1086
0
    Key(key);
1087
0
    Null();
1088
0
  }
1089
1090
678k
  void Int(int64_t i) { stack_.push_back(Value(i, FBT_INT, WidthI(i))); }
1091
0
  void Int(const char* key, int64_t i) {
1092
0
    Key(key);
1093
0
    Int(i);
1094
0
  }
1095
1096
0
  void UInt(uint64_t u) { stack_.push_back(Value(u, FBT_UINT, WidthU(u))); }
1097
0
  void UInt(const char* key, uint64_t u) {
1098
0
    Key(key);
1099
0
    UInt(u);
1100
0
  }
1101
1102
0
  void Float(float f) { stack_.push_back(Value(f)); }
1103
0
  void Float(const char* key, float f) {
1104
0
    Key(key);
1105
0
    Float(f);
1106
0
  }
1107
1108
770k
  void Double(double f) { stack_.push_back(Value(f)); }
1109
0
  void Double(const char* key, double d) {
1110
0
    Key(key);
1111
0
    Double(d);
1112
0
  }
1113
1114
2.68k
  void Bool(bool b) { stack_.push_back(Value(b)); }
1115
0
  void Bool(const char* key, bool b) {
1116
0
    Key(key);
1117
0
    Bool(b);
1118
0
  }
1119
1120
0
  void IndirectInt(int64_t i) { PushIndirect(i, FBT_INDIRECT_INT, WidthI(i)); }
1121
0
  void IndirectInt(const char* key, int64_t i) {
1122
0
    Key(key);
1123
0
    IndirectInt(i);
1124
0
  }
1125
1126
0
  void IndirectUInt(uint64_t u) {
1127
0
    PushIndirect(u, FBT_INDIRECT_UINT, WidthU(u));
1128
0
  }
1129
0
  void IndirectUInt(const char* key, uint64_t u) {
1130
0
    Key(key);
1131
0
    IndirectUInt(u);
1132
0
  }
1133
1134
0
  void IndirectFloat(float f) {
1135
0
    PushIndirect(f, FBT_INDIRECT_FLOAT, BIT_WIDTH_32);
1136
0
  }
1137
0
  void IndirectFloat(const char* key, float f) {
1138
0
    Key(key);
1139
0
    IndirectFloat(f);
1140
0
  }
1141
1142
0
  void IndirectDouble(double f) {
1143
0
    PushIndirect(f, FBT_INDIRECT_FLOAT, WidthF(f));
1144
0
  }
1145
0
  void IndirectDouble(const char* key, double d) {
1146
0
    Key(key);
1147
0
    IndirectDouble(d);
1148
0
  }
1149
1150
284k
  size_t Key(const char* str, size_t len) {
1151
284k
    auto sloc = buf_.size();
1152
284k
    WriteBytes(str, len + 1);
1153
284k
    if (flags_ & BUILDER_FLAG_SHARE_KEYS) {
1154
284k
      auto it = key_pool.find(sloc);
1155
284k
      if (it != key_pool.end()) {
1156
        // Already in the buffer. Remove key we just serialized, and use
1157
        // existing offset instead.
1158
211k
        buf_.resize(sloc);
1159
211k
        sloc = *it;
1160
211k
      } else {
1161
72.9k
        key_pool.insert(sloc);
1162
72.9k
      }
1163
284k
    }
1164
284k
    stack_.push_back(Value(static_cast<uint64_t>(sloc), FBT_KEY, BIT_WIDTH_8));
1165
284k
    return sloc;
1166
284k
  }
1167
1168
0
  size_t Key(const char* str) { return Key(str, strlen(str)); }
1169
284k
  size_t Key(const std::string& str) { return Key(str.c_str(), str.size()); }
1170
1171
23.9k
  size_t String(const char* str, size_t len) {
1172
23.9k
    auto reset_to = buf_.size();
1173
23.9k
    auto sloc = CreateBlob(str, len, 1, FBT_STRING);
1174
23.9k
    if (flags_ & BUILDER_FLAG_SHARE_STRINGS) {
1175
23.9k
      StringOffset so(sloc, len);
1176
23.9k
      auto it = string_pool.find(so);
1177
23.9k
      if (it != string_pool.end()) {
1178
        // Already in the buffer. Remove string we just serialized, and use
1179
        // existing offset instead.
1180
11.5k
        buf_.resize(reset_to);
1181
11.5k
        sloc = it->first;
1182
11.5k
        stack_.back().u_ = sloc;
1183
12.3k
      } else {
1184
12.3k
        string_pool.insert(so);
1185
12.3k
      }
1186
23.9k
    }
1187
23.9k
    return sloc;
1188
23.9k
  }
1189
0
  size_t String(const char* str) { return String(str, strlen(str)); }
1190
23.9k
  size_t String(const std::string& str) {
1191
23.9k
    return String(str.c_str(), str.size());
1192
23.9k
  }
1193
0
  void String(const flexbuffers::String& str) {
1194
0
    String(str.c_str(), str.length());
1195
0
  }
1196
1197
0
  void String(const char* key, const char* str) {
1198
0
    Key(key);
1199
0
    String(str);
1200
0
  }
1201
0
  void String(const char* key, const std::string& str) {
1202
0
    Key(key);
1203
0
    String(str);
1204
0
  }
1205
0
  void String(const char* key, const flexbuffers::String& str) {
1206
0
    Key(key);
1207
0
    String(str);
1208
0
  }
1209
1210
0
  size_t AlignedBlob(const void* data, size_t len, BitWidth alignment) {
1211
0
    // The requested alignment must not be smaller than the one required to
1212
0
    // store the length.
1213
0
    return CreateAlignedBlob(data, len, 0, FBT_BLOB,
1214
0
                             std::max(alignment, WidthU(len)));
1215
0
  }
1216
0
  size_t AlignedBlob(const std::vector<uint8_t>& v, BitWidth alignment) {
1217
0
    return AlignedBlob(v.data(), v.size(), alignment);
1218
0
  }
1219
0
  size_t Blob(const void* data, size_t len) {
1220
0
    return CreateBlob(data, len, 0, FBT_BLOB);
1221
0
  }
1222
0
  size_t Blob(const std::vector<uint8_t>& v) {
1223
0
    return Blob(v.data(), v.size());
1224
0
  }
1225
1226
0
  void Blob(const char* key, const void* data, size_t len) {
1227
0
    Key(key);
1228
0
    Blob(data, len);
1229
0
  }
1230
0
  void Blob(const char* key, const std::vector<uint8_t>& v) {
1231
0
    Key(key);
1232
0
    Blob(v);
1233
0
  }
1234
1235
  // TODO(wvo): support all the FlexBuffer types (like flexbuffers::String),
1236
  // e.g. Vector etc. Also in overloaded versions.
1237
  // Also some FlatBuffers types?
1238
1239
742k
  size_t StartVector() { return stack_.size(); }
1240
0
  size_t StartVector(const char* key) {
1241
0
    Key(key);
1242
0
    return stack_.size();
1243
0
  }
1244
77.5k
  size_t StartMap() { return stack_.size(); }
1245
0
  size_t StartMap(const char* key) {
1246
0
    Key(key);
1247
0
    return stack_.size();
1248
0
  }
1249
1250
  // TODO(wvo): allow this to specify an alignment greater than the natural
1251
  // alignment.
1252
742k
  size_t EndVector(size_t start, bool typed, bool fixed) {
1253
742k
    auto vec = CreateVector(start, stack_.size() - start, 1, typed, fixed);
1254
    // Remove temp elements and return vector.
1255
742k
    stack_.resize(start);
1256
742k
    stack_.push_back(vec);
1257
742k
    return static_cast<size_t>(vec.u_);
1258
742k
  }
1259
1260
76.4k
  size_t EndMap(size_t start) {
1261
    // We should have interleaved keys and values on the stack.
1262
76.4k
    auto len = MapElementCount(start);
1263
    // Make sure keys are all strings:
1264
355k
    for (auto key = start; key < stack_.size(); key += 2) {
1265
278k
      FLATBUFFERS_ASSERT(stack_[key].type_ == FBT_KEY);
1266
278k
    }
1267
    // Now sort values, so later we can do a binary search lookup.
1268
    // We want to sort 2 array elements at a time.
1269
76.4k
    struct TwoValue {
1270
76.4k
      Value key;
1271
76.4k
      Value val;
1272
76.4k
    };
1273
    // TODO(wvo): strict aliasing?
1274
    // TODO(wvo): allow the caller to indicate the data is already sorted
1275
    // for maximum efficiency? With an assert to check sortedness to make sure
1276
    // we're not breaking binary search.
1277
    // Or, we can track if the map is sorted as keys are added which would be
1278
    // be quite cheap (cheaper than checking it here), so we can skip this
1279
    // step automatically when appliccable, and encourage people to write in
1280
    // sorted fashion.
1281
    // std::sort is typically already a lot faster on sorted data though.
1282
76.4k
    auto dict = reinterpret_cast<TwoValue*>(stack_.data() + start);
1283
76.4k
    std::sort(dict, dict + len,
1284
4.02M
              [&](const TwoValue& a, const TwoValue& b) -> bool {
1285
4.02M
                auto as = reinterpret_cast<const char*>(buf_.data() + a.key.u_);
1286
4.02M
                auto bs = reinterpret_cast<const char*>(buf_.data() + b.key.u_);
1287
4.02M
                auto comp = strcmp(as, bs);
1288
                // We want to disallow duplicate keys, since this results in a
1289
                // map where values cannot be found.
1290
                // But we can't assert here (since we don't want to fail on
1291
                // random JSON input) or have an error mechanism.
1292
                // Instead, we set has_duplicate_keys_ in the builder to
1293
                // signal this.
1294
                // TODO: Have to check for pointer equality, as some sort
1295
                // implementation apparently call this function with the same
1296
                // element?? Why?
1297
4.02M
                if (!comp && &a != &b) has_duplicate_keys_ = true;
1298
4.02M
                return comp < 0;
1299
4.02M
              });
1300
    // First create a vector out of all keys.
1301
    // TODO(wvo): if kBuilderFlagShareKeyVectors is true, see if we can share
1302
    // the first vector.
1303
76.4k
    auto keys = CreateVector(start, len, 2, true, false);
1304
76.4k
    auto vec = CreateVector(start + 1, len, 2, false, false, &keys);
1305
    // Remove temp elements and return map.
1306
76.4k
    stack_.resize(start);
1307
76.4k
    stack_.push_back(vec);
1308
76.4k
    return static_cast<size_t>(vec.u_);
1309
76.4k
  }
1310
1311
  // Call this after EndMap to see if the map had any duplicate keys.
1312
  // Any map with such keys won't be able to retrieve all values.
1313
76.4k
  bool HasDuplicateKeys() const { return has_duplicate_keys_; }
1314
1315
  template <typename F>
1316
  size_t Vector(F f) {
1317
    auto start = StartVector();
1318
    f();
1319
    return EndVector(start, false, false);
1320
  }
1321
  template <typename F, typename T>
1322
  size_t Vector(F f, T& state) {
1323
    auto start = StartVector();
1324
    f(state);
1325
    return EndVector(start, false, false);
1326
  }
1327
  template <typename F>
1328
  size_t Vector(const char* key, F f) {
1329
    auto start = StartVector(key);
1330
    f();
1331
    return EndVector(start, false, false);
1332
  }
1333
  template <typename F, typename T>
1334
  size_t Vector(const char* key, F f, T& state) {
1335
    auto start = StartVector(key);
1336
    f(state);
1337
    return EndVector(start, false, false);
1338
  }
1339
1340
  template <typename T>
1341
  void Vector(const T* elems, size_t len) {
1342
    if (flatbuffers::is_scalar<T>::value) {
1343
      // This path should be a lot quicker and use less space.
1344
      ScalarVector(elems, len, false);
1345
    } else {
1346
      auto start = StartVector();
1347
      for (size_t i = 0; i < len; i++) Add(elems[i]);
1348
      EndVector(start, false, false);
1349
    }
1350
  }
1351
  template <typename T>
1352
  void Vector(const char* key, const T* elems, size_t len) {
1353
    Key(key);
1354
    Vector(elems, len);
1355
  }
1356
  template <typename T>
1357
  void Vector(const std::vector<T>& vec) {
1358
    Vector(vec.data(), vec.size());
1359
  }
1360
1361
  template <typename F>
1362
  size_t TypedVector(F f) {
1363
    auto start = StartVector();
1364
    f();
1365
    return EndVector(start, true, false);
1366
  }
1367
  template <typename F, typename T>
1368
  size_t TypedVector(F f, T& state) {
1369
    auto start = StartVector();
1370
    f(state);
1371
    return EndVector(start, true, false);
1372
  }
1373
  template <typename F>
1374
  size_t TypedVector(const char* key, F f) {
1375
    auto start = StartVector(key);
1376
    f();
1377
    return EndVector(start, true, false);
1378
  }
1379
  template <typename F, typename T>
1380
  size_t TypedVector(const char* key, F f, T& state) {
1381
    auto start = StartVector(key);
1382
    f(state);
1383
    return EndVector(start, true, false);
1384
  }
1385
1386
  template <typename T>
1387
  size_t FixedTypedVector(const T* elems, size_t len) {
1388
    // We only support a few fixed vector lengths. Anything bigger use a
1389
    // regular typed vector.
1390
    FLATBUFFERS_ASSERT(len >= 2 && len <= 4);
1391
    // And only scalar values.
1392
    static_assert(flatbuffers::is_scalar<T>::value, "Unrelated types");
1393
    return ScalarVector(elems, len, true);
1394
  }
1395
1396
  template <typename T>
1397
  size_t FixedTypedVector(const char* key, const T* elems, size_t len) {
1398
    Key(key);
1399
    return FixedTypedVector(elems, len);
1400
  }
1401
1402
  template <typename F>
1403
  size_t Map(F f) {
1404
    auto start = StartMap();
1405
    f();
1406
    return EndMap(start);
1407
  }
1408
  template <typename F, typename T>
1409
  size_t Map(F f, T& state) {
1410
    auto start = StartMap();
1411
    f(state);
1412
    return EndMap(start);
1413
  }
1414
  template <typename F>
1415
  size_t Map(const char* key, F f) {
1416
    auto start = StartMap(key);
1417
    f();
1418
    return EndMap(start);
1419
  }
1420
  template <typename F, typename T>
1421
  size_t Map(const char* key, F f, T& state) {
1422
    auto start = StartMap(key);
1423
    f(state);
1424
    return EndMap(start);
1425
  }
1426
  template <typename T>
1427
  void Map(const std::map<std::string, T>& map) {
1428
    auto start = StartMap();
1429
    for (auto it = map.begin(); it != map.end(); ++it)
1430
      Add(it->first.c_str(), it->second);
1431
    EndMap(start);
1432
  }
1433
1434
76.4k
  size_t MapElementCount(size_t start) {
1435
    // Make sure it is an even number:
1436
76.4k
    auto len = stack_.size() - start;
1437
76.4k
    FLATBUFFERS_ASSERT(!(len & 1));
1438
76.4k
    len /= 2;
1439
76.4k
    return len;
1440
76.4k
  }
1441
1442
  // If you wish to share a value explicitly (a value not shared automatically
1443
  // through one of the BUILDER_FLAG_SHARE_* flags) you can do so with these
1444
  // functions. Or if you wish to turn those flags off for performance reasons
1445
  // and still do some explicit sharing. For example:
1446
  // builder.IndirectDouble(M_PI);
1447
  // auto id = builder.LastValue();  // Remember where we stored it.
1448
  // .. more code goes here ..
1449
  // builder.ReuseValue(id);  // Refers to same double by offset.
1450
  // LastValue works regardless of whether the value has a key or not.
1451
  // Works on any data type.
1452
  struct Value;
1453
0
  Value LastValue() { return stack_.back(); }
1454
0
  void ReuseValue(Value v) { stack_.push_back(v); }
1455
0
  void ReuseValue(const char* key, Value v) {
1456
0
    Key(key);
1457
0
    ReuseValue(v);
1458
0
  }
1459
1460
  // Undo the last element serialized. Call once for a value and once for a
1461
  // key.
1462
0
  void Undo() { stack_.pop_back(); }
1463
1464
  // Overloaded Add that tries to call the correct function above.
1465
0
  void Add(int8_t i) { Int(i); }
1466
0
  void Add(int16_t i) { Int(i); }
1467
0
  void Add(int32_t i) { Int(i); }
1468
0
  void Add(int64_t i) { Int(i); }
1469
0
  void Add(uint8_t u) { UInt(u); }
1470
0
  void Add(uint16_t u) { UInt(u); }
1471
0
  void Add(uint32_t u) { UInt(u); }
1472
0
  void Add(uint64_t u) { UInt(u); }
1473
0
  void Add(float f) { Float(f); }
1474
0
  void Add(double d) { Double(d); }
1475
0
  void Add(bool b) { Bool(b); }
1476
0
  void Add(const char* str) { String(str); }
1477
0
  void Add(const std::string& str) { String(str); }
1478
0
  void Add(const flexbuffers::String& str) { String(str); }
1479
1480
  template <typename T>
1481
  void Add(const std::vector<T>& vec) {
1482
    Vector(vec);
1483
  }
1484
1485
  template <typename T>
1486
  void Add(const char* key, const T& t) {
1487
    Key(key);
1488
    Add(t);
1489
  }
1490
1491
  template <typename T>
1492
  void Add(const std::map<std::string, T>& map) {
1493
    Map(map);
1494
  }
1495
1496
  template <typename T>
1497
  void operator+=(const T& t) {
1498
    Add(t);
1499
  }
1500
1501
  // This function is useful in combination with the Mutate* functions above.
1502
  // It forces elements of vectors and maps to have a minimum size, such that
1503
  // they can later be updated without failing.
1504
  // Call with no arguments to reset.
1505
0
  void ForceMinimumBitWidth(BitWidth bw = BIT_WIDTH_8) {
1506
0
    force_min_bit_width_ = bw;
1507
0
  }
1508
1509
14.5k
  void Finish() {
1510
    // If you hit this assert, you likely have objects that were never included
1511
    // in a parent. You need to have exactly one root to finish a buffer.
1512
    // Check your Start/End calls are matched, and all objects are inside
1513
    // some other object.
1514
14.5k
    FLATBUFFERS_ASSERT(stack_.size() == 1);
1515
1516
    // Write root value.
1517
14.5k
    auto byte_width = Align(stack_[0].ElemWidth(buf_.size(), 0));
1518
14.5k
    WriteAny(stack_[0], byte_width);
1519
    // Write root type.
1520
14.5k
    Write(stack_[0].StoredPackedType(), 1);
1521
    // Write root size. Normally determined by parent, but root has no parent :)
1522
14.5k
    Write(byte_width, 1);
1523
1524
14.5k
    finished_ = true;
1525
14.5k
  }
1526
1527
 private:
1528
14.5k
  void Finished() const {
1529
    // If you get this assert, you're attempting to get access a buffer
1530
    // which hasn't been finished yet. Be sure to call
1531
    // Builder::Finish with your root object.
1532
14.5k
    FLATBUFFERS_ASSERT(finished_);
1533
14.5k
  }
1534
1535
  // Align to prepare for writing a scalar with a certain size.
1536
933k
  uint8_t Align(BitWidth alignment) {
1537
933k
    auto byte_width = 1U << alignment;
1538
933k
    buf_.insert(buf_.end(), flatbuffers::PaddingBytes(buf_.size(), byte_width),
1539
933k
                0);
1540
933k
    return static_cast<uint8_t>(byte_width);
1541
933k
  }
1542
1543
3.96M
  void WriteBytes(const void* val, size_t size) {
1544
3.96M
    buf_.insert(buf_.end(), reinterpret_cast<const uint8_t*>(val),
1545
3.96M
                reinterpret_cast<const uint8_t*>(val) + size);
1546
3.96M
  }
1547
1548
  template <typename T>
1549
3.65M
  void Write(T val, size_t byte_width) {
1550
3.65M
    FLATBUFFERS_ASSERT(sizeof(T) >= byte_width);
1551
3.65M
    val = flatbuffers::EndianScalar(val);
1552
3.65M
    WriteBytes(&val, byte_width);
1553
3.65M
  }
void flexbuffers::Builder::Write<unsigned char>(unsigned char, unsigned long)
Line
Count
Source
1549
29.0k
  void Write(T val, size_t byte_width) {
1550
29.0k
    FLATBUFFERS_ASSERT(sizeof(T) >= byte_width);
1551
29.0k
    val = flatbuffers::EndianScalar(val);
1552
29.0k
    WriteBytes(&val, byte_width);
1553
29.0k
  }
void flexbuffers::Builder::Write<double>(double, unsigned long)
Line
Count
Source
1549
746k
  void Write(T val, size_t byte_width) {
1550
746k
    FLATBUFFERS_ASSERT(sizeof(T) >= byte_width);
1551
746k
    val = flatbuffers::EndianScalar(val);
1552
746k
    WriteBytes(&val, byte_width);
1553
746k
  }
void flexbuffers::Builder::Write<float>(float, unsigned long)
Line
Count
Source
1549
23.2k
  void Write(T val, size_t byte_width) {
1550
23.2k
    FLATBUFFERS_ASSERT(sizeof(T) >= byte_width);
1551
23.2k
    val = flatbuffers::EndianScalar(val);
1552
23.2k
    WriteBytes(&val, byte_width);
1553
23.2k
  }
void flexbuffers::Builder::Write<unsigned long>(unsigned long, unsigned long)
Line
Count
Source
1549
2.18M
  void Write(T val, size_t byte_width) {
1550
2.18M
    FLATBUFFERS_ASSERT(sizeof(T) >= byte_width);
1551
2.18M
    val = flatbuffers::EndianScalar(val);
1552
2.18M
    WriteBytes(&val, byte_width);
1553
2.18M
  }
void flexbuffers::Builder::Write<long>(long, unsigned long)
Line
Count
Source
1549
669k
  void Write(T val, size_t byte_width) {
1550
669k
    FLATBUFFERS_ASSERT(sizeof(T) >= byte_width);
1551
669k
    val = flatbuffers::EndianScalar(val);
1552
669k
    WriteBytes(&val, byte_width);
1553
669k
  }
1554
1555
769k
  void WriteDouble(double f, uint8_t byte_width) {
1556
769k
    switch (byte_width) {
1557
746k
      case 8:
1558
746k
        Write(f, byte_width);
1559
746k
        break;
1560
23.2k
      case 4:
1561
23.2k
        Write(static_cast<float>(f), byte_width);
1562
23.2k
        break;
1563
      // case 2: Write(static_cast<half>(f), byte_width); break;
1564
      // case 1: Write(static_cast<quarter>(f), byte_width); break;
1565
0
      default:
1566
0
        FLATBUFFERS_ASSERT(0);
1567
769k
    }
1568
769k
  }
1569
1570
1.18M
  void WriteOffset(uint64_t o, uint8_t byte_width) {
1571
1.18M
    auto reloff = buf_.size() - o;
1572
1.18M
    FLATBUFFERS_ASSERT(byte_width == 8 || reloff < 1ULL << (byte_width * 8));
1573
1.18M
    Write(reloff, byte_width);
1574
1.18M
  }
1575
1576
  template <typename T>
1577
0
  void PushIndirect(T val, Type type, BitWidth bit_width) {
1578
0
    auto byte_width = Align(bit_width);
1579
0
    auto iloc = buf_.size();
1580
0
    Write(val, byte_width);
1581
0
    stack_.push_back(Value(static_cast<uint64_t>(iloc), type, bit_width));
1582
0
  }
Unexecuted instantiation: void flexbuffers::Builder::PushIndirect<long>(long, flexbuffers::Type, flexbuffers::BitWidth)
Unexecuted instantiation: void flexbuffers::Builder::PushIndirect<unsigned long>(unsigned long, flexbuffers::Type, flexbuffers::BitWidth)
Unexecuted instantiation: void flexbuffers::Builder::PushIndirect<float>(float, flexbuffers::Type, flexbuffers::BitWidth)
Unexecuted instantiation: void flexbuffers::Builder::PushIndirect<double>(double, flexbuffers::Type, flexbuffers::BitWidth)
1583
1584
0
  static BitWidth WidthB(size_t byte_width) {
1585
0
    switch (byte_width) {
1586
0
      case 1:
1587
0
        return BIT_WIDTH_8;
1588
0
      case 2:
1589
0
        return BIT_WIDTH_16;
1590
0
      case 4:
1591
0
        return BIT_WIDTH_32;
1592
0
      case 8:
1593
0
        return BIT_WIDTH_64;
1594
0
      default:
1595
0
        FLATBUFFERS_ASSERT(false);
1596
0
        return BIT_WIDTH_64;
1597
0
    }
1598
0
  }
1599
1600
  template <typename T>
1601
  static Type GetScalarType() {
1602
    static_assert(flatbuffers::is_scalar<T>::value, "Unrelated types");
1603
    return flatbuffers::is_floating_point<T>::value ? FBT_FLOAT
1604
           : flatbuffers::is_same<T, bool>::value
1605
               ? FBT_BOOL
1606
               : (flatbuffers::is_unsigned<T>::value ? FBT_UINT : FBT_INT);
1607
  }
1608
1609
 public:
1610
  // This was really intended to be private, except for LastValue/ReuseValue.
1611
  struct Value {
1612
    union {
1613
      int64_t i_;
1614
      uint64_t u_;
1615
      double f_;
1616
    };
1617
1618
    Type type_;
1619
1620
    // For scalars: of itself, for vector: of its elements, for string: length.
1621
    BitWidth min_bit_width_;
1622
1623
1.62k
    Value() : i_(0), type_(FBT_NULL), min_bit_width_(BIT_WIDTH_8) {}
1624
1625
    Value(bool b)
1626
2.68k
        : u_(static_cast<uint64_t>(b)),
1627
2.68k
          type_(FBT_BOOL),
1628
2.68k
          min_bit_width_(BIT_WIDTH_8) {}
1629
1630
    Value(int64_t i, Type t, BitWidth bw)
1631
678k
        : i_(i), type_(t), min_bit_width_(bw) {}
1632
    Value(uint64_t u, Type t, BitWidth bw)
1633
1.20M
        : u_(u), type_(t), min_bit_width_(bw) {}
1634
1635
    Value(float f)
1636
        : f_(static_cast<double>(f)),
1637
          type_(FBT_FLOAT),
1638
0
          min_bit_width_(BIT_WIDTH_32) {}
1639
770k
    Value(double f) : f_(f), type_(FBT_FLOAT), min_bit_width_(WidthF(f)) {}
1640
1641
2.27M
    uint8_t StoredPackedType(BitWidth parent_bit_width_ = BIT_WIDTH_8) const {
1642
2.27M
      return PackedType(StoredWidth(parent_bit_width_), type_);
1643
2.27M
    }
1644
1645
2.62M
    BitWidth ElemWidth(size_t buf_size, size_t elem_index) const {
1646
2.62M
      if (IsInline(type_)) {
1647
1.44M
        return min_bit_width_;
1648
1.44M
      } else {
1649
        // We have an absolute offset, but want to store a relative offset
1650
        // elem_index elements beyond the current buffer end. Since whether
1651
        // the relative offset fits in a certain byte_width depends on
1652
        // the size of the elements before it (and their alignment), we have
1653
        // to test for each size in turn.
1654
1.18M
        for (size_t byte_width = 1;
1655
2.10M
             byte_width <= sizeof(flatbuffers::largest_scalar_t);
1656
2.10M
             byte_width *= 2) {
1657
          // Where are we going to write this offset?
1658
2.10M
          auto offset_loc = buf_size +
1659
2.10M
                            flatbuffers::PaddingBytes(buf_size, byte_width) +
1660
2.10M
                            elem_index * byte_width;
1661
          // Compute relative offset.
1662
2.10M
          auto offset = offset_loc - u_;
1663
          // Does it fit?
1664
2.10M
          auto bit_width = WidthU(offset);
1665
2.10M
          if (static_cast<size_t>(static_cast<size_t>(1U) << bit_width) ==
1666
2.10M
              byte_width)
1667
1.18M
            return bit_width;
1668
2.10M
        }
1669
0
        FLATBUFFERS_ASSERT(false);  // Must match one of the sizes above.
1670
0
        return BIT_WIDTH_64;
1671
0
      }
1672
2.62M
    }
1673
1674
2.27M
    BitWidth StoredWidth(BitWidth parent_bit_width_ = BIT_WIDTH_8) const {
1675
2.27M
      if (IsInline(type_)) {
1676
1.44M
        return (std::max)(min_bit_width_, parent_bit_width_);
1677
1.44M
      } else {
1678
832k
        return min_bit_width_;
1679
832k
      }
1680
2.27M
    }
1681
  };
1682
1683
 private:
1684
2.55M
  void WriteAny(const Value& val, uint8_t byte_width) {
1685
2.55M
    switch (val.type_) {
1686
1.61k
      case FBT_NULL:
1687
669k
      case FBT_INT:
1688
669k
        Write(val.i_, byte_width);
1689
669k
        break;
1690
2.66k
      case FBT_BOOL:
1691
2.66k
      case FBT_UINT:
1692
2.66k
        Write(val.u_, byte_width);
1693
2.66k
        break;
1694
769k
      case FBT_FLOAT:
1695
769k
        WriteDouble(val.f_, byte_width);
1696
769k
        break;
1697
1.11M
      default:
1698
1.11M
        WriteOffset(val.u_, byte_width);
1699
1.11M
        break;
1700
2.55M
    }
1701
2.55M
  }
1702
1703
23.9k
  size_t CreateBlob(const void* data, size_t len, size_t trailing, Type type) {
1704
23.9k
    auto bit_width = WidthU(len);
1705
23.9k
    return CreateAlignedBlob(data, len, trailing, type, bit_width);
1706
23.9k
  }
1707
1708
  size_t CreateAlignedBlob(const void* data, size_t len, size_t trailing,
1709
23.9k
                           Type type, BitWidth alignment) {
1710
23.9k
    auto byte_width = Align(alignment);
1711
23.9k
    Write<uint64_t>(len, byte_width);
1712
23.9k
    auto sloc = buf_.size();
1713
23.9k
    WriteBytes(data, len + trailing);
1714
23.9k
    stack_.push_back(Value(static_cast<uint64_t>(sloc), type, alignment));
1715
23.9k
    return sloc;
1716
23.9k
  }
1717
1718
  template <typename T>
1719
  size_t ScalarVector(const T* elems, size_t len, bool fixed) {
1720
    auto vector_type = GetScalarType<T>();
1721
    auto byte_width = sizeof(T);
1722
    auto bit_width = WidthB(byte_width);
1723
    // If you get this assert, you're trying to write a vector with a size
1724
    // field that is bigger than the scalars you're trying to write (e.g. a
1725
    // byte vector > 255 elements). For such types, write a "blob" instead.
1726
    // TODO: instead of asserting, could write vector with larger elements
1727
    // instead, though that would be wasteful.
1728
    FLATBUFFERS_ASSERT(WidthU(len) <= bit_width);
1729
    Align(bit_width);
1730
    if (!fixed) Write<uint64_t>(len, byte_width);
1731
    auto vloc = buf_.size();
1732
    for (size_t i = 0; i < len; i++) Write(elems[i], byte_width);
1733
    stack_.push_back(Value(static_cast<uint64_t>(vloc),
1734
                           ToTypedVector(vector_type, fixed ? len : 0),
1735
                           bit_width));
1736
    return vloc;
1737
  }
1738
1739
  Value CreateVector(size_t start, size_t vec_len, size_t step, bool typed,
1740
895k
                     bool fixed, const Value* keys = nullptr) {
1741
895k
    FLATBUFFERS_ASSERT(
1742
895k
        !fixed ||
1743
895k
        typed);  // typed=false, fixed=true combination is not supported.
1744
    // Figure out smallest bit width we can store this vector with.
1745
895k
    auto bit_width = (std::max)(force_min_bit_width_, WidthU(vec_len));
1746
895k
    auto prefix_elems = 1;
1747
895k
    if (keys) {
1748
      // If this vector is part of a map, we will pre-fix an offset to the keys
1749
      // to this vector.
1750
76.4k
      bit_width = (std::max)(bit_width, keys->ElemWidth(buf_.size(), 0));
1751
76.4k
      prefix_elems += 2;
1752
76.4k
    }
1753
895k
    Type vector_type = FBT_KEY;
1754
    // Check bit widths and types for all elements.
1755
3.43M
    for (size_t i = start; i < stack_.size(); i += step) {
1756
2.53M
      auto elem_width =
1757
2.53M
          stack_[i].ElemWidth(buf_.size(), i - start + prefix_elems);
1758
2.53M
      bit_width = (std::max)(bit_width, elem_width);
1759
2.53M
      if (typed) {
1760
278k
        if (i == start) {
1761
16.2k
          vector_type = stack_[i].type_;
1762
262k
        } else {
1763
          // If you get this assert, you are writing a typed vector with
1764
          // elements that are not all the same type.
1765
262k
          FLATBUFFERS_ASSERT(vector_type == stack_[i].type_);
1766
262k
        }
1767
278k
      }
1768
2.53M
    }
1769
    // If you get this assert, your typed types are not one of:
1770
    // Int / UInt / Float / Key.
1771
895k
    FLATBUFFERS_ASSERT(!typed || IsTypedVectorElementType(vector_type));
1772
895k
    auto byte_width = Align(bit_width);
1773
    // Write vector. First the keys width/offset if available, and size.
1774
895k
    if (keys) {
1775
76.4k
      WriteOffset(keys->u_, byte_width);
1776
76.4k
      Write<uint64_t>(1ULL << keys->min_bit_width_, byte_width);
1777
76.4k
    }
1778
895k
    if (!fixed) Write<uint64_t>(vec_len, byte_width);
1779
    // Then the actual data.
1780
895k
    auto vloc = buf_.size();
1781
3.43M
    for (size_t i = start; i < stack_.size(); i += step) {
1782
2.53M
      WriteAny(stack_[i], byte_width);
1783
2.53M
    }
1784
    // Then the types.
1785
895k
    if (!typed) {
1786
3.07M
      for (size_t i = start; i < stack_.size(); i += step) {
1787
2.25M
        buf_.push_back(stack_[i].StoredPackedType(bit_width));
1788
2.25M
      }
1789
818k
    }
1790
895k
    return Value(static_cast<uint64_t>(vloc),
1791
895k
                 keys ? FBT_MAP
1792
895k
                      : (typed ? ToTypedVector(vector_type, fixed ? vec_len : 0)
1793
818k
                               : FBT_VECTOR),
1794
895k
                 bit_width);
1795
895k
  }
1796
1797
  // You shouldn't really be copying instances of this class.
1798
  Builder(const Builder&);
1799
  Builder& operator=(const Builder&);
1800
1801
  std::vector<uint8_t> buf_;
1802
  std::vector<Value> stack_;
1803
1804
  bool finished_;
1805
  bool has_duplicate_keys_;
1806
1807
  BuilderFlag flags_;
1808
1809
  BitWidth force_min_bit_width_;
1810
1811
  struct KeyOffsetCompare {
1812
30.2k
    explicit KeyOffsetCompare(const std::vector<uint8_t>& buf) : buf_(&buf) {}
1813
1.84M
    bool operator()(size_t a, size_t b) const {
1814
1.84M
      auto stra = reinterpret_cast<const char*>(buf_->data() + a);
1815
1.84M
      auto strb = reinterpret_cast<const char*>(buf_->data() + b);
1816
1.84M
      return strcmp(stra, strb) < 0;
1817
1.84M
    }
1818
    const std::vector<uint8_t>* buf_;
1819
  };
1820
1821
  typedef std::pair<size_t, size_t> StringOffset;
1822
  struct StringOffsetCompare {
1823
    explicit StringOffsetCompare(const std::vector<uint8_t>& buf)
1824
30.2k
        : buf_(&buf) {}
1825
114k
    bool operator()(const StringOffset& a, const StringOffset& b) const {
1826
114k
      auto stra = buf_->data() + a.first;
1827
114k
      auto strb = buf_->data() + b.first;
1828
114k
      auto cr = memcmp(stra, strb, (std::min)(a.second, b.second) + 1);
1829
114k
      return cr < 0 || (cr == 0 && a.second < b.second);
1830
114k
    }
1831
    const std::vector<uint8_t>* buf_;
1832
  };
1833
1834
  typedef std::set<size_t, KeyOffsetCompare> KeyOffsetMap;
1835
  typedef std::set<StringOffset, StringOffsetCompare> StringOffsetMap;
1836
1837
  KeyOffsetMap key_pool;
1838
  StringOffsetMap string_pool;
1839
1840
  friend class Verifier;
1841
};
1842
1843
// Helper class to verify the integrity of a FlexBuffer
1844
class Verifier FLATBUFFERS_FINAL_CLASS {
1845
 public:
1846
  Verifier(const uint8_t* buf, size_t buf_len,
1847
           // Supplying this vector likely results in faster verification
1848
           // of larger buffers with many shared keys/strings, but
1849
           // comes at the cost of using additional memory the same size of
1850
           // the buffer being verified, so it is by default off.
1851
           std::vector<uint8_t>* reuse_tracker = nullptr,
1852
           bool _check_alignment = true, size_t max_depth = 64)
1853
11.2k
      : buf_(buf),
1854
11.2k
        size_(buf_len),
1855
11.2k
        depth_(0),
1856
11.2k
        max_depth_(max_depth),
1857
11.2k
        num_vectors_(0),
1858
11.2k
        max_vectors_(buf_len),
1859
11.2k
        check_alignment_(_check_alignment),
1860
11.2k
        reuse_tracker_(reuse_tracker) {
1861
11.2k
    FLATBUFFERS_ASSERT(static_cast<int32_t>(size_) <
1862
11.2k
                       FLATBUFFERS_MAX_BUFFER_SIZE);
1863
11.2k
    if (reuse_tracker_) {
1864
0
      reuse_tracker_->clear();
1865
0
      reuse_tracker_->resize(size_, PackedType(BIT_WIDTH_8, FBT_NULL));
1866
0
    }
1867
11.2k
  }
1868
1869
 private:
1870
  // Central location where any verification failures register.
1871
9.75M
  bool Check(bool ok) const {
1872
    // clang-format off
1873
    #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE
1874
      FLATBUFFERS_ASSERT(ok);
1875
    #endif
1876
    // clang-format on
1877
9.75M
    return ok;
1878
9.75M
  }
1879
1880
  // Verify any range within the buffer.
1881
1.62M
  bool VerifyFrom(size_t elem, size_t elem_len) const {
1882
1.62M
    return Check(elem_len < size_ && elem <= size_ - elem_len);
1883
1.62M
  }
1884
906k
  bool VerifyBefore(size_t elem, size_t elem_len) const {
1885
906k
    return Check(elem_len <= elem);
1886
906k
  }
1887
1888
1.62M
  bool VerifyFromPointer(const uint8_t* p, size_t len) {
1889
1.62M
    auto o = static_cast<size_t>(p - buf_);
1890
1.62M
    return VerifyFrom(o, len);
1891
1.62M
  }
1892
906k
  bool VerifyBeforePointer(const uint8_t* p, size_t len) {
1893
906k
    auto o = static_cast<size_t>(p - buf_);
1894
906k
    return VerifyBefore(o, len);
1895
906k
  }
1896
1897
1.95M
  bool VerifyByteWidth(size_t width) {
1898
1.95M
    return Check(width == 1 || width == 2 || width == 4 || width == 8);
1899
1.95M
  }
1900
1901
1.88M
  bool VerifyType(int type) { return Check(type >= 0 && type < FBT_MAX_TYPE); }
1902
1903
867k
  bool VerifyOffset(uint64_t off, const uint8_t* p) {
1904
867k
    return Check(off <= static_cast<uint64_t>(size_)) &&
1905
867k
           off <= static_cast<uint64_t>(p - buf_);
1906
867k
  }
1907
1908
805k
  bool VerifyAlignment(const uint8_t* p, size_t size) const {
1909
805k
    auto o = static_cast<size_t>(p - buf_);
1910
805k
    return Check((o & (size - 1)) == 0 || !check_alignment_);
1911
805k
  }
1912
1913
// Macro, since we want to escape from parent function & use lazy args.
1914
#define FLEX_CHECK_VERIFIED(P, PACKED_TYPE)                     \
1915
867k
  if (reuse_tracker_) {                                         \
1916
0
    auto packed_type = PACKED_TYPE;                             \
1917
0
    auto existing = (*reuse_tracker_)[P - buf_];                \
1918
0
    if (existing == packed_type) return true;                   \
1919
0
    /* Fail verification if already set with different type! */ \
1920
0
    if (!Check(existing == 0)) return false;                    \
1921
0
    (*reuse_tracker_)[P - buf_] = packed_type;                  \
1922
0
  }
1923
1924
843k
  bool VerifyVector(Reference r, const uint8_t* p, Type elem_type) {
1925
    // Any kind of nesting goes thru this function, so guard against that
1926
    // here, both with simple nesting checks, and the reuse tracker if on.
1927
843k
    depth_++;
1928
843k
    num_vectors_++;
1929
843k
    if (!Check(depth_ <= max_depth_ && num_vectors_ <= max_vectors_))
1930
0
      return false;
1931
843k
    auto size_byte_width = r.byte_width_;
1932
843k
    if (!VerifyBeforePointer(p, size_byte_width)) return false;
1933
843k
    FLEX_CHECK_VERIFIED(p - size_byte_width,
1934
843k
                        PackedType(Builder::WidthB(size_byte_width), r.type_));
1935
843k
    auto sized = Sized(p, size_byte_width);
1936
843k
    auto num_elems = sized.size();
1937
843k
    auto elem_byte_width = r.type_ == FBT_STRING || r.type_ == FBT_BLOB
1938
843k
                               ? uint8_t(1)
1939
843k
                               : r.byte_width_;
1940
843k
    auto max_elems = SIZE_MAX / elem_byte_width;
1941
843k
    if (!Check(num_elems < max_elems))
1942
0
      return false;  // Protect against byte_size overflowing.
1943
843k
    auto byte_size = num_elems * elem_byte_width;
1944
843k
    if (!VerifyFromPointer(p, byte_size)) return false;
1945
843k
    if (elem_type == FBT_NULL) {
1946
      // Verify type bytes after the vector.
1947
762k
      if (!VerifyFromPointer(p + byte_size, num_elems)) return false;
1948
762k
      auto v = Vector(p, size_byte_width);
1949
2.61M
      for (size_t i = 0; i < num_elems; i++)
1950
1.84M
        if (!VerifyRef(v[i])) return false;
1951
762k
    } else if (elem_type == FBT_KEY) {
1952
62.7k
      auto v = TypedVector(p, elem_byte_width, FBT_KEY);
1953
87.1k
      for (size_t i = 0; i < num_elems; i++)
1954
24.4k
        if (!VerifyRef(v[i])) return false;
1955
62.7k
    } else {
1956
17.9k
      FLATBUFFERS_ASSERT(IsInline(elem_type));
1957
17.9k
    }
1958
843k
    depth_--;
1959
843k
    return true;
1960
843k
  }
1961
1962
62.7k
  bool VerifyKeys(const uint8_t* p, uint8_t byte_width) {
1963
    // The vector part of the map has already been verified.
1964
62.7k
    const size_t num_prefixed_fields = 3;
1965
62.7k
    if (!VerifyBeforePointer(p, byte_width * num_prefixed_fields)) return false;
1966
62.7k
    p -= byte_width * num_prefixed_fields;
1967
62.7k
    auto off = ReadUInt64(p, byte_width);
1968
62.7k
    if (!VerifyOffset(off, p)) return false;
1969
62.7k
    auto key_byte_with =
1970
62.7k
        static_cast<uint8_t>(ReadUInt64(p + byte_width, byte_width));
1971
62.7k
    if (!VerifyByteWidth(key_byte_with)) return false;
1972
62.7k
    return VerifyVector(Reference(p, byte_width, key_byte_with, FBT_VECTOR_KEY),
1973
62.7k
                        p - off, FBT_KEY);
1974
62.7k
  }
1975
1976
24.4k
  bool VerifyKey(const uint8_t* p) {
1977
24.4k
    FLEX_CHECK_VERIFIED(p, PackedType(BIT_WIDTH_8, FBT_KEY));
1978
185k
    while (p < buf_ + size_)
1979
185k
      if (!*p++) return true;
1980
0
    return false;
1981
24.4k
  }
1982
1983
#undef FLEX_CHECK_VERIFIED
1984
1985
17.9k
  bool VerifyTerminator(const String& s) {
1986
17.9k
    return VerifyFromPointer(reinterpret_cast<const uint8_t*>(s.c_str()),
1987
17.9k
                             s.size() + 1);
1988
17.9k
  }
1989
1990
1.88M
  bool VerifyRef(Reference r) {
1991
    // r.parent_width_ and r.data_ already verified.
1992
1.88M
    if (!VerifyByteWidth(r.byte_width_) || !VerifyType(r.type_)) {
1993
0
      return false;
1994
0
    }
1995
1.88M
    if (IsInline(r.type_)) {
1996
      // Inline scalars, don't require further verification.
1997
1.07M
      return true;
1998
1.07M
    }
1999
    // All remaining types are an offset.
2000
805k
    auto off = ReadUInt64(r.data_, r.parent_width_);
2001
805k
    if (!VerifyOffset(off, r.data_)) return false;
2002
805k
    auto p = r.Indirect();
2003
805k
    if (!VerifyAlignment(p, r.byte_width_)) return false;
2004
805k
    switch (r.type_) {
2005
0
      case FBT_INDIRECT_INT:
2006
0
      case FBT_INDIRECT_UINT:
2007
0
      case FBT_INDIRECT_FLOAT:
2008
0
        return VerifyFromPointer(p, r.byte_width_);
2009
24.4k
      case FBT_KEY:
2010
24.4k
        return VerifyKey(p);
2011
62.7k
      case FBT_MAP:
2012
62.7k
        return VerifyVector(r, p, FBT_NULL) && VerifyKeys(p, r.byte_width_);
2013
700k
      case FBT_VECTOR:
2014
700k
        return VerifyVector(r, p, FBT_NULL);
2015
0
      case FBT_VECTOR_INT:
2016
0
        return VerifyVector(r, p, FBT_INT);
2017
0
      case FBT_VECTOR_BOOL:
2018
0
      case FBT_VECTOR_UINT:
2019
0
        return VerifyVector(r, p, FBT_UINT);
2020
0
      case FBT_VECTOR_FLOAT:
2021
0
        return VerifyVector(r, p, FBT_FLOAT);
2022
0
      case FBT_VECTOR_KEY:
2023
0
        return VerifyVector(r, p, FBT_KEY);
2024
0
      case FBT_VECTOR_STRING_DEPRECATED:
2025
        // Use of FBT_KEY here intentional, see elsewhere.
2026
0
        return VerifyVector(r, p, FBT_KEY);
2027
0
      case FBT_BLOB:
2028
0
        return VerifyVector(r, p, FBT_UINT);
2029
17.9k
      case FBT_STRING:
2030
17.9k
        return VerifyVector(r, p, FBT_UINT) &&
2031
17.9k
               VerifyTerminator(String(p, r.byte_width_));
2032
0
      case FBT_VECTOR_INT2:
2033
0
      case FBT_VECTOR_UINT2:
2034
0
      case FBT_VECTOR_FLOAT2:
2035
0
      case FBT_VECTOR_INT3:
2036
0
      case FBT_VECTOR_UINT3:
2037
0
      case FBT_VECTOR_FLOAT3:
2038
0
      case FBT_VECTOR_INT4:
2039
0
      case FBT_VECTOR_UINT4:
2040
0
      case FBT_VECTOR_FLOAT4: {
2041
0
        uint8_t len = 0;
2042
0
        auto vtype = ToFixedTypedVectorElementType(r.type_, &len);
2043
0
        if (!VerifyType(vtype)) return false;
2044
0
        return VerifyFromPointer(p, static_cast<size_t>(r.byte_width_) * len);
2045
0
      }
2046
0
      default:
2047
0
        return false;
2048
805k
    }
2049
805k
  }
2050
2051
 public:
2052
11.2k
  bool VerifyBuffer() {
2053
11.2k
    if (!Check(size_ >= 3)) return false;
2054
11.2k
    auto end = buf_ + size_;
2055
11.2k
    auto byte_width = *--end;
2056
11.2k
    auto packed_type = *--end;
2057
11.2k
    return VerifyByteWidth(byte_width) && Check(end - buf_ >= byte_width) &&
2058
11.2k
           VerifyRef(Reference(end - byte_width, byte_width, packed_type));
2059
11.2k
  }
2060
2061
 private:
2062
  const uint8_t* buf_;
2063
  size_t size_;
2064
  size_t depth_;
2065
  const size_t max_depth_;
2066
  size_t num_vectors_;
2067
  const size_t max_vectors_;
2068
  bool check_alignment_;
2069
  std::vector<uint8_t>* reuse_tracker_;
2070
};
2071
2072
// Utility function that constructs the Verifier for you, see above for
2073
// parameters.
2074
inline bool VerifyBuffer(const uint8_t* buf, size_t buf_len,
2075
11.2k
                         std::vector<uint8_t>* reuse_tracker = nullptr) {
2076
11.2k
  Verifier verifier(buf, buf_len, reuse_tracker);
2077
11.2k
  return verifier.VerifyBuffer();
2078
11.2k
}
2079
2080
}  // namespace flexbuffers
2081
2082
#if defined(_MSC_VER)
2083
#pragma warning(pop)
2084
#endif
2085
2086
#endif  // FLATBUFFERS_FLEXBUFFERS_H_