forked from BigfootDev/flatbuffers
* First working hack of adding 64-bit. Don't judge :) * Made vector_downward work on 64 bit types * vector_downward uses size_t, added offset64 to reflection * cleaned up adding offset64 in parser * Add C++ testing skeleton for 64-bit * working test for CreateVector64 * working >2 GiB buffers * support for large strings * simplified CreateString<> to just provide the offset type * generalize CreateVector template * update test_64.afb due to upstream format change * Added Vector64 type, which is just an alias for vector ATM * Switch to Offset64 for Vector64 * Update for reflection bfbs output change * Starting to add support for vector64 type in C++ * made a generic CreateVector that can handle different offsets and vector types * Support for 32-vector with 64-addressing * Vector64 basic builder + tests working * basic support for json vector64 support * renamed fields in test_64bit.fbs to better reflect their use * working C++ vector64 builder * Apply --annotate-sparse-vector to 64-bit tests * Enable Vector64 for --annotate-sparse-vectors * Merged from upstream * Add `near_string` field for testing 32-bit offsets alongside * keep track of where the 32-bit and 64-bit regions are for flatbufferbuilder * move template<> outside class body for GCC * update run.sh to build and run tests * basic assertion for adding 64-bit offset at the wrong time * started to separate `FlatBufferBuilder` into two classes, 1 64-bit aware, the other not * add test for nested flatbuffer vector64, fix bug in alignment of big vectors * fixed CreateDirect method by iterating by Offset64 first * internal refactoring of flatbufferbuilder * block not supported languages in the parser from using 64-bit * evolution tests for adding a vector64 field * conformity tests for adding/removing offset64 attributes * ensure test is for a big buffer * add parser error tests for `offset64` and `vector64` attributes * add missing static that GCC only complains about * remove stdint-uintn.h header that gets automatically added * move 64-bit CalculateOffset internal * fixed return size of EndVector * various fixes on windows * add SizeT to vector_downward * minimze range of size changes in vector and builder * reworked how tracking if 64-offsets are added * Add ReturnT to EndVector * small cleanups * remove need for second Array definition * combine IndirectHelpers into one definition * started support for vector of struct * Support for 32/64-vectors of structs + Offset64 * small cleanups * add verification for vector64 * add sized prefix for 64-bit buffers * add fuzzer for 64-bit * add example of adding many vectors using a wrapper table * run the new -bfbs-gen-embed logic on the 64-bit tests * remove run.sh and fix cmakelist issue * fixed bazel rules * fixed some PR comments * add 64-bit tests to cmakelist
401 lines
13 KiB
C++
401 lines
13 KiB
C++
/*
|
|
* 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<typename T, typename IT, typename Data = uint8_t *,
|
|
typename SizeT = uoffset_t>
|
|
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;
|
|
|
|
static const SizeT element_stride = IndirectHelper<T>::element_stride;
|
|
|
|
VectorIterator(Data data, SizeT i) : data_(data + 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_) / element_stride;
|
|
}
|
|
|
|
// Note: return type is incompatible with the standard
|
|
// `reference operator*()`.
|
|
IT operator*() const { return IndirectHelper<T>::Read(data_, 0); }
|
|
|
|
// Note: return type is incompatible with the standard
|
|
// `pointer operator->()`.
|
|
IT operator->() const { return IndirectHelper<T>::Read(data_, 0); }
|
|
|
|
VectorIterator &operator++() {
|
|
data_ += element_stride;
|
|
return *this;
|
|
}
|
|
|
|
VectorIterator operator++(int) {
|
|
VectorIterator temp(data_, 0);
|
|
data_ += element_stride;
|
|
return temp;
|
|
}
|
|
|
|
VectorIterator operator+(const SizeT &offset) const {
|
|
return VectorIterator(data_ + offset * element_stride, 0);
|
|
}
|
|
|
|
VectorIterator &operator+=(const SizeT &offset) {
|
|
data_ += offset * element_stride;
|
|
return *this;
|
|
}
|
|
|
|
VectorIterator &operator--() {
|
|
data_ -= element_stride;
|
|
return *this;
|
|
}
|
|
|
|
VectorIterator operator--(int) {
|
|
VectorIterator temp(data_, 0);
|
|
data_ -= element_stride;
|
|
return temp;
|
|
}
|
|
|
|
VectorIterator operator-(const SizeT &offset) const {
|
|
return VectorIterator(data_ - offset * element_stride, 0);
|
|
}
|
|
|
|
VectorIterator &operator-=(const SizeT &offset) {
|
|
data_ -= offset * element_stride;
|
|
return *this;
|
|
}
|
|
|
|
private:
|
|
Data data_;
|
|
};
|
|
|
|
template<typename T, typename IT, typename SizeT = uoffset_t>
|
|
using VectorConstIterator = VectorIterator<T, IT, const uint8_t *, SizeT>;
|
|
|
|
template<typename Iterator>
|
|
struct VectorReverseIterator : public std::reverse_iterator<Iterator> {
|
|
explicit VectorReverseIterator(Iterator iter)
|
|
: std::reverse_iterator<Iterator>(iter) {}
|
|
|
|
// Note: return type is incompatible with the standard
|
|
// `reference operator*()`.
|
|
typename Iterator::value_type operator*() const {
|
|
auto tmp = std::reverse_iterator<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<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<typename T, typename SizeT = uoffset_t> class Vector {
|
|
public:
|
|
typedef VectorIterator<T,
|
|
typename IndirectHelper<T>::mutable_return_type,
|
|
uint8_t *, SizeT>
|
|
iterator;
|
|
typedef VectorConstIterator<T, typename IndirectHelper<T>::return_type,
|
|
SizeT>
|
|
const_iterator;
|
|
typedef VectorReverseIterator<iterator> reverse_iterator;
|
|
typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
|
|
|
|
typedef typename flatbuffers::bool_constant<flatbuffers::is_scalar<T>::value>
|
|
scalar_tag;
|
|
|
|
static FLATBUFFERS_CONSTEXPR bool is_span_observable =
|
|
scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1);
|
|
|
|
SizeT size() const { return EndianScalar(length_); }
|
|
|
|
// Deprecated: use size(). Here for backwards compatibility.
|
|
FLATBUFFERS_ATTRIBUTE([[deprecated("use size() instead")]])
|
|
SizeT Length() const { return size(); }
|
|
|
|
typedef SizeT size_type;
|
|
typedef typename IndirectHelper<T>::return_type return_type;
|
|
typedef typename IndirectHelper<T>::mutable_return_type
|
|
mutable_return_type;
|
|
typedef return_type value_type;
|
|
|
|
return_type Get(SizeT i) const {
|
|
FLATBUFFERS_ASSERT(i < size());
|
|
return IndirectHelper<T>::Read(Data(), i);
|
|
}
|
|
|
|
return_type operator[](SizeT 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<typename E> E GetEnum(SizeT i) const {
|
|
return static_cast<E>(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<typename U> const U *GetAs(SizeT i) const {
|
|
return reinterpret_cast<const U *>(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(SizeT i) const {
|
|
return reinterpret_cast<const String *>(Get(i));
|
|
}
|
|
|
|
const void *GetStructFromOffset(size_t o) const {
|
|
return reinterpret_cast<const void *>(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(SizeT 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(SizeT i, const uint8_t *val) {
|
|
FLATBUFFERS_ASSERT(i < size());
|
|
static_assert(sizeof(T) == sizeof(SizeT), "Unrelated types");
|
|
WriteScalar(data() + i,
|
|
static_cast<SizeT>(val - (Data() + i * sizeof(SizeT))));
|
|
}
|
|
|
|
// Get a mutable pointer to tables/strings inside this vector.
|
|
mutable_return_type GetMutableObject(SizeT i) const {
|
|
FLATBUFFERS_ASSERT(i < size());
|
|
return const_cast<mutable_return_type>(IndirectHelper<T>::Read(Data(), i));
|
|
}
|
|
|
|
// The raw data in little endian format. Use with care.
|
|
const uint8_t *Data() const {
|
|
return reinterpret_cast<const uint8_t *>(&length_ + 1);
|
|
}
|
|
|
|
uint8_t *Data() { return reinterpret_cast<uint8_t *>(&length_ + 1); }
|
|
|
|
// Similarly, but typed, much like std::vector::data
|
|
const T *data() const { return reinterpret_cast<const T *>(Data()); }
|
|
T *data() { return reinterpret_cast<T *>(Data()); }
|
|
|
|
template<typename K> return_type LookupByKey(K key) const {
|
|
void *search_result = std::bsearch(
|
|
&key, Data(), size(), IndirectHelper<T>::element_stride, KeyCompare<K>);
|
|
|
|
if (!search_result) {
|
|
return nullptr; // Key not found.
|
|
}
|
|
|
|
const uint8_t *element = reinterpret_cast<const uint8_t *>(search_result);
|
|
|
|
return IndirectHelper<T>::Read(element, 0);
|
|
}
|
|
|
|
template<typename K> mutable_return_type MutableLookupByKey(K key) {
|
|
return const_cast<mutable_return_type>(LookupByKey(key));
|
|
}
|
|
|
|
protected:
|
|
// This class is only used to access pre-existing data. Don't ever
|
|
// try to construct these manually.
|
|
Vector();
|
|
|
|
SizeT 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<typename K> static int KeyCompare(const void *ap, const void *bp) {
|
|
const K *key = reinterpret_cast<const K *>(ap);
|
|
const uint8_t *data = reinterpret_cast<const uint8_t *>(bp);
|
|
auto table = IndirectHelper<T>::Read(data, 0);
|
|
|
|
// std::bsearch compares with the operands transposed, so we negate the
|
|
// result here.
|
|
return -table->KeyCompareWithValue(*key);
|
|
}
|
|
};
|
|
|
|
template<typename T> using Vector64 = Vector<T, uoffset64_t>;
|
|
|
|
template<class U>
|
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U> make_span(Vector<U> &vec)
|
|
FLATBUFFERS_NOEXCEPT {
|
|
static_assert(Vector<U>::is_span_observable,
|
|
"wrong type U, only LE-scalar, or byte types are allowed");
|
|
return span<U>(vec.data(), vec.size());
|
|
}
|
|
|
|
template<class U>
|
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U> make_span(
|
|
const Vector<U> &vec) FLATBUFFERS_NOEXCEPT {
|
|
static_assert(Vector<U>::is_span_observable,
|
|
"wrong type U, only LE-scalar, or byte types are allowed");
|
|
return span<const U>(vec.data(), vec.size());
|
|
}
|
|
|
|
template<class U>
|
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<uint8_t> make_bytes_span(
|
|
Vector<U> &vec) FLATBUFFERS_NOEXCEPT {
|
|
static_assert(Vector<U>::scalar_tag::value,
|
|
"wrong type U, only LE-scalar, or byte types are allowed");
|
|
return span<uint8_t>(vec.Data(), vec.size() * sizeof(U));
|
|
}
|
|
|
|
template<class U>
|
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const uint8_t> make_bytes_span(
|
|
const Vector<U> &vec) FLATBUFFERS_NOEXCEPT {
|
|
static_assert(Vector<U>::scalar_tag::value,
|
|
"wrong type U, only LE-scalar, or byte types are allowed");
|
|
return span<const uint8_t>(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<class U>
|
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U> make_span(Vector<U> *ptr)
|
|
FLATBUFFERS_NOEXCEPT {
|
|
static_assert(Vector<U>::is_span_observable,
|
|
"wrong type U, only LE-scalar, or byte types are allowed");
|
|
return ptr ? make_span(*ptr) : span<U>();
|
|
}
|
|
|
|
template<class U>
|
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U> make_span(
|
|
const Vector<U> *ptr) FLATBUFFERS_NOEXCEPT {
|
|
static_assert(Vector<U>::is_span_observable,
|
|
"wrong type U, only LE-scalar, or byte types are allowed");
|
|
return ptr ? make_span(*ptr) : span<const U>();
|
|
}
|
|
|
|
// 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<const uint8_t *>(&length_ + 1);
|
|
}
|
|
uint8_t *Data() { return reinterpret_cast<uint8_t *>(&length_ + 1); }
|
|
|
|
protected:
|
|
VectorOfAny();
|
|
|
|
uoffset_t length_;
|
|
|
|
private:
|
|
VectorOfAny(const VectorOfAny &);
|
|
VectorOfAny &operator=(const VectorOfAny &);
|
|
};
|
|
|
|
template<typename T, typename U>
|
|
Vector<Offset<T>> *VectorCast(Vector<Offset<U>> *ptr) {
|
|
static_assert(std::is_base_of<T, U>::value, "Unrelated types");
|
|
return reinterpret_cast<Vector<Offset<T>> *>(ptr);
|
|
}
|
|
|
|
template<typename T, typename U>
|
|
const Vector<Offset<T>> *VectorCast(const Vector<Offset<U>> *ptr) {
|
|
static_assert(std::is_base_of<T, U>::value, "Unrelated types");
|
|
return reinterpret_cast<const Vector<Offset<T>> *>(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<typename T> static inline size_t VectorLength(const Vector<T> *v) {
|
|
return v ? v->size() : 0;
|
|
}
|
|
|
|
} // namespace flatbuffers
|
|
|
|
#endif // FLATBUFFERS_VERIFIER_H_
|