Skip to content

Commit

Permalink
Add support for fixed-size arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
svenk177 committed Jun 17, 2019
1 parent a80db85 commit fd227ae
Show file tree
Hide file tree
Showing 40 changed files with 2,117 additions and 222 deletions.
1 change: 1 addition & 0 deletions .appveyor/check-generate-code.bat
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ call generate_code.bat -b %buildtype% || goto FAIL

:: TODO: Release and Debug builds produce differences here for some reason.
git checkout HEAD -- monster_test.bfbs
git checkout HEAD -- arrays_test.bfbs

git -c core.autocrlf=true diff --exit-code --quiet || goto :DIFFFOUND
goto SUCCESS
Expand Down
1 change: 1 addition & 0 deletions .travis/check-generate-code.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ cd ..

# TODO: Linux and macos builds produce differences here for some reason.
git checkout HEAD -- tests/monster_test.bfbs
git checkout HEAD -- tests/arrays_test.bfbs

if ! git diff --quiet; then
echo >&2
Expand Down
17 changes: 17 additions & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,15 @@ cc_test(
":tests/union_vector/union_vector.json",
":tests/monster_extra.fbs",
":tests/monsterdata_extra.json",
":tests/arrays_test.bfbs",
":tests/arrays_test.fbs",
":tests/arrays_test.golden",
],
includes = ["include/"],
deps = [
":monster_extra_cc_fbs",
":monster_test_cc_fbs",
":arrays_test_cc_fbs",
],
)

Expand All @@ -188,3 +192,16 @@ flatbuffer_cc_library(
name = "monster_extra_cc_fbs",
srcs = ["tests/monster_extra.fbs"],
)

flatbuffer_cc_library(
name = "arrays_test_cc_fbs",
srcs = ["tests/arrays_test.fbs"],
flatc_args = [
"--gen-object-api",
"--gen-compare",
"--no-includes",
"--gen-mutable",
"--reflect-names",
"--cpp-ptr-type flatbuffers::unique_ptr",
"--scoped-enums" ],
)
11 changes: 9 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ set(FlatBuffers_Tests_SRCS
tests/test_builder.cpp
# file generate by running compiler on tests/monster_test.fbs
${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h
# file generate by running compiler on tests/arrays_test.fbs
${CMAKE_CURRENT_BINARY_DIR}/tests/arrays_test_generated.h
)

set(FlatBuffers_Sample_Binary_SRCS
Expand Down Expand Up @@ -303,20 +305,24 @@ if(FLATBUFFERS_BUILD_SHAREDLIB)
VERSION "${FlatBuffers_Library_SONAME_FULL}")
endif()

function(compile_flatbuffers_schema_to_cpp SRC_FBS)
function(compile_flatbuffers_schema_to_cpp_opt SRC_FBS OPT)
get_filename_component(SRC_FBS_DIR ${SRC_FBS} PATH)
string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
add_custom_command(
OUTPUT ${GEN_HEADER}
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable
--gen-object-api --gen-compare -o "${SRC_FBS_DIR}"
--cpp-ptr-type flatbuffers::unique_ptr # Used to test with C++98 STLs
--reflect-names
--reflect-names ${OPT}
-I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test"
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
DEPENDS flatc)
endfunction()

function(compile_flatbuffers_schema_to_cpp SRC_FBS)
compile_flatbuffers_schema_to_cpp_opt(${SRC_FBS} "")
endfunction()

function(compile_flatbuffers_schema_to_binary SRC_FBS)
get_filename_component(SRC_FBS_DIR ${SRC_FBS} PATH)
string(REGEX REPLACE "\\.fbs$" ".bfbs" GEN_BINARY_SCHEMA ${SRC_FBS})
Expand All @@ -329,6 +335,7 @@ endfunction()

if(FLATBUFFERS_BUILD_TESTS)
compile_flatbuffers_schema_to_cpp(tests/monster_test.fbs)
compile_flatbuffers_schema_to_cpp_opt(tests/arrays_test.fbs --scoped-enums)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/tests)
add_executable(flattests ${FlatBuffers_Tests_SRCS})
set_property(TARGET flattests
Expand Down
21 changes: 21 additions & 0 deletions docs/source/Schemas.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,27 @@ of same-size data where a `reinterpret_cast` would give you a desirable result,
e.g. you could change a `uint` to an `int` if no values in current data use the
high bit yet.

### Arrays

Arrays are a convenience short-hand for a fixed-length collection of elements.
Arrays can be used to replace the following schema:

struct Vec3 {
x:float;
y:float;
z:float;
}

with the following schema:

struct Vec3 {
v:[float:3];
}

Both representations are binary equivalent.

Arrays are currently only supported in a `struct`.

### (Default) Values

Values are a sequence of digits. Values may be optionally followed by a decimal
Expand Down
77 changes: 77 additions & 0 deletions include/flatbuffers/flatbuffers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
46 changes: 39 additions & 7 deletions include/flatbuffers/idl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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__
Expand Down Expand Up @@ -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;

Expand All @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -849,6 +880,7 @@ class Parser : public ParserState {
BaseType baseType);

bool SupportsAdvancedUnionFeatures() const;
bool SupportsAdvancedArrayFeatures() const;
Namespace *UniqueNamespace(Namespace *ns);

FLATBUFFERS_CHECKED_ERROR RecurseError();
Expand Down
Loading

0 comments on commit fd227ae

Please sign in to comment.