Add support for fixed-size arrays (#5313)

This commit is contained in:
svenk177
2019-06-18 00:15:13 +02:00
committed by Wouter van Oortmerssen
parent 0d2cebccfe
commit e635141d5b
40 changed files with 2113 additions and 220 deletions

View File

@@ -395,6 +395,83 @@ template<typename T> static inline size_t VectorLength(const Vector<T> *v) {
return v ? v->size() : 0;
}
// This is used as a helper type for accessing arrays.
template<typename T, uint16_t length> class Array {
public:
typedef VectorIterator<T, typename IndirectHelper<T>::return_type>
const_iterator;
typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
typedef typename IndirectHelper<T>::return_type return_type;
FLATBUFFERS_CONSTEXPR uint16_t size() const { return length; }
return_type Get(uoffset_t i) const {
FLATBUFFERS_ASSERT(i < size());
return IndirectHelper<T>::Read(Data(), i);
}
return_type operator[](uoffset_t i) const { return Get(i); }
const_iterator begin() const { return const_iterator(Data(), 0); }
const_iterator end() const { return const_iterator(Data(), size()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const { return const_reverse_iterator(end()); }
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.
void Mutate(uoffset_t i, const T &val) {
FLATBUFFERS_ASSERT(i < size());
WriteScalar(data() + i, val);
}
// Get a mutable pointer to elements inside this array.
// @note This method should be only used to mutate arrays of structs followed
// by a @p Mutate operation. For primitive types use @p Mutate directly.
// @warning Assignments and reads to/from the dereferenced pointer are not
// automatically converted to the correct endianness.
T *GetMutablePointer(uoffset_t i) const {
FLATBUFFERS_ASSERT(i < size());
return const_cast<T *>(&data()[i]);
}
// The raw data in little endian format. Use with care.
const uint8_t *Data() const { return data_; }
uint8_t *Data() { return data_; }
// 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()); }
protected:
// This class is only used to access pre-existing data. Don't ever
// try to construct these manually.
// 'constexpr' allows us to use 'size()' at compile time.
// @note Must not use 'FLATBUFFERS_CONSTEXPR' here, as const is not allowed on
// a constructor.
#if defined(__cpp_constexpr)
constexpr Array();
#else
Array();
#endif
uint8_t data_[length * sizeof(T)];
private:
// This class is a pointer. Copying will therefore create an invalid object.
// Private and unimplemented copy constructor.
Array(const Array &);
};
// 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,

View File

@@ -65,7 +65,8 @@ namespace flatbuffers {
TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int, unused) \
TD(STRUCT, "", Offset<void>, int, int, int, int, unused) \
TD(UNION, "", Offset<void>, int, int, int, int, unused)
#define FLATBUFFERS_GEN_TYPE_ARRAY(TD) \
TD(ARRAY, "", int, int, int, int, int, unused)
// The fields are:
// - enum
// - FlatBuffers schema type.
@@ -91,7 +92,8 @@ switch (type) {
#define FLATBUFFERS_GEN_TYPES(TD) \
FLATBUFFERS_GEN_TYPES_SCALAR(TD) \
FLATBUFFERS_GEN_TYPES_POINTER(TD)
FLATBUFFERS_GEN_TYPES_POINTER(TD) \
FLATBUFFERS_GEN_TYPE_ARRAY(TD)
// Create an enum for all the types above.
#ifdef __GNUC__
@@ -145,18 +147,21 @@ class Parser;
// and additional information for vectors/structs_.
struct Type {
explicit Type(BaseType _base_type = BASE_TYPE_NONE, StructDef *_sd = nullptr,
EnumDef *_ed = nullptr)
EnumDef *_ed = nullptr, uint16_t _fixed_length = 0)
: base_type(_base_type),
element(BASE_TYPE_NONE),
struct_def(_sd),
enum_def(_ed) {}
enum_def(_ed),
fixed_length(_fixed_length) {}
bool operator==(const Type &o) {
return base_type == o.base_type && element == o.element &&
struct_def == o.struct_def && enum_def == o.enum_def;
}
Type VectorType() const { return Type(element, struct_def, enum_def); }
Type VectorType() const {
return Type(element, struct_def, enum_def, fixed_length);
}
Offset<reflection::Type> Serialize(FlatBufferBuilder *builder) const;
@@ -167,6 +172,7 @@ struct Type {
StructDef *struct_def; // only set if t or element == BASE_TYPE_STRUCT
EnumDef *enum_def; // set if t == BASE_TYPE_UNION / BASE_TYPE_UTYPE,
// or for an integral type derived from an enum.
uint16_t fixed_length; // only set if t == BASE_TYPE_ARRAY
};
// Represents a parsed scalar value, it's type, and field offset.
@@ -335,12 +341,34 @@ inline bool IsStruct(const Type &type) {
return type.base_type == BASE_TYPE_STRUCT && type.struct_def->fixed;
}
inline bool IsVector(const Type &type) {
return type.base_type == BASE_TYPE_VECTOR;
}
inline bool IsArray(const Type &type) {
return type.base_type == BASE_TYPE_ARRAY;
}
inline bool IsSeries(const Type &type) {
return IsVector(type) || IsArray(type);
}
inline bool IsEnum(const Type &type) {
return type.enum_def != nullptr && IsInteger(type.base_type);
}
inline size_t InlineSize(const Type &type) {
return IsStruct(type) ? type.struct_def->bytesize : SizeOf(type.base_type);
return IsStruct(type)
? type.struct_def->bytesize
: (IsArray(type)
? InlineSize(type.VectorType()) * type.fixed_length
: SizeOf(type.base_type));
}
inline size_t InlineAlignment(const Type &type) {
return IsStruct(type) ? type.struct_def->minalign : SizeOf(type.base_type);
return IsStruct(type)
? type.struct_def->minalign
: (SizeOf(IsArray(type) ? type.element : type.base_type));
}
struct EnumDef;
@@ -799,10 +827,13 @@ class Parser : public ParserState {
FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def,
std::string *value, uoffset_t *ovalue);
void SerializeStruct(const StructDef &struct_def, const Value &val);
void SerializeStruct(FlatBufferBuilder &builder, const StructDef &struct_def,
const Value &val);
template<typename F>
FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(uoffset_t &count, F body);
FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue,
FieldDef *field, size_t fieldn);
FLATBUFFERS_CHECKED_ERROR ParseArray(Value &array);
FLATBUFFERS_CHECKED_ERROR ParseNestedFlatbuffer(Value &val, FieldDef *field,
size_t fieldn,
const StructDef *parent_struct_def);
@@ -849,6 +880,7 @@ class Parser : public ParserState {
BaseType baseType);
bool SupportsAdvancedUnionFeatures() const;
bool SupportsAdvancedArrayFeatures() const;
Namespace *UniqueNamespace(Namespace *ns);
FLATBUFFERS_CHECKED_ERROR RecurseError();

View File

@@ -43,10 +43,11 @@ enum BaseType {
String = 13,
Vector = 14,
Obj = 15,
Union = 16
Union = 16,
Array = 17
};
inline const BaseType (&EnumValuesBaseType())[17] {
inline const BaseType (&EnumValuesBaseType())[18] {
static const BaseType values[] = {
None,
UType,
@@ -64,13 +65,14 @@ inline const BaseType (&EnumValuesBaseType())[17] {
String,
Vector,
Obj,
Union
Union,
Array
};
return values;
}
inline const char * const *EnumNamesBaseType() {
static const char * const names[18] = {
static const char * const names[19] = {
"None",
"UType",
"Bool",
@@ -88,13 +90,14 @@ inline const char * const *EnumNamesBaseType() {
"Vector",
"Obj",
"Union",
"Array",
nullptr
};
return names;
}
inline const char *EnumNameBaseType(BaseType e) {
if (e < None || e > Union) return "";
if (e < None || e > Array) return "";
const size_t index = static_cast<size_t>(e);
return EnumNamesBaseType()[index];
}
@@ -103,7 +106,8 @@ struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_BASE_TYPE = 4,
VT_ELEMENT = 6,
VT_INDEX = 8
VT_INDEX = 8,
VT_FIXED_LENGTH = 10
};
reflection::BaseType base_type() const {
return static_cast<reflection::BaseType>(GetField<int8_t>(VT_BASE_TYPE, 0));
@@ -114,11 +118,15 @@ struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
int32_t index() const {
return GetField<int32_t>(VT_INDEX, -1);
}
uint16_t fixed_length() const {
return GetField<uint16_t>(VT_FIXED_LENGTH, 0);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<int8_t>(verifier, VT_BASE_TYPE) &&
VerifyField<int8_t>(verifier, VT_ELEMENT) &&
VerifyField<int32_t>(verifier, VT_INDEX) &&
VerifyField<uint16_t>(verifier, VT_FIXED_LENGTH) &&
verifier.EndTable();
}
};
@@ -135,6 +143,9 @@ struct TypeBuilder {
void add_index(int32_t index) {
fbb_.AddElement<int32_t>(Type::VT_INDEX, index, -1);
}
void add_fixed_length(uint16_t fixed_length) {
fbb_.AddElement<uint16_t>(Type::VT_FIXED_LENGTH, fixed_length, 0);
}
explicit TypeBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
@@ -151,9 +162,11 @@ inline flatbuffers::Offset<Type> CreateType(
flatbuffers::FlatBufferBuilder &_fbb,
reflection::BaseType base_type = reflection::None,
reflection::BaseType element = reflection::None,
int32_t index = -1) {
int32_t index = -1,
uint16_t fixed_length = 0) {
TypeBuilder builder_(_fbb);
builder_.add_index(index);
builder_.add_fixed_length(fixed_length);
builder_.add_element(element);
builder_.add_base_type(base_type);
return builder_.Finish();