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