| /* | |
| * 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 <algorithm> | |
| #include "flatbuffers/base.h" | |
| #include "flatbuffers/stl_emulation.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 <typename T = void> | |
| 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; } | |
| }; | |
| template <typename T> | |
| struct is_specialisation_of_Offset : false_type {}; | |
| template <typename T> | |
| struct is_specialisation_of_Offset<Offset<T>> : true_type {}; | |
| // Wrapper for uoffset64_t Offsets. | |
| template <typename T = void> | |
| 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; } | |
| }; | |
| template <typename T> | |
| struct is_specialisation_of_Offset64 : false_type {}; | |
| template <typename T> | |
| struct is_specialisation_of_Offset64<Offset64<T>> : true_type {}; | |
| // 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<char*>(&endiantest) == | |
| FLATBUFFERS_LITTLEENDIAN); | |
| (void)endiantest; | |
| } | |
| template <typename T> | |
| 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 <typename T, typename Enable = void> | |
| 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<const T*>(p))[i]); | |
| } | |
| static mutable_return_type Read(uint8_t* p, const size_t i) { | |
| return reinterpret_cast<mutable_return_type>( | |
| Read(const_cast<const uint8_t*>(p), i)); | |
| } | |
| }; | |
| // For vector of Offsets. | |
| template <typename T, template <typename> class OffsetT> | |
| struct IndirectHelper<OffsetT<T>> { | |
| typedef const T* return_type; | |
| typedef T* mutable_return_type; | |
| typedef typename OffsetT<T>::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<return_type>( | |
| offset_location + ReadScalar<offset_type>(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<mutable_return_type>( | |
| offset_location + ReadScalar<offset_type>(offset_location)); | |
| } | |
| }; | |
| // For vector of structs. | |
| template <typename T> | |
| struct IndirectHelper< | |
| T, typename std::enable_if< | |
| !std::is_scalar<typename std::remove_pointer<T>::type>::value && | |
| !is_specialisation_of_Offset<T>::value && | |
| !is_specialisation_of_Offset64<T>::value>::type> { | |
| private: | |
| typedef typename std::remove_pointer<typename std::remove_cv<T>::type>::type | |
| pointee_type; | |
| public: | |
| typedef const pointee_type* return_type; | |
| typedef pointee_type* mutable_return_type; | |
| static const size_t element_stride = sizeof(pointee_type); | |
| 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<return_type>(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<mutable_return_type>(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<const char*>(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 <typename T> | |
| T* GetMutableRoot(void* buf) { | |
| if (!buf) return nullptr; | |
| EndianCheck(); | |
| return reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(buf) + | |
| EndianScalar(*reinterpret_cast<uoffset_t*>(buf))); | |
| } | |
| template <typename T, typename SizeT = uoffset_t> | |
| T* GetMutableSizePrefixedRoot(void* buf) { | |
| return GetMutableRoot<T>(reinterpret_cast<uint8_t*>(buf) + sizeof(SizeT)); | |
| } | |
| template <typename T> | |
| const T* GetRoot(const void* buf) { | |
| return GetMutableRoot<T>(const_cast<void*>(buf)); | |
| } | |
| template <typename T, typename SizeT = uoffset_t> | |
| const T* GetSizePrefixedRoot(const void* buf) { | |
| return GetRoot<T>(reinterpret_cast<const uint8_t*>(buf) + sizeof(SizeT)); | |
| } | |
| } // namespace flatbuffers | |
| #endif // FLATBUFFERS_BUFFER_H_ |