/* * Copyright 2021 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FLATBUFFERS_BUFFER_H_ #define FLATBUFFERS_BUFFER_H_ #include #include "flatbuffers/base.h" namespace flatbuffers { // Wrapper for uoffset_t to allow safe template specialization. // Value is allowed to be 0 to indicate a null object (see e.g. AddOffset). template struct Offset { // The type of offset to use. typedef uoffset_t offset_type; offset_type o; Offset() : o(0) {} Offset(const offset_type _o) : o(_o) {} Offset<> Union() const { return o; } bool IsNull() const { return !o; } }; // Wrapper for uoffset64_t Offsets. template struct Offset64 { // The type of offset to use. typedef uoffset64_t offset_type; offset_type o; Offset64() : o(0) {} Offset64(const offset_type offset) : o(offset) {} Offset64<> Union() const { return o; } bool IsNull() const { return !o; } }; // Litmus check for ensuring the Offsets are the expected size. static_assert(sizeof(Offset<>) == 4, "Offset has wrong size"); static_assert(sizeof(Offset64<>) == 8, "Offset64 has wrong size"); inline void EndianCheck() { int endiantest = 1; // If this fails, see FLATBUFFERS_LITTLEENDIAN above. FLATBUFFERS_ASSERT(*reinterpret_cast(&endiantest) == FLATBUFFERS_LITTLEENDIAN); (void)endiantest; } template FLATBUFFERS_CONSTEXPR size_t AlignOf() { // clang-format off #ifdef _MSC_VER return __alignof(T); #else #ifndef alignof return __alignof__(T); #else return alignof(T); #endif #endif // clang-format on } // Lexicographically compare two strings (possibly containing nulls), and // return true if the first is less than the second. static inline bool StringLessThan(const char *a_data, uoffset_t a_size, const char *b_data, uoffset_t b_size) { const auto cmp = memcmp(a_data, b_data, (std::min)(a_size, b_size)); return cmp == 0 ? a_size < b_size : cmp < 0; } // When we read serialized data from memory, in the case of most scalars, // we want to just read T, but in the case of Offset, we want to actually // perform the indirection and return a pointer. // The template specialization below does just that. // It is wrapped in a struct since function templates can't overload on the // return type like this. // The typedef is for the convenience of callers of this function // (avoiding the need for a trailing return decltype) template struct IndirectHelper { typedef T return_type; typedef T mutable_return_type; static const size_t element_stride = sizeof(T); static return_type Read(const uint8_t *p, const size_t i) { return EndianScalar((reinterpret_cast(p))[i]); } static mutable_return_type Read(uint8_t *p, const size_t i) { return reinterpret_cast( Read(const_cast(p), i)); } }; // For vector of Offsets. template class OffsetT> struct IndirectHelper> { typedef const T *return_type; typedef T *mutable_return_type; typedef typename OffsetT::offset_type offset_type; static const offset_type element_stride = sizeof(offset_type); static return_type Read(const uint8_t *const p, const offset_type i) { // Offsets are relative to themselves, so first update the pointer to // point to the offset location. const uint8_t *const offset_location = p + i * element_stride; // Then read the scalar value of the offset (which may be 32 or 64-bits) and // then determine the relative location from the offset location. return reinterpret_cast( offset_location + ReadScalar(offset_location)); } static mutable_return_type Read(uint8_t *const p, const offset_type i) { // Offsets are relative to themselves, so first update the pointer to // point to the offset location. uint8_t *const offset_location = p + i * element_stride; // Then read the scalar value of the offset (which may be 32 or 64-bits) and // then determine the relative location from the offset location. return reinterpret_cast( offset_location + ReadScalar(offset_location)); } }; // For vector of structs. template struct IndirectHelper { typedef const T *return_type; typedef T *mutable_return_type; static const size_t element_stride = sizeof(T); static return_type Read(const uint8_t *const p, const size_t i) { // Structs are stored inline, relative to the first struct pointer. return reinterpret_cast(p + i * element_stride); } static mutable_return_type Read(uint8_t *const p, const size_t i) { // Structs are stored inline, relative to the first struct pointer. return reinterpret_cast(p + i * element_stride); } }; /// @brief Get a pointer to the file_identifier section of the buffer. /// @return Returns a const char pointer to the start of the file_identifier /// characters in the buffer. The returned char * has length /// 'flatbuffers::FlatBufferBuilder::kFileIdentifierLength'. /// This function is UNDEFINED for FlatBuffers whose schema does not include /// a file_identifier (likely points at padding or the start of a the root /// vtable). inline const char *GetBufferIdentifier(const void *buf, bool size_prefixed = false) { return reinterpret_cast(buf) + ((size_prefixed) ? 2 * sizeof(uoffset_t) : sizeof(uoffset_t)); } // Helper to see if the identifier in a buffer has the expected value. inline bool BufferHasIdentifier(const void *buf, const char *identifier, bool size_prefixed = false) { return strncmp(GetBufferIdentifier(buf, size_prefixed), identifier, flatbuffers::kFileIdentifierLength) == 0; } /// @cond FLATBUFFERS_INTERNAL // Helpers to get a typed pointer to the root object contained in the buffer. template T *GetMutableRoot(void *buf) { if (!buf) return nullptr; EndianCheck(); return reinterpret_cast( reinterpret_cast(buf) + EndianScalar(*reinterpret_cast(buf))); } template T *GetMutableSizePrefixedRoot(void *buf) { return GetMutableRoot(reinterpret_cast(buf) + sizeof(SizeT)); } template const T *GetRoot(const void *buf) { return GetMutableRoot(const_cast(buf)); } template const T *GetSizePrefixedRoot(const void *buf) { return GetRoot(reinterpret_cast(buf) + sizeof(SizeT)); } } // namespace flatbuffers #endif // FLATBUFFERS_BUFFER_H_