/* * 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_VECTOR_H_ #define FLATBUFFERS_VECTOR_H_ #include "flatbuffers/base.h" #include "flatbuffers/buffer.h" #include "flatbuffers/stl_emulation.h" namespace flatbuffers { struct String; // An STL compatible iterator implementation for Vector below, effectively // calling Get() for every element. template struct VectorIterator { typedef std::random_access_iterator_tag iterator_category; typedef IT value_type; typedef ptrdiff_t difference_type; typedef IT *pointer; typedef IT &reference; VectorIterator(const uint8_t *data, uoffset_t i) : data_(data + IndirectHelper::element_stride * i) {} VectorIterator(const VectorIterator &other) : data_(other.data_) {} VectorIterator() : data_(nullptr) {} VectorIterator &operator=(const VectorIterator &other) { data_ = other.data_; return *this; } VectorIterator &operator=(VectorIterator &&other) { data_ = other.data_; return *this; } bool operator==(const VectorIterator &other) const { return data_ == other.data_; } bool operator<(const VectorIterator &other) const { return data_ < other.data_; } bool operator!=(const VectorIterator &other) const { return data_ != other.data_; } difference_type operator-(const VectorIterator &other) const { return (data_ - other.data_) / IndirectHelper::element_stride; } // Note: return type is incompatible with the standard // `reference operator*()`. IT operator*() const { return IndirectHelper::Read(data_, 0); } // Note: return type is incompatible with the standard // `pointer operator->()`. IT operator->() const { return IndirectHelper::Read(data_, 0); } VectorIterator &operator++() { data_ += IndirectHelper::element_stride; return *this; } VectorIterator operator++(int) { VectorIterator temp(data_, 0); data_ += IndirectHelper::element_stride; return temp; } VectorIterator operator+(const uoffset_t &offset) const { return VectorIterator(data_ + offset * IndirectHelper::element_stride, 0); } VectorIterator &operator+=(const uoffset_t &offset) { data_ += offset * IndirectHelper::element_stride; return *this; } VectorIterator &operator--() { data_ -= IndirectHelper::element_stride; return *this; } VectorIterator operator--(int) { VectorIterator temp(data_, 0); data_ -= IndirectHelper::element_stride; return temp; } VectorIterator operator-(const uoffset_t &offset) const { return VectorIterator(data_ - offset * IndirectHelper::element_stride, 0); } VectorIterator &operator-=(const uoffset_t &offset) { data_ -= offset * IndirectHelper::element_stride; return *this; } private: const uint8_t *data_; }; template struct VectorReverseIterator : public std::reverse_iterator { explicit VectorReverseIterator(Iterator iter) : std::reverse_iterator(iter) {} // Note: return type is incompatible with the standard // `reference operator*()`. typename Iterator::value_type operator*() const { auto tmp = std::reverse_iterator::current; return *--tmp; } // Note: return type is incompatible with the standard // `pointer operator->()`. typename Iterator::value_type operator->() const { auto tmp = std::reverse_iterator::current; return *--tmp; } }; // This is used as a helper type for accessing vectors. // Vector::data() assumes the vector elements start after the length field. template class Vector { public: typedef VectorIterator::mutable_return_type> iterator; typedef VectorIterator::return_type> const_iterator; typedef VectorReverseIterator reverse_iterator; typedef VectorReverseIterator const_reverse_iterator; typedef typename flatbuffers::bool_constant::value> scalar_tag; static FLATBUFFERS_CONSTEXPR bool is_span_observable = scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1); uoffset_t size() const { return EndianScalar(length_); } // Deprecated: use size(). Here for backwards compatibility. FLATBUFFERS_ATTRIBUTE([[deprecated("use size() instead")]]) uoffset_t Length() const { return size(); } typedef typename IndirectHelper::return_type return_type; typedef typename IndirectHelper::mutable_return_type mutable_return_type; typedef return_type value_type; return_type Get(uoffset_t i) const { FLATBUFFERS_ASSERT(i < size()); return IndirectHelper::Read(Data(), i); } return_type operator[](uoffset_t i) const { return Get(i); } // If this is a Vector of enums, T will be its storage type, not the enum // type. This function makes it convenient to retrieve value with enum // type E. template E GetEnum(uoffset_t i) const { return static_cast(Get(i)); } // If this a vector of unions, this does the cast for you. There's no check // to make sure this is the right type! template const U *GetAs(uoffset_t i) const { return reinterpret_cast(Get(i)); } // If this a vector of unions, this does the cast for you. There's no check // to make sure this is actually a string! const String *GetAsString(uoffset_t i) const { return reinterpret_cast(Get(i)); } const void *GetStructFromOffset(size_t o) const { return reinterpret_cast(Data() + o); } iterator begin() { return iterator(Data(), 0); } const_iterator begin() const { return const_iterator(Data(), 0); } iterator end() { return iterator(Data(), size()); } const_iterator end() const { return const_iterator(Data(), size()); } reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } const_iterator cbegin() const { return begin(); } const_iterator cend() const { return end(); } const_reverse_iterator crbegin() const { return rbegin(); } const_reverse_iterator crend() const { return rend(); } // Change elements if you have a non-const pointer to this object. // Scalars only. See reflection.h, and the documentation. void Mutate(uoffset_t i, const T &val) { FLATBUFFERS_ASSERT(i < size()); WriteScalar(data() + i, val); } // Change an element of a vector of tables (or strings). // "val" points to the new table/string, as you can obtain from // e.g. reflection::AddFlatBuffer(). void MutateOffset(uoffset_t i, const uint8_t *val) { FLATBUFFERS_ASSERT(i < size()); static_assert(sizeof(T) == sizeof(uoffset_t), "Unrelated types"); WriteScalar(data() + i, static_cast(val - (Data() + i * sizeof(uoffset_t)))); } // Get a mutable pointer to tables/strings inside this vector. mutable_return_type GetMutableObject(uoffset_t i) const { FLATBUFFERS_ASSERT(i < size()); return const_cast(IndirectHelper::Read(Data(), i)); } // The raw data in little endian format. Use with care. const uint8_t *Data() const { return reinterpret_cast(&length_ + 1); } uint8_t *Data() { return reinterpret_cast(&length_ + 1); } // Similarly, but typed, much like std::vector::data const T *data() const { return reinterpret_cast(Data()); } T *data() { return reinterpret_cast(Data()); } template return_type LookupByKey(K key) const { void *search_result = std::bsearch( &key, Data(), size(), IndirectHelper::element_stride, KeyCompare); if (!search_result) { return nullptr; // Key not found. } const uint8_t *element = reinterpret_cast(search_result); return IndirectHelper::Read(element, 0); } template mutable_return_type MutableLookupByKey(K key) { return const_cast(LookupByKey(key)); } protected: // This class is only used to access pre-existing data. Don't ever // try to construct these manually. Vector(); uoffset_t length_; private: // This class is a pointer. Copying will therefore create an invalid object. // Private and unimplemented copy constructor. Vector(const Vector &); Vector &operator=(const Vector &); template static int KeyCompare(const void *ap, const void *bp) { const K *key = reinterpret_cast(ap); const uint8_t *data = reinterpret_cast(bp); auto table = IndirectHelper::Read(data, 0); // std::bsearch compares with the operands transposed, so we negate the // result here. return -table->KeyCompareWithValue(*key); } }; template FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span(Vector &vec) FLATBUFFERS_NOEXCEPT { static_assert(Vector::is_span_observable, "wrong type U, only LE-scalar, or byte types are allowed"); return span(vec.data(), vec.size()); } template FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span( const Vector &vec) FLATBUFFERS_NOEXCEPT { static_assert(Vector::is_span_observable, "wrong type U, only LE-scalar, or byte types are allowed"); return span(vec.data(), vec.size()); } template FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_bytes_span( Vector &vec) FLATBUFFERS_NOEXCEPT { static_assert(Vector::scalar_tag::value, "wrong type U, only LE-scalar, or byte types are allowed"); return span(vec.Data(), vec.size() * sizeof(U)); } template FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_bytes_span( const Vector &vec) FLATBUFFERS_NOEXCEPT { static_assert(Vector::scalar_tag::value, "wrong type U, only LE-scalar, or byte types are allowed"); return span(vec.Data(), vec.size() * sizeof(U)); } // Convenient helper functions to get a span of any vector, regardless // of whether it is null or not (the field is not set). template FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span(Vector *ptr) FLATBUFFERS_NOEXCEPT { static_assert(Vector::is_span_observable, "wrong type U, only LE-scalar, or byte types are allowed"); return ptr ? make_span(*ptr) : span(); } template FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span( const Vector *ptr) FLATBUFFERS_NOEXCEPT { static_assert(Vector::is_span_observable, "wrong type U, only LE-scalar, or byte types are allowed"); return ptr ? make_span(*ptr) : span(); } // Represent a vector much like the template above, but in this case we // don't know what the element types are (used with reflection.h). class VectorOfAny { public: uoffset_t size() const { return EndianScalar(length_); } const uint8_t *Data() const { return reinterpret_cast(&length_ + 1); } uint8_t *Data() { return reinterpret_cast(&length_ + 1); } protected: VectorOfAny(); uoffset_t length_; private: VectorOfAny(const VectorOfAny &); VectorOfAny &operator=(const VectorOfAny &); }; template Vector> *VectorCast(Vector> *ptr) { static_assert(std::is_base_of::value, "Unrelated types"); return reinterpret_cast> *>(ptr); } template const Vector> *VectorCast(const Vector> *ptr) { static_assert(std::is_base_of::value, "Unrelated types"); return reinterpret_cast> *>(ptr); } // Convenient helper function to get the length of any vector, regardless // of whether it is null or not (the field is not set). template static inline size_t VectorLength(const Vector *v) { return v ? v->size() : 0; } } // namespace flatbuffers #endif // FLATBUFFERS_VERIFIER_H_