1 | /* |
2 | * Copyright 2021 Google Inc. All rights reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #ifndef FLATBUFFERS_BUFFER_H_ |
18 | #define FLATBUFFERS_BUFFER_H_ |
19 | |
20 | #include "flatbuffers/base.h" |
21 | |
22 | namespace flatbuffers { |
23 | |
24 | // Wrapper for uoffset_t to allow safe template specialization. |
25 | // Value is allowed to be 0 to indicate a null object (see e.g. AddOffset). |
26 | template<typename T> struct Offset { |
27 | uoffset_t o; |
28 | Offset() : o(0) {} |
29 | Offset(uoffset_t _o) : o(_o) {} |
30 | Offset<void> Union() const { return Offset<void>(o); } |
31 | bool IsNull() const { return !o; } |
32 | }; |
33 | |
34 | inline void EndianCheck() { |
35 | int endiantest = 1; |
36 | // If this fails, see FLATBUFFERS_LITTLEENDIAN above. |
37 | FLATBUFFERS_ASSERT(*reinterpret_cast<char *>(&endiantest) == |
38 | FLATBUFFERS_LITTLEENDIAN); |
39 | (void)endiantest; |
40 | } |
41 | |
42 | template<typename T> FLATBUFFERS_CONSTEXPR size_t AlignOf() { |
43 | // clang-format off |
44 | #ifdef _MSC_VER |
45 | return __alignof(T); |
46 | #else |
47 | #ifndef alignof |
48 | return __alignof__(T); |
49 | #else |
50 | return alignof(T); |
51 | #endif |
52 | #endif |
53 | // clang-format on |
54 | } |
55 | |
56 | // Lexicographically compare two strings (possibly containing nulls), and |
57 | // return true if the first is less than the second. |
58 | static inline bool StringLessThan(const char *a_data, uoffset_t a_size, |
59 | const char *b_data, uoffset_t b_size) { |
60 | const auto cmp = memcmp(a_data, b_data, (std::min)(a_size, b_size)); |
61 | return cmp == 0 ? a_size < b_size : cmp < 0; |
62 | } |
63 | |
64 | // When we read serialized data from memory, in the case of most scalars, |
65 | // we want to just read T, but in the case of Offset, we want to actually |
66 | // perform the indirection and return a pointer. |
67 | // The template specialization below does just that. |
68 | // It is wrapped in a struct since function templates can't overload on the |
69 | // return type like this. |
70 | // The typedef is for the convenience of callers of this function |
71 | // (avoiding the need for a trailing return decltype) |
72 | template<typename T> struct IndirectHelper { |
73 | typedef T return_type; |
74 | typedef T mutable_return_type; |
75 | static const size_t element_stride = sizeof(T); |
76 | static return_type Read(const uint8_t *p, uoffset_t i) { |
77 | return EndianScalar((reinterpret_cast<const T *>(p))[i]); |
78 | } |
79 | }; |
80 | template<typename T> struct IndirectHelper<Offset<T>> { |
81 | typedef const T *return_type; |
82 | typedef T *mutable_return_type; |
83 | static const size_t element_stride = sizeof(uoffset_t); |
84 | static return_type Read(const uint8_t *p, uoffset_t i) { |
85 | p += i * sizeof(uoffset_t); |
86 | return reinterpret_cast<return_type>(p + ReadScalar<uoffset_t>(p)); |
87 | } |
88 | }; |
89 | template<typename T> struct IndirectHelper<const T *> { |
90 | typedef const T *return_type; |
91 | typedef T *mutable_return_type; |
92 | static const size_t element_stride = sizeof(T); |
93 | static return_type Read(const uint8_t *p, uoffset_t i) { |
94 | return reinterpret_cast<const T *>(p + i * sizeof(T)); |
95 | } |
96 | }; |
97 | |
98 | /// @brief Get a pointer to the the file_identifier section of the buffer. |
99 | /// @return Returns a const char pointer to the start of the file_identifier |
100 | /// characters in the buffer. The returned char * has length |
101 | /// 'flatbuffers::FlatBufferBuilder::kFileIdentifierLength'. |
102 | /// This function is UNDEFINED for FlatBuffers whose schema does not include |
103 | /// a file_identifier (likely points at padding or the start of a the root |
104 | /// vtable). |
105 | inline const char *GetBufferIdentifier(const void *buf, |
106 | bool size_prefixed = false) { |
107 | return reinterpret_cast<const char *>(buf) + |
108 | ((size_prefixed) ? 2 * sizeof(uoffset_t) : sizeof(uoffset_t)); |
109 | } |
110 | |
111 | // Helper to see if the identifier in a buffer has the expected value. |
112 | inline bool BufferHasIdentifier(const void *buf, const char *identifier, |
113 | bool size_prefixed = false) { |
114 | return strncmp(GetBufferIdentifier(buf, size_prefixed), identifier, |
115 | flatbuffers::kFileIdentifierLength) == 0; |
116 | } |
117 | |
118 | /// @cond FLATBUFFERS_INTERNAL |
119 | // Helpers to get a typed pointer to the root object contained in the buffer. |
120 | template<typename T> T *GetMutableRoot(void *buf) { |
121 | EndianCheck(); |
122 | return reinterpret_cast<T *>( |
123 | reinterpret_cast<uint8_t *>(buf) + |
124 | EndianScalar(*reinterpret_cast<uoffset_t *>(buf))); |
125 | } |
126 | |
127 | template<typename T> T *GetMutableSizePrefixedRoot(void *buf) { |
128 | return GetMutableRoot<T>(reinterpret_cast<uint8_t *>(buf) + |
129 | sizeof(uoffset_t)); |
130 | } |
131 | |
132 | template<typename T> const T *GetRoot(const void *buf) { |
133 | return GetMutableRoot<T>(const_cast<void *>(buf)); |
134 | } |
135 | |
136 | template<typename T> const T *GetSizePrefixedRoot(const void *buf) { |
137 | return GetRoot<T>(reinterpret_cast<const uint8_t *>(buf) + sizeof(uoffset_t)); |
138 | } |
139 | |
140 | } // namespace flatbuffers |
141 | |
142 | #endif // FLATBUFFERS_BUFFER_H_ |