base.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. #ifndef FLATBUFFERS_BASE_H_
  2. #define FLATBUFFERS_BASE_H_
  3. // For TFLM, we always want FLATBUFFERS_LOCALE_INDEPENDENT to be defined as 0.
  4. // We could achieve this by adding -DFLATBUFFERS_LOCALE_INDEPENDENT=0 to the
  5. // TFLM Makefile. However, for (at least) the Arduino, adding additional build
  6. // flags during the compilation can be a bit awkward. As such, we have instead
  7. // made a decision to change the default to be FLATBUFFERS_LOCALE_INDEPENDENT=0
  8. // for TFLM to make it easier for external IDE integration.
  9. #ifndef FLATBUFFERS_LOCALE_INDEPENDENT
  10. #define FLATBUFFERS_LOCALE_INDEPENDENT 0
  11. #endif
  12. // clang-format off
  13. // If activate should be declared and included first.
  14. #if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
  15. defined(_MSC_VER) && defined(_DEBUG)
  16. // The _CRTDBG_MAP_ALLOC inside <crtdbg.h> will replace
  17. // calloc/free (etc) to its debug version using #define directives.
  18. #define _CRTDBG_MAP_ALLOC
  19. #include <stdlib.h>
  20. #include <crtdbg.h>
  21. // Replace operator new by trace-enabled version.
  22. #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
  23. #define new DEBUG_NEW
  24. #endif
  25. #if !defined(FLATBUFFERS_ASSERT)
  26. #include <assert.h>
  27. #define FLATBUFFERS_ASSERT assert
  28. #elif defined(FLATBUFFERS_ASSERT_INCLUDE)
  29. // Include file with forward declaration
  30. #include FLATBUFFERS_ASSERT_INCLUDE
  31. #endif
  32. #ifndef ARDUINO
  33. #include <cstdint>
  34. #endif
  35. #include <cstddef>
  36. #include <cstdlib>
  37. #include <cstring>
  38. #if defined(ARDUINO) && !defined(ARDUINOSTL_M_H)
  39. #include <utility.h>
  40. #else
  41. #include <utility>
  42. #endif
  43. #include <string>
  44. #include <type_traits>
  45. #include <vector>
  46. #include <set>
  47. #include <algorithm>
  48. #include <iterator>
  49. #include <memory>
  50. #if defined(__unix__) && !defined(FLATBUFFERS_LOCALE_INDEPENDENT)
  51. #include <unistd.h>
  52. #endif
  53. #ifdef __ANDROID__
  54. #include <android/api-level.h>
  55. #endif
  56. #if defined(__ICCARM__)
  57. #include <intrinsics.h>
  58. #endif
  59. // Note the __clang__ check is needed, because clang presents itself
  60. // as an older GNUC compiler (4.2).
  61. // Clang 3.3 and later implement all of the ISO C++ 2011 standard.
  62. // Clang 3.4 and later implement all of the ISO C++ 2014 standard.
  63. // http://clang.llvm.org/cxx_status.html
  64. // Note the MSVC value '__cplusplus' may be incorrect:
  65. // The '__cplusplus' predefined macro in the MSVC stuck at the value 199711L,
  66. // indicating (erroneously!) that the compiler conformed to the C++98 Standard.
  67. // This value should be correct starting from MSVC2017-15.7-Preview-3.
  68. // The '__cplusplus' will be valid only if MSVC2017-15.7-P3 and the `/Zc:__cplusplus` switch is set.
  69. // Workaround (for details see MSDN):
  70. // Use the _MSC_VER and _MSVC_LANG definition instead of the __cplusplus for compatibility.
  71. // The _MSVC_LANG macro reports the Standard version regardless of the '/Zc:__cplusplus' switch.
  72. #if defined(__GNUC__) && !defined(__clang__)
  73. #define FLATBUFFERS_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
  74. #else
  75. #define FLATBUFFERS_GCC 0
  76. #endif
  77. #if defined(__clang__)
  78. #define FLATBUFFERS_CLANG (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
  79. #else
  80. #define FLATBUFFERS_CLANG 0
  81. #endif
  82. /// @cond FLATBUFFERS_INTERNAL
  83. #if __cplusplus <= 199711L && \
  84. (!defined(_MSC_VER) || _MSC_VER < 1600) && \
  85. (!defined(__GNUC__) || \
  86. (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400))
  87. #error A C++11 compatible compiler with support for the auto typing is \
  88. required for FlatBuffers.
  89. #error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__
  90. #endif
  91. #if !defined(__clang__) && \
  92. defined(__GNUC__) && \
  93. (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600)
  94. // Backwards compatibility for g++ 4.4, and 4.5 which don't have the nullptr
  95. // and constexpr keywords. Note the __clang__ check is needed, because clang
  96. // presents itself as an older GNUC compiler.
  97. #ifndef nullptr_t
  98. const class nullptr_t {
  99. public:
  100. template<class T> inline operator T*() const { return 0; }
  101. private:
  102. void operator&() const;
  103. } nullptr = {};
  104. #endif
  105. #ifndef constexpr
  106. #define constexpr const
  107. #endif
  108. #endif
  109. // The wire format uses a little endian encoding (since that's efficient for
  110. // the common platforms).
  111. #if defined(__s390x__)
  112. #define FLATBUFFERS_LITTLEENDIAN 0
  113. #endif // __s390x__
  114. #if !defined(FLATBUFFERS_LITTLEENDIAN)
  115. #if defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__)
  116. #if (defined(__BIG_ENDIAN__) || \
  117. (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
  118. #define FLATBUFFERS_LITTLEENDIAN 0
  119. #else
  120. #define FLATBUFFERS_LITTLEENDIAN 1
  121. #endif // __BIG_ENDIAN__
  122. #elif defined(_MSC_VER)
  123. #if defined(_M_PPC)
  124. #define FLATBUFFERS_LITTLEENDIAN 0
  125. #else
  126. #define FLATBUFFERS_LITTLEENDIAN 1
  127. #endif
  128. #else
  129. #error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN.
  130. #endif
  131. #endif // !defined(FLATBUFFERS_LITTLEENDIAN)
  132. #define FLATBUFFERS_VERSION_MAJOR 2
  133. #define FLATBUFFERS_VERSION_MINOR 0
  134. #define FLATBUFFERS_VERSION_REVISION 5
  135. #define FLATBUFFERS_STRING_EXPAND(X) #X
  136. #define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
  137. namespace flatbuffers {
  138. // Returns version as string "MAJOR.MINOR.REVISION".
  139. const char* FLATBUFFERS_VERSION();
  140. }
  141. #if (!defined(_MSC_VER) || _MSC_VER > 1600) && \
  142. (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407)) || \
  143. defined(__clang__)
  144. #define FLATBUFFERS_FINAL_CLASS final
  145. #define FLATBUFFERS_OVERRIDE override
  146. #define FLATBUFFERS_EXPLICIT_CPP11 explicit
  147. #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE : flatbuffers::voffset_t
  148. #else
  149. #define FLATBUFFERS_FINAL_CLASS
  150. #define FLATBUFFERS_OVERRIDE
  151. #define FLATBUFFERS_EXPLICIT_CPP11
  152. #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE
  153. #endif
  154. #if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
  155. (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
  156. (defined(__cpp_constexpr) && __cpp_constexpr >= 200704)
  157. #define FLATBUFFERS_CONSTEXPR constexpr
  158. #define FLATBUFFERS_CONSTEXPR_CPP11 constexpr
  159. #define FLATBUFFERS_CONSTEXPR_DEFINED
  160. #else
  161. #define FLATBUFFERS_CONSTEXPR const
  162. #define FLATBUFFERS_CONSTEXPR_CPP11
  163. #endif
  164. #if (defined(__cplusplus) && __cplusplus >= 201402L) || \
  165. (defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
  166. #define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR_CPP11
  167. #else
  168. #define FLATBUFFERS_CONSTEXPR_CPP14
  169. #endif
  170. #if (defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
  171. (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023026)) || \
  172. defined(__clang__)
  173. #define FLATBUFFERS_NOEXCEPT noexcept
  174. #else
  175. #define FLATBUFFERS_NOEXCEPT
  176. #endif
  177. // NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to
  178. // private, so be sure to put it at the end or reset access mode explicitly.
  179. #if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \
  180. (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) || \
  181. defined(__clang__)
  182. #define FLATBUFFERS_DELETE_FUNC(func) func = delete
  183. #else
  184. #define FLATBUFFERS_DELETE_FUNC(func) private: func
  185. #endif
  186. #if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
  187. (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \
  188. defined(__clang__)
  189. #define FLATBUFFERS_DEFAULT_DECLARATION
  190. #endif
  191. // Check if we can use template aliases
  192. // Not possible if Microsoft Compiler before 2012
  193. // Possible is the language feature __cpp_alias_templates is defined well
  194. // Or possible if the C++ std is C+11 or newer
  195. #if (defined(_MSC_VER) && _MSC_VER > 1700 /* MSVC2012 */) \
  196. || (defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \
  197. || (defined(__cplusplus) && __cplusplus >= 201103L)
  198. #define FLATBUFFERS_TEMPLATES_ALIASES
  199. #endif
  200. #ifndef FLATBUFFERS_HAS_STRING_VIEW
  201. // Only provide flatbuffers::string_view if __has_include can be used
  202. // to detect a header that provides an implementation
  203. #if defined(__has_include)
  204. // Check for std::string_view (in c++17)
  205. #if __has_include(<string_view>) && (__cplusplus >= 201606 || (defined(_HAS_CXX17) && _HAS_CXX17))
  206. #include <string_view>
  207. namespace flatbuffers {
  208. typedef std::string_view string_view;
  209. }
  210. #define FLATBUFFERS_HAS_STRING_VIEW 1
  211. // Check for std::experimental::string_view (in c++14, compiler-dependent)
  212. #elif __has_include(<experimental/string_view>) && (__cplusplus >= 201411)
  213. #include <experimental/string_view>
  214. namespace flatbuffers {
  215. typedef std::experimental::string_view string_view;
  216. }
  217. #define FLATBUFFERS_HAS_STRING_VIEW 1
  218. // Check for absl::string_view
  219. #elif __has_include("absl/strings/string_view.h")
  220. #include "absl/strings/string_view.h"
  221. namespace flatbuffers {
  222. typedef absl::string_view string_view;
  223. }
  224. #define FLATBUFFERS_HAS_STRING_VIEW 1
  225. #endif
  226. #endif // __has_include
  227. #endif // !FLATBUFFERS_HAS_STRING_VIEW
  228. #ifndef FLATBUFFERS_GENERAL_HEAP_ALLOC_OK
  229. // Allow heap allocations to be used
  230. #define FLATBUFFERS_GENERAL_HEAP_ALLOC_OK 1
  231. #endif // !FLATBUFFERS_GENERAL_HEAP_ALLOC_OK
  232. #ifndef FLATBUFFERS_HAS_NEW_STRTOD
  233. // Modern (C++11) strtod and strtof functions are available for use.
  234. // 1) nan/inf strings as argument of strtod;
  235. // 2) hex-float as argument of strtod/strtof.
  236. #if (defined(_MSC_VER) && _MSC_VER >= 1900) || \
  237. (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \
  238. (defined(__clang__))
  239. #define FLATBUFFERS_HAS_NEW_STRTOD 1
  240. #endif
  241. #endif // !FLATBUFFERS_HAS_NEW_STRTOD
  242. #ifndef FLATBUFFERS_LOCALE_INDEPENDENT
  243. // Enable locale independent functions {strtof_l, strtod_l,strtoll_l, strtoull_l}.
  244. #if ((defined(_MSC_VER) && _MSC_VER >= 1800) || \
  245. (defined(_XOPEN_VERSION) && (_XOPEN_VERSION>=700)) && (!defined(__ANDROID_API__) || (defined(__ANDROID_API__) && (__ANDROID_API__>=21))))
  246. #define FLATBUFFERS_LOCALE_INDEPENDENT 1
  247. #else
  248. #define FLATBUFFERS_LOCALE_INDEPENDENT 0
  249. #endif
  250. #endif // !FLATBUFFERS_LOCALE_INDEPENDENT
  251. // Suppress Undefined Behavior Sanitizer (recoverable only). Usage:
  252. // - __supress_ubsan__("undefined")
  253. // - __supress_ubsan__("signed-integer-overflow")
  254. #if defined(__clang__) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >=7))
  255. #define __supress_ubsan__(type) __attribute__((no_sanitize(type)))
  256. #elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)
  257. #define __supress_ubsan__(type) __attribute__((no_sanitize_undefined))
  258. #else
  259. #define __supress_ubsan__(type)
  260. #endif
  261. // This is constexpr function used for checking compile-time constants.
  262. // Avoid `#pragma warning(disable: 4127) // C4127: expression is constant`.
  263. template<typename T> FLATBUFFERS_CONSTEXPR inline bool IsConstTrue(T t) {
  264. return !!t;
  265. }
  266. // Enable C++ attribute [[]] if std:c++17 or higher.
  267. #if ((__cplusplus >= 201703L) \
  268. || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)))
  269. // All attributes unknown to an implementation are ignored without causing an error.
  270. #define FLATBUFFERS_ATTRIBUTE(attr) attr
  271. #define FLATBUFFERS_FALLTHROUGH() [[fallthrough]]
  272. #else
  273. #define FLATBUFFERS_ATTRIBUTE(attr)
  274. #if FLATBUFFERS_CLANG >= 30800
  275. #define FLATBUFFERS_FALLTHROUGH() [[clang::fallthrough]]
  276. #elif FLATBUFFERS_GCC >= 70300
  277. #define FLATBUFFERS_FALLTHROUGH() [[gnu::fallthrough]]
  278. #else
  279. #define FLATBUFFERS_FALLTHROUGH()
  280. #endif
  281. #endif
  282. /// @endcond
  283. /// @file
  284. namespace flatbuffers {
  285. /// @cond FLATBUFFERS_INTERNAL
  286. // Our default offset / size type, 32bit on purpose on 64bit systems.
  287. // Also, using a consistent offset type maintains compatibility of serialized
  288. // offset values between 32bit and 64bit systems.
  289. typedef uint32_t uoffset_t;
  290. // Signed offsets for references that can go in both directions.
  291. typedef int32_t soffset_t;
  292. // Offset/index used in v-tables, can be changed to uint8_t in
  293. // format forks to save a bit of space if desired.
  294. typedef uint16_t voffset_t;
  295. typedef uintmax_t largest_scalar_t;
  296. // In 32bits, this evaluates to 2GB - 1
  297. #define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(::flatbuffers::soffset_t) * 8 - 1)) - 1)
  298. // We support aligning the contents of buffers up to this size.
  299. #define FLATBUFFERS_MAX_ALIGNMENT 16
  300. /// @brief The length of a FlatBuffer file header.
  301. static const size_t kFileIdentifierLength = 4;
  302. inline bool VerifyAlignmentRequirements(size_t align, size_t min_align = 1) {
  303. return (min_align <= align) && (align <= (FLATBUFFERS_MAX_ALIGNMENT)) &&
  304. (align & (align - 1)) == 0; // must be power of 2
  305. }
  306. #if defined(_MSC_VER)
  307. #pragma warning(disable: 4351) // C4351: new behavior: elements of array ... will be default initialized
  308. #pragma warning(push)
  309. #pragma warning(disable: 4127) // C4127: conditional expression is constant
  310. #endif
  311. template<typename T> T EndianSwap(T t) {
  312. #if defined(_MSC_VER)
  313. #define FLATBUFFERS_BYTESWAP16 _byteswap_ushort
  314. #define FLATBUFFERS_BYTESWAP32 _byteswap_ulong
  315. #define FLATBUFFERS_BYTESWAP64 _byteswap_uint64
  316. #elif defined(__ICCARM__)
  317. #define FLATBUFFERS_BYTESWAP16 __REV16
  318. #define FLATBUFFERS_BYTESWAP32 __REV
  319. #define FLATBUFFERS_BYTESWAP64(x) \
  320. ((__REV(static_cast<uint32_t>(x >> 32U))) | (static_cast<uint64_t>(__REV(static_cast<uint32_t>(x)))) << 32U)
  321. #else
  322. #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408 && !defined(__clang__)
  323. // __builtin_bswap16 was missing prior to GCC 4.8.
  324. #define FLATBUFFERS_BYTESWAP16(x) \
  325. static_cast<uint16_t>(__builtin_bswap32(static_cast<uint32_t>(x) << 16))
  326. #else
  327. #define FLATBUFFERS_BYTESWAP16 __builtin_bswap16
  328. #endif
  329. #define FLATBUFFERS_BYTESWAP32 __builtin_bswap32
  330. #define FLATBUFFERS_BYTESWAP64 __builtin_bswap64
  331. #endif
  332. if (sizeof(T) == 1) { // Compile-time if-then's.
  333. return t;
  334. } else if (sizeof(T) == 2) {
  335. union { T t; uint16_t i; } u = { t };
  336. u.i = FLATBUFFERS_BYTESWAP16(u.i);
  337. return u.t;
  338. } else if (sizeof(T) == 4) {
  339. union { T t; uint32_t i; } u = { t };
  340. u.i = FLATBUFFERS_BYTESWAP32(u.i);
  341. return u.t;
  342. } else if (sizeof(T) == 8) {
  343. union { T t; uint64_t i; } u = { t };
  344. u.i = FLATBUFFERS_BYTESWAP64(u.i);
  345. return u.t;
  346. } else {
  347. FLATBUFFERS_ASSERT(0);
  348. return t;
  349. }
  350. }
  351. #if defined(_MSC_VER)
  352. #pragma warning(pop)
  353. #endif
  354. template<typename T> T EndianScalar(T t) {
  355. #if FLATBUFFERS_LITTLEENDIAN
  356. return t;
  357. #else
  358. return EndianSwap(t);
  359. #endif
  360. }
  361. template<typename T>
  362. // UBSAN: C++ aliasing type rules, see std::bit_cast<> for details.
  363. __supress_ubsan__("alignment")
  364. T ReadScalar(const void *p) {
  365. return EndianScalar(*reinterpret_cast<const T *>(p));
  366. }
  367. // See https://github.com/google/flatbuffers/issues/5950
  368. #if (FLATBUFFERS_GCC >= 100000) && (FLATBUFFERS_GCC < 110000)
  369. #pragma GCC diagnostic push
  370. #pragma GCC diagnostic ignored "-Wstringop-overflow"
  371. #endif
  372. template<typename T>
  373. // UBSAN: C++ aliasing type rules, see std::bit_cast<> for details.
  374. __supress_ubsan__("alignment")
  375. void WriteScalar(void *p, T t) {
  376. *reinterpret_cast<T *>(p) = EndianScalar(t);
  377. }
  378. template<typename T> struct Offset;
  379. template<typename T> __supress_ubsan__("alignment") void WriteScalar(void *p, Offset<T> t) {
  380. *reinterpret_cast<uoffset_t *>(p) = EndianScalar(t.o);
  381. }
  382. #if (FLATBUFFERS_GCC >= 100000) && (FLATBUFFERS_GCC < 110000)
  383. #pragma GCC diagnostic pop
  384. #endif
  385. // Computes how many bytes you'd have to pad to be able to write an
  386. // "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in
  387. // memory).
  388. __supress_ubsan__("unsigned-integer-overflow")
  389. inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
  390. return ((~buf_size) + 1) & (scalar_size - 1);
  391. }
  392. // Generic 'operator==' with conditional specialisations.
  393. // T e - new value of a scalar field.
  394. // T def - default of scalar (is known at compile-time).
  395. template<typename T> inline bool IsTheSameAs(T e, T def) { return e == def; }
  396. #if defined(FLATBUFFERS_NAN_DEFAULTS) && \
  397. defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
  398. // Like `operator==(e, def)` with weak NaN if T=(float|double).
  399. template<typename T> inline bool IsFloatTheSameAs(T e, T def) {
  400. return (e == def) || ((def != def) && (e != e));
  401. }
  402. template<> inline bool IsTheSameAs<float>(float e, float def) {
  403. return IsFloatTheSameAs(e, def);
  404. }
  405. template<> inline bool IsTheSameAs<double>(double e, double def) {
  406. return IsFloatTheSameAs(e, def);
  407. }
  408. #endif
  409. // Check 'v' is out of closed range [low; high].
  410. // Workaround for GCC warning [-Werror=type-limits]:
  411. // comparison is always true due to limited range of data type.
  412. template<typename T>
  413. inline bool IsOutRange(const T &v, const T &low, const T &high) {
  414. return (v < low) || (high < v);
  415. }
  416. // Check 'v' is in closed range [low; high].
  417. template<typename T>
  418. inline bool IsInRange(const T &v, const T &low, const T &high) {
  419. return !IsOutRange(v, low, high);
  420. }
  421. } // namespace flatbuffers
  422. #endif // FLATBUFFERS_BASE_H_