[C++] Enable using struct and array of struct as key (#7741)

* add unit tests for support struct as key

* make changes to parser and add helper function to generate comparator for struct

* implement

* add more unit tests

* format

* just a test

* test done

* rerun generator

* restore build file

* address comment

* format

* rebase

* rebase

* add more unit tests

* rerun generator

* address some comments

* address comment

* update

* format

* address comment

Co-authored-by: Wen Sun <sunwen@google.com>
Co-authored-by: Derek Bailey <derekbailey@google.com>
This commit is contained in:
Wen Sun 2023-01-24 16:37:13 -08:00 committed by GitHub
parent ee848a02e1
commit 802a3a056a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 853 additions and 37 deletions

View File

@ -2245,54 +2245,147 @@ class CppGenerator : public BaseGenerator {
}
}
void GenComparatorForStruct(const StructDef &struct_def, size_t space_size,
const std::string lhs_struct_literal,
const std::string rhs_struct_literal) {
code_.SetValue("LHS_PREFIX", lhs_struct_literal);
code_.SetValue("RHS_PREFIX", rhs_struct_literal);
std::string space(space_size, ' ');
for (const auto &curr_field : struct_def.fields.vec) {
const auto curr_field_name = Name(*curr_field);
code_.SetValue("CURR_FIELD_NAME", curr_field_name);
code_.SetValue("LHS", lhs_struct_literal + "_" + curr_field_name);
code_.SetValue("RHS", rhs_struct_literal + "_" + curr_field_name);
const bool is_scalar = IsScalar(curr_field->value.type.base_type);
const bool is_array = IsArray(curr_field->value.type);
const bool is_struct = IsStruct(curr_field->value.type);
// If encouter a key field, call KeyCompareWithValue to compare this field.
if (curr_field->key) {
code_ +=
space + "const auto {{RHS}} = {{RHS_PREFIX}}.{{CURR_FIELD_NAME}}();";
code_ += space + "const auto {{CURR_FIELD_NAME}}_compare_result = {{LHS_PREFIX}}.KeyCompareWithValue({{RHS}});";
code_ += space + "if ({{CURR_FIELD_NAME}}_compare_result != 0)";
code_ += space + " return {{CURR_FIELD_NAME}}_compare_result;";
continue;
}
code_ +=
space + "const auto {{LHS}} = {{LHS_PREFIX}}.{{CURR_FIELD_NAME}}();";
code_ +=
space + "const auto {{RHS}} = {{RHS_PREFIX}}.{{CURR_FIELD_NAME}}();";
if (is_scalar) {
code_ += space + "if ({{LHS}} != {{RHS}})";
code_ += space +
" return static_cast<int>({{LHS}} > {{RHS}}) - "
"static_cast<int>({{LHS}} < {{RHS}});";
} else if (is_array) {
const auto &elem_type = curr_field->value.type.VectorType();
code_ +=
space +
"for (::flatbuffers::uoffset_t i = 0; i < {{LHS}}->size(); i++) {";
code_ += space + " const auto {{LHS}}_elem = {{LHS}}->Get(i);";
code_ += space + " const auto {{RHS}}_elem = {{RHS}}->Get(i);";
if (IsScalar(elem_type.base_type)) {
code_ += space + " if ({{LHS}}_elem != {{RHS}}_elem)";
code_ += space +
" return static_cast<int>({{LHS}}_elem > {{RHS}}_elem) - "
"static_cast<int>({{LHS}}_elem < {{RHS}}_elem);";
code_ += space + "}";
} else if (IsStruct(elem_type)) {
if (curr_field->key) {
code_ += space + "const auto {{CURR_FIELD_NAME}}_compare_result = {{LHS_PREFIX}}.KeyCompareWithValue({{RHS}});";
code_ += space + "if ({{CURR_FIELD_NAME}}_compare_result != 0)";
code_ += space + " return {{CURR_FIELD_NAME}}_compare_result;";
continue;
}
GenComparatorForStruct(
*curr_field->value.type.struct_def, space_size + 2,
code_.GetValue("LHS") + "_elem", code_.GetValue("RHS") + "_elem");
code_ += space + "}";
}
} else if (is_struct) {
GenComparatorForStruct(*curr_field->value.type.struct_def, space_size,
code_.GetValue("LHS"), code_.GetValue("RHS"));
}
}
}
// Generate CompareWithValue method for a key field.
void GenKeyFieldMethods(const FieldDef &field) {
FLATBUFFERS_ASSERT(field.key);
const bool is_string = IsString(field.value.type);
const bool is_array = IsArray(field.value.type);
const bool is_struct = IsStruct(field.value.type);
// Generate KeyCompareLessThan function
code_ +=
" bool KeyCompareLessThan(const {{STRUCT_NAME}} * const o) const {";
if (is_string) {
// use operator< of ::flatbuffers::String
code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
} else if (is_array) {
const auto &elem_type = field.value.type.VectorType();
if (IsScalar(elem_type.base_type)) {
code_ += " return KeyCompareWithValue(o->{{FIELD_NAME}}()) < 0;";
}
} else {
} else if (is_array || is_struct) {
code_ += " return KeyCompareWithValue(o->{{FIELD_NAME}}()) < 0;";
}else {
code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
}
code_ += " }";
// Generate KeyCompareWithValue function
if (is_string) {
code_ += " int KeyCompareWithValue(const char *_{{FIELD_NAME}}) const {";
code_ += " return strcmp({{FIELD_NAME}}()->c_str(), _{{FIELD_NAME}});";
} else if (is_array) {
const auto &elem_type = field.value.type.VectorType();
std::string input_type = "::flatbuffers::Array<" +
GenTypeGet(elem_type, "", "", " ", false) +
", " + NumToString(elem_type.fixed_length) + ">";
code_.SetValue("INPUT_TYPE", input_type);
code_ +=
" int KeyCompareWithValue(const {{INPUT_TYPE}} *_{{FIELD_NAME}}"
") const {";
code_ +=
" const {{INPUT_TYPE}} *curr_{{FIELD_NAME}} = {{FIELD_NAME}}();";
code_ +=
" for (::flatbuffers::uoffset_t i = 0; i < "
"curr_{{FIELD_NAME}}->size(); i++) {";
if (IsScalar(elem_type.base_type)) {
std::string input_type = "::flatbuffers::Array<" +
GenTypeBasic(elem_type, false) + ", " +
NumToString(elem_type.fixed_length) + ">";
code_.SetValue("INPUT_TYPE", input_type);
code_ +=
" int KeyCompareWithValue(const {{INPUT_TYPE}} *_{{FIELD_NAME}}"
") const {";
code_ +=
" const {{INPUT_TYPE}} *curr_{{FIELD_NAME}} = {{FIELD_NAME}}();";
code_ +=
" for (::flatbuffers::uoffset_t i = 0; i < "
"curr_{{FIELD_NAME}}->size(); i++) {";
code_ += " const auto lhs = curr_{{FIELD_NAME}}->Get(i);";
code_ += " const auto rhs = _{{FIELD_NAME}}->Get(i);";
code_ += " if(lhs != rhs)";
code_ += " if (lhs != rhs)";
code_ +=
" return static_cast<int>(lhs > rhs)"
" - static_cast<int>(lhs < rhs);";
code_ += " }";
code_ += " return 0;";
} else if (IsStruct(elem_type)) {
code_ +=
" const auto &lhs_{{FIELD_NAME}} = "
"*(curr_{{FIELD_NAME}}->Get(i));";
code_ +=
" const auto &rhs_{{FIELD_NAME}} = *(_{{FIELD_NAME}}->Get(i));";
GenComparatorForStruct(*elem_type.struct_def, 6,
"lhs_" + code_.GetValue("FIELD_NAME"),
"rhs_" + code_.GetValue("FIELD_NAME"));
}
code_ += " }";
code_ += " return 0;";
} else if (is_struct) {
const auto *struct_def = field.value.type.struct_def;
code_.SetValue("INPUT_TYPE",
GenTypeGet(field.value.type, "", "", "", false));
code_ +=
" int KeyCompareWithValue(const {{INPUT_TYPE}} &_{{FIELD_NAME}}) "
"const {";
code_ += " const auto &lhs_{{FIELD_NAME}} = {{FIELD_NAME}}();";
code_ += " const auto &rhs_{{FIELD_NAME}} = _{{FIELD_NAME}};";
GenComparatorForStruct(*struct_def, 4,
"lhs_" + code_.GetValue("FIELD_NAME"),
"rhs_" + code_.GetValue("FIELD_NAME"));
code_ += " return 0;";
} else {
FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
auto type = GenTypeBasic(field.value.type, false);

View File

@ -918,7 +918,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
ECHECK(ParseType(type));
if (struct_def.fixed) {
if (IsIncompleteStruct(type) ||
if (IsIncompleteStruct(type) ||
(IsArray(type) && IsIncompleteStruct(type.VectorType()))) {
std::string type_name = IsArray(type) ? type.VectorType().struct_def->name : type.struct_def->name;
return Error(std::string("Incomplete type in struct is not allowed, type name: ") + type_name);
@ -1072,8 +1072,11 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
if (field->key) {
if (struct_def.has_key) return Error("only one field may be set as 'key'");
struct_def.has_key = true;
auto is_valid = IsScalar(type.base_type) || IsString(type);
if (IsArray(type)) { is_valid |= IsScalar(type.VectorType().base_type); }
auto is_valid = IsScalar(type.base_type) || IsString(type) || IsStruct(type);
if (IsArray(type)) {
is_valid |=
IsScalar(type.VectorType().base_type) || IsStruct(type.VectorType());
}
if (!is_valid) {
return Error(
"'key' field must be string, scalar type or fixed size array of "

View File

@ -10,12 +10,40 @@ struct Bar {
b: uint8;
}
struct Color {
rgb: [float:3] (key);
tag: uint8;
}
struct Apple {
tag: uint8;
color: Color(key);
}
struct Fruit {
a: Apple (key);
b: uint8;
}
struct Rice {
origin: [uint8:3];
quantity: uint32;
}
struct Grain {
a: [Rice:3] (key);
tag: uint8;
}
table FooTable {
a: int;
b: int;
c: string (key);
d: [Baz];
e: [Bar];
f: [Apple];
g: [Fruit];
h: [Grain];
}
root_type FooTable;

View File

@ -20,6 +20,16 @@ struct Baz;
struct Bar;
struct Color;
struct Apple;
struct Fruit;
struct Rice;
struct Grain;
struct FooTable;
struct FooTableBuilder;
struct FooTableT;
@ -28,6 +38,16 @@ bool operator==(const Baz &lhs, const Baz &rhs);
bool operator!=(const Baz &lhs, const Baz &rhs);
bool operator==(const Bar &lhs, const Bar &rhs);
bool operator!=(const Bar &lhs, const Bar &rhs);
bool operator==(const Color &lhs, const Color &rhs);
bool operator!=(const Color &lhs, const Color &rhs);
bool operator==(const Apple &lhs, const Apple &rhs);
bool operator!=(const Apple &lhs, const Apple &rhs);
bool operator==(const Fruit &lhs, const Fruit &rhs);
bool operator!=(const Fruit &lhs, const Fruit &rhs);
bool operator==(const Rice &lhs, const Rice &rhs);
bool operator!=(const Rice &lhs, const Rice &rhs);
bool operator==(const Grain &lhs, const Grain &rhs);
bool operator!=(const Grain &lhs, const Grain &rhs);
bool operator==(const FooTableT &lhs, const FooTableT &rhs);
bool operator!=(const FooTableT &lhs, const FooTableT &rhs);
@ -35,6 +55,16 @@ inline const ::flatbuffers::TypeTable *BazTypeTable();
inline const ::flatbuffers::TypeTable *BarTypeTable();
inline const ::flatbuffers::TypeTable *ColorTypeTable();
inline const ::flatbuffers::TypeTable *AppleTypeTable();
inline const ::flatbuffers::TypeTable *FruitTypeTable();
inline const ::flatbuffers::TypeTable *RiceTypeTable();
inline const ::flatbuffers::TypeTable *GrainTypeTable();
inline const ::flatbuffers::TypeTable *FooTableTypeTable();
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(1) Baz FLATBUFFERS_FINAL_CLASS {
@ -72,7 +102,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(1) Baz FLATBUFFERS_FINAL_CLASS {
for (::flatbuffers::uoffset_t i = 0; i < curr_a->size(); i++) {
const auto lhs = curr_a->Get(i);
const auto rhs = _a->Get(i);
if(lhs != rhs)
if (lhs != rhs)
return static_cast<int>(lhs > rhs) - static_cast<int>(lhs < rhs);
}
return 0;
@ -145,7 +175,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Bar FLATBUFFERS_FINAL_CLASS {
for (::flatbuffers::uoffset_t i = 0; i < curr_a->size(); i++) {
const auto lhs = curr_a->Get(i);
const auto rhs = _a->Get(i);
if(lhs != rhs)
if (lhs != rhs)
return static_cast<int>(lhs > rhs) - static_cast<int>(lhs < rhs);
}
return 0;
@ -170,6 +200,352 @@ inline bool operator!=(const Bar &lhs, const Bar &rhs) {
}
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Color FLATBUFFERS_FINAL_CLASS {
private:
float rgb_[3];
uint8_t tag_;
int8_t padding0__; int16_t padding1__;
public:
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return ColorTypeTable();
}
Color()
: rgb_(),
tag_(0),
padding0__(0),
padding1__(0) {
(void)padding0__;
(void)padding1__;
}
Color(uint8_t _tag)
: rgb_(),
tag_(::flatbuffers::EndianScalar(_tag)),
padding0__(0),
padding1__(0) {
(void)padding0__;
(void)padding1__;
}
Color(::flatbuffers::span<const float, 3> _rgb, uint8_t _tag)
: tag_(::flatbuffers::EndianScalar(_tag)),
padding0__(0),
padding1__(0) {
::flatbuffers::CastToArray(rgb_).CopyFromSpan(_rgb);
(void)padding0__;
(void)padding1__;
}
const ::flatbuffers::Array<float, 3> *rgb() const {
return &::flatbuffers::CastToArray(rgb_);
}
::flatbuffers::Array<float, 3> *mutable_rgb() {
return &::flatbuffers::CastToArray(rgb_);
}
bool KeyCompareLessThan(const Color * const o) const {
return KeyCompareWithValue(o->rgb()) < 0;
}
int KeyCompareWithValue(const ::flatbuffers::Array<float, 3> *_rgb) const {
const ::flatbuffers::Array<float, 3> *curr_rgb = rgb();
for (::flatbuffers::uoffset_t i = 0; i < curr_rgb->size(); i++) {
const auto lhs = curr_rgb->Get(i);
const auto rhs = _rgb->Get(i);
if (lhs != rhs)
return static_cast<int>(lhs > rhs) - static_cast<int>(lhs < rhs);
}
return 0;
}
uint8_t tag() const {
return ::flatbuffers::EndianScalar(tag_);
}
void mutate_tag(uint8_t _tag) {
::flatbuffers::WriteScalar(&tag_, _tag);
}
};
FLATBUFFERS_STRUCT_END(Color, 16);
inline bool operator==(const Color &lhs, const Color &rhs) {
return
(*lhs.rgb() == *rhs.rgb()) &&
(lhs.tag() == rhs.tag());
}
inline bool operator!=(const Color &lhs, const Color &rhs) {
return !(lhs == rhs);
}
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Apple FLATBUFFERS_FINAL_CLASS {
private:
uint8_t tag_;
int8_t padding0__; int16_t padding1__;
keyfield::sample::Color color_;
public:
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return AppleTypeTable();
}
Apple()
: tag_(0),
padding0__(0),
padding1__(0),
color_() {
(void)padding0__;
(void)padding1__;
}
Apple(uint8_t _tag, const keyfield::sample::Color &_color)
: tag_(::flatbuffers::EndianScalar(_tag)),
padding0__(0),
padding1__(0),
color_(_color) {
(void)padding0__;
(void)padding1__;
}
uint8_t tag() const {
return ::flatbuffers::EndianScalar(tag_);
}
void mutate_tag(uint8_t _tag) {
::flatbuffers::WriteScalar(&tag_, _tag);
}
const keyfield::sample::Color &color() const {
return color_;
}
keyfield::sample::Color &mutable_color() {
return color_;
}
bool KeyCompareLessThan(const Apple * const o) const {
return KeyCompareWithValue(o->color()) < 0;
}
int KeyCompareWithValue(const keyfield::sample::Color &_color) const {
const auto &lhs_color = color();
const auto &rhs_color = _color;
const auto rhs_color_rgb = rhs_color.rgb();
const auto rgb_compare_result = lhs_color.KeyCompareWithValue(rhs_color_rgb);
if (rgb_compare_result != 0)
return rgb_compare_result;
const auto lhs_color_tag = lhs_color.tag();
const auto rhs_color_tag = rhs_color.tag();
if (lhs_color_tag != rhs_color_tag)
return static_cast<int>(lhs_color_tag > rhs_color_tag) - static_cast<int>(lhs_color_tag < rhs_color_tag);
return 0;
}
};
FLATBUFFERS_STRUCT_END(Apple, 20);
inline bool operator==(const Apple &lhs, const Apple &rhs) {
return
(lhs.tag() == rhs.tag()) &&
(lhs.color() == rhs.color());
}
inline bool operator!=(const Apple &lhs, const Apple &rhs) {
return !(lhs == rhs);
}
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Fruit FLATBUFFERS_FINAL_CLASS {
private:
keyfield::sample::Apple a_;
uint8_t b_;
int8_t padding0__; int16_t padding1__;
public:
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return FruitTypeTable();
}
Fruit()
: a_(),
b_(0),
padding0__(0),
padding1__(0) {
(void)padding0__;
(void)padding1__;
}
Fruit(const keyfield::sample::Apple &_a, uint8_t _b)
: a_(_a),
b_(::flatbuffers::EndianScalar(_b)),
padding0__(0),
padding1__(0) {
(void)padding0__;
(void)padding1__;
}
const keyfield::sample::Apple &a() const {
return a_;
}
keyfield::sample::Apple &mutable_a() {
return a_;
}
bool KeyCompareLessThan(const Fruit * const o) const {
return KeyCompareWithValue(o->a()) < 0;
}
int KeyCompareWithValue(const keyfield::sample::Apple &_a) const {
const auto &lhs_a = a();
const auto &rhs_a = _a;
const auto lhs_a_tag = lhs_a.tag();
const auto rhs_a_tag = rhs_a.tag();
if (lhs_a_tag != rhs_a_tag)
return static_cast<int>(lhs_a_tag > rhs_a_tag) - static_cast<int>(lhs_a_tag < rhs_a_tag);
const auto rhs_a_color = rhs_a.color();
const auto color_compare_result = lhs_a.KeyCompareWithValue(rhs_a_color);
if (color_compare_result != 0)
return color_compare_result;
return 0;
}
uint8_t b() const {
return ::flatbuffers::EndianScalar(b_);
}
void mutate_b(uint8_t _b) {
::flatbuffers::WriteScalar(&b_, _b);
}
};
FLATBUFFERS_STRUCT_END(Fruit, 24);
inline bool operator==(const Fruit &lhs, const Fruit &rhs) {
return
(lhs.a() == rhs.a()) &&
(lhs.b() == rhs.b());
}
inline bool operator!=(const Fruit &lhs, const Fruit &rhs) {
return !(lhs == rhs);
}
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Rice FLATBUFFERS_FINAL_CLASS {
private:
uint8_t origin_[3];
int8_t padding0__;
uint32_t quantity_;
public:
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return RiceTypeTable();
}
Rice()
: origin_(),
padding0__(0),
quantity_(0) {
(void)padding0__;
}
Rice(uint32_t _quantity)
: origin_(),
padding0__(0),
quantity_(::flatbuffers::EndianScalar(_quantity)) {
(void)padding0__;
}
Rice(::flatbuffers::span<const uint8_t, 3> _origin, uint32_t _quantity)
: padding0__(0),
quantity_(::flatbuffers::EndianScalar(_quantity)) {
::flatbuffers::CastToArray(origin_).CopyFromSpan(_origin);
(void)padding0__;
}
const ::flatbuffers::Array<uint8_t, 3> *origin() const {
return &::flatbuffers::CastToArray(origin_);
}
::flatbuffers::Array<uint8_t, 3> *mutable_origin() {
return &::flatbuffers::CastToArray(origin_);
}
uint32_t quantity() const {
return ::flatbuffers::EndianScalar(quantity_);
}
void mutate_quantity(uint32_t _quantity) {
::flatbuffers::WriteScalar(&quantity_, _quantity);
}
};
FLATBUFFERS_STRUCT_END(Rice, 8);
inline bool operator==(const Rice &lhs, const Rice &rhs) {
return
(*lhs.origin() == *rhs.origin()) &&
(lhs.quantity() == rhs.quantity());
}
inline bool operator!=(const Rice &lhs, const Rice &rhs) {
return !(lhs == rhs);
}
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Grain FLATBUFFERS_FINAL_CLASS {
private:
keyfield::sample::Rice a_[3];
uint8_t tag_;
int8_t padding0__; int16_t padding1__;
public:
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return GrainTypeTable();
}
Grain()
: a_(),
tag_(0),
padding0__(0),
padding1__(0) {
(void)padding0__;
(void)padding1__;
}
Grain(uint8_t _tag)
: a_(),
tag_(::flatbuffers::EndianScalar(_tag)),
padding0__(0),
padding1__(0) {
(void)padding0__;
(void)padding1__;
}
Grain(::flatbuffers::span<const keyfield::sample::Rice, 3> _a, uint8_t _tag)
: tag_(::flatbuffers::EndianScalar(_tag)),
padding0__(0),
padding1__(0) {
::flatbuffers::CastToArray(a_).CopyFromSpan(_a);
(void)padding0__;
(void)padding1__;
}
const ::flatbuffers::Array<keyfield::sample::Rice, 3> *a() const {
return &::flatbuffers::CastToArray(a_);
}
::flatbuffers::Array<keyfield::sample::Rice, 3> *mutable_a() {
return &::flatbuffers::CastToArray(a_);
}
bool KeyCompareLessThan(const Grain * const o) const {
return KeyCompareWithValue(o->a()) < 0;
}
int KeyCompareWithValue(const ::flatbuffers::Array<keyfield::sample::Rice , 3> *_a) const {
const ::flatbuffers::Array<keyfield::sample::Rice , 3> *curr_a = a();
for (::flatbuffers::uoffset_t i = 0; i < curr_a->size(); i++) {
const auto &lhs_a = *(curr_a->Get(i));
const auto &rhs_a = *(_a->Get(i));
const auto lhs_a_origin = lhs_a.origin();
const auto rhs_a_origin = rhs_a.origin();
for (::flatbuffers::uoffset_t i = 0; i < lhs_a_origin->size(); i++) {
const auto lhs_a_origin_elem = lhs_a_origin->Get(i);
const auto rhs_a_origin_elem = rhs_a_origin->Get(i);
if (lhs_a_origin_elem != rhs_a_origin_elem)
return static_cast<int>(lhs_a_origin_elem > rhs_a_origin_elem) - static_cast<int>(lhs_a_origin_elem < rhs_a_origin_elem);
}
const auto lhs_a_quantity = lhs_a.quantity();
const auto rhs_a_quantity = rhs_a.quantity();
if (lhs_a_quantity != rhs_a_quantity)
return static_cast<int>(lhs_a_quantity > rhs_a_quantity) - static_cast<int>(lhs_a_quantity < rhs_a_quantity);
}
return 0;
}
uint8_t tag() const {
return ::flatbuffers::EndianScalar(tag_);
}
void mutate_tag(uint8_t _tag) {
::flatbuffers::WriteScalar(&tag_, _tag);
}
};
FLATBUFFERS_STRUCT_END(Grain, 28);
inline bool operator==(const Grain &lhs, const Grain &rhs) {
return
(*lhs.a() == *rhs.a()) &&
(lhs.tag() == rhs.tag());
}
inline bool operator!=(const Grain &lhs, const Grain &rhs) {
return !(lhs == rhs);
}
struct FooTableT : public ::flatbuffers::NativeTable {
typedef FooTable TableType;
int32_t a = 0;
@ -177,6 +553,9 @@ struct FooTableT : public ::flatbuffers::NativeTable {
std::string c{};
std::vector<keyfield::sample::Baz> d{};
std::vector<keyfield::sample::Bar> e{};
std::vector<keyfield::sample::Apple> f{};
std::vector<keyfield::sample::Fruit> g{};
std::vector<keyfield::sample::Grain> h{};
};
struct FooTable FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
@ -190,7 +569,10 @@ struct FooTable FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
VT_B = 6,
VT_C = 8,
VT_D = 10,
VT_E = 12
VT_E = 12,
VT_F = 14,
VT_G = 16,
VT_H = 18
};
int32_t a() const {
return GetField<int32_t>(VT_A, 0);
@ -228,6 +610,24 @@ struct FooTable FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
::flatbuffers::Vector<const keyfield::sample::Bar *> *mutable_e() {
return GetPointer<::flatbuffers::Vector<const keyfield::sample::Bar *> *>(VT_E);
}
const ::flatbuffers::Vector<const keyfield::sample::Apple *> *f() const {
return GetPointer<const ::flatbuffers::Vector<const keyfield::sample::Apple *> *>(VT_F);
}
::flatbuffers::Vector<const keyfield::sample::Apple *> *mutable_f() {
return GetPointer<::flatbuffers::Vector<const keyfield::sample::Apple *> *>(VT_F);
}
const ::flatbuffers::Vector<const keyfield::sample::Fruit *> *g() const {
return GetPointer<const ::flatbuffers::Vector<const keyfield::sample::Fruit *> *>(VT_G);
}
::flatbuffers::Vector<const keyfield::sample::Fruit *> *mutable_g() {
return GetPointer<::flatbuffers::Vector<const keyfield::sample::Fruit *> *>(VT_G);
}
const ::flatbuffers::Vector<const keyfield::sample::Grain *> *h() const {
return GetPointer<const ::flatbuffers::Vector<const keyfield::sample::Grain *> *>(VT_H);
}
::flatbuffers::Vector<const keyfield::sample::Grain *> *mutable_h() {
return GetPointer<::flatbuffers::Vector<const keyfield::sample::Grain *> *>(VT_H);
}
bool Verify(::flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<int32_t>(verifier, VT_A, 4) &&
@ -238,6 +638,12 @@ struct FooTable FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
verifier.VerifyVector(d()) &&
VerifyOffset(verifier, VT_E) &&
verifier.VerifyVector(e()) &&
VerifyOffset(verifier, VT_F) &&
verifier.VerifyVector(f()) &&
VerifyOffset(verifier, VT_G) &&
verifier.VerifyVector(g()) &&
VerifyOffset(verifier, VT_H) &&
verifier.VerifyVector(h()) &&
verifier.EndTable();
}
FooTableT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
@ -264,6 +670,15 @@ struct FooTableBuilder {
void add_e(::flatbuffers::Offset<::flatbuffers::Vector<const keyfield::sample::Bar *>> e) {
fbb_.AddOffset(FooTable::VT_E, e);
}
void add_f(::flatbuffers::Offset<::flatbuffers::Vector<const keyfield::sample::Apple *>> f) {
fbb_.AddOffset(FooTable::VT_F, f);
}
void add_g(::flatbuffers::Offset<::flatbuffers::Vector<const keyfield::sample::Fruit *>> g) {
fbb_.AddOffset(FooTable::VT_G, g);
}
void add_h(::flatbuffers::Offset<::flatbuffers::Vector<const keyfield::sample::Grain *>> h) {
fbb_.AddOffset(FooTable::VT_H, h);
}
explicit FooTableBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
@ -282,8 +697,14 @@ inline ::flatbuffers::Offset<FooTable> CreateFooTable(
int32_t b = 0,
::flatbuffers::Offset<::flatbuffers::String> c = 0,
::flatbuffers::Offset<::flatbuffers::Vector<const keyfield::sample::Baz *>> d = 0,
::flatbuffers::Offset<::flatbuffers::Vector<const keyfield::sample::Bar *>> e = 0) {
::flatbuffers::Offset<::flatbuffers::Vector<const keyfield::sample::Bar *>> e = 0,
::flatbuffers::Offset<::flatbuffers::Vector<const keyfield::sample::Apple *>> f = 0,
::flatbuffers::Offset<::flatbuffers::Vector<const keyfield::sample::Fruit *>> g = 0,
::flatbuffers::Offset<::flatbuffers::Vector<const keyfield::sample::Grain *>> h = 0) {
FooTableBuilder builder_(_fbb);
builder_.add_h(h);
builder_.add_g(g);
builder_.add_f(f);
builder_.add_e(e);
builder_.add_d(d);
builder_.add_c(c);
@ -298,17 +719,26 @@ inline ::flatbuffers::Offset<FooTable> CreateFooTableDirect(
int32_t b = 0,
const char *c = nullptr,
std::vector<keyfield::sample::Baz> *d = nullptr,
std::vector<keyfield::sample::Bar> *e = nullptr) {
std::vector<keyfield::sample::Bar> *e = nullptr,
std::vector<keyfield::sample::Apple> *f = nullptr,
std::vector<keyfield::sample::Fruit> *g = nullptr,
std::vector<keyfield::sample::Grain> *h = nullptr) {
auto c__ = c ? _fbb.CreateString(c) : 0;
auto d__ = d ? _fbb.CreateVectorOfSortedStructs<keyfield::sample::Baz>(d) : 0;
auto e__ = e ? _fbb.CreateVectorOfSortedStructs<keyfield::sample::Bar>(e) : 0;
auto f__ = f ? _fbb.CreateVectorOfSortedStructs<keyfield::sample::Apple>(f) : 0;
auto g__ = g ? _fbb.CreateVectorOfSortedStructs<keyfield::sample::Fruit>(g) : 0;
auto h__ = h ? _fbb.CreateVectorOfSortedStructs<keyfield::sample::Grain>(h) : 0;
return keyfield::sample::CreateFooTable(
_fbb,
a,
b,
c__,
d__,
e__);
e__,
f__,
g__,
h__);
}
::flatbuffers::Offset<FooTable> CreateFooTable(::flatbuffers::FlatBufferBuilder &_fbb, const FooTableT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
@ -320,7 +750,10 @@ inline bool operator==(const FooTableT &lhs, const FooTableT &rhs) {
(lhs.b == rhs.b) &&
(lhs.c == rhs.c) &&
(lhs.d == rhs.d) &&
(lhs.e == rhs.e);
(lhs.e == rhs.e) &&
(lhs.f == rhs.f) &&
(lhs.g == rhs.g) &&
(lhs.h == rhs.h);
}
inline bool operator!=(const FooTableT &lhs, const FooTableT &rhs) {
@ -342,6 +775,9 @@ inline void FooTable::UnPackTo(FooTableT *_o, const ::flatbuffers::resolver_func
{ auto _e = c(); if (_e) _o->c = _e->str(); }
{ auto _e = d(); if (_e) { _o->d.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->d[_i] = *_e->Get(_i); } } else { _o->d.resize(0); } }
{ auto _e = e(); if (_e) { _o->e.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->e[_i] = *_e->Get(_i); } } else { _o->e.resize(0); } }
{ auto _e = f(); if (_e) { _o->f.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->f[_i] = *_e->Get(_i); } } else { _o->f.resize(0); } }
{ auto _e = g(); if (_e) { _o->g.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->g[_i] = *_e->Get(_i); } } else { _o->g.resize(0); } }
{ auto _e = h(); if (_e) { _o->h.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->h[_i] = *_e->Get(_i); } } else { _o->h.resize(0); } }
}
inline ::flatbuffers::Offset<FooTable> FooTable::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const FooTableT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) {
@ -357,13 +793,19 @@ inline ::flatbuffers::Offset<FooTable> CreateFooTable(::flatbuffers::FlatBufferB
auto _c = _fbb.CreateString(_o->c);
auto _d = _o->d.size() ? _fbb.CreateVectorOfStructs(_o->d) : 0;
auto _e = _o->e.size() ? _fbb.CreateVectorOfStructs(_o->e) : 0;
auto _f = _o->f.size() ? _fbb.CreateVectorOfStructs(_o->f) : 0;
auto _g = _o->g.size() ? _fbb.CreateVectorOfStructs(_o->g) : 0;
auto _h = _o->h.size() ? _fbb.CreateVectorOfStructs(_o->h) : 0;
return keyfield::sample::CreateFooTable(
_fbb,
_a,
_b,
_c,
_d,
_e);
_e,
_f,
_g,
_h);
}
inline const ::flatbuffers::TypeTable *BazTypeTable() {
@ -400,27 +842,128 @@ inline const ::flatbuffers::TypeTable *BarTypeTable() {
return &tt;
}
inline const ::flatbuffers::TypeTable *ColorTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_FLOAT, 1, -1 },
{ ::flatbuffers::ET_UCHAR, 0, -1 }
};
static const int16_t array_sizes[] = { 3, };
static const int64_t values[] = { 0, 12, 16 };
static const char * const names[] = {
"rgb",
"tag"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_STRUCT, 2, type_codes, nullptr, array_sizes, values, names
};
return &tt;
}
inline const ::flatbuffers::TypeTable *AppleTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_UCHAR, 0, -1 },
{ ::flatbuffers::ET_SEQUENCE, 0, 0 }
};
static const ::flatbuffers::TypeFunction type_refs[] = {
keyfield::sample::ColorTypeTable
};
static const int64_t values[] = { 0, 4, 20 };
static const char * const names[] = {
"tag",
"color"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_STRUCT, 2, type_codes, type_refs, nullptr, values, names
};
return &tt;
}
inline const ::flatbuffers::TypeTable *FruitTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_SEQUENCE, 0, 0 },
{ ::flatbuffers::ET_UCHAR, 0, -1 }
};
static const ::flatbuffers::TypeFunction type_refs[] = {
keyfield::sample::AppleTypeTable
};
static const int64_t values[] = { 0, 20, 24 };
static const char * const names[] = {
"a",
"b"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_STRUCT, 2, type_codes, type_refs, nullptr, values, names
};
return &tt;
}
inline const ::flatbuffers::TypeTable *RiceTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_UCHAR, 1, -1 },
{ ::flatbuffers::ET_UINT, 0, -1 }
};
static const int16_t array_sizes[] = { 3, };
static const int64_t values[] = { 0, 4, 8 };
static const char * const names[] = {
"origin",
"quantity"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_STRUCT, 2, type_codes, nullptr, array_sizes, values, names
};
return &tt;
}
inline const ::flatbuffers::TypeTable *GrainTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_SEQUENCE, 1, 0 },
{ ::flatbuffers::ET_UCHAR, 0, -1 }
};
static const ::flatbuffers::TypeFunction type_refs[] = {
keyfield::sample::RiceTypeTable
};
static const int16_t array_sizes[] = { 3, };
static const int64_t values[] = { 0, 24, 28 };
static const char * const names[] = {
"a",
"tag"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_STRUCT, 2, type_codes, type_refs, array_sizes, values, names
};
return &tt;
}
inline const ::flatbuffers::TypeTable *FooTableTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_INT, 0, -1 },
{ ::flatbuffers::ET_INT, 0, -1 },
{ ::flatbuffers::ET_STRING, 0, -1 },
{ ::flatbuffers::ET_SEQUENCE, 1, 0 },
{ ::flatbuffers::ET_SEQUENCE, 1, 1 }
{ ::flatbuffers::ET_SEQUENCE, 1, 1 },
{ ::flatbuffers::ET_SEQUENCE, 1, 2 },
{ ::flatbuffers::ET_SEQUENCE, 1, 3 },
{ ::flatbuffers::ET_SEQUENCE, 1, 4 }
};
static const ::flatbuffers::TypeFunction type_refs[] = {
keyfield::sample::BazTypeTable,
keyfield::sample::BarTypeTable
keyfield::sample::BarTypeTable,
keyfield::sample::AppleTypeTable,
keyfield::sample::FruitTypeTable,
keyfield::sample::GrainTypeTable
};
static const char * const names[] = {
"a",
"b",
"c",
"d",
"e"
"e",
"f",
"g",
"h"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_TABLE, 5, type_codes, type_refs, nullptr, nullptr, names
::flatbuffers::ST_TABLE, 8, type_codes, type_refs, nullptr, nullptr, names
};
return &tt;
}

View File

@ -40,6 +40,7 @@ void FixedSizedScalarKeyInStructTest() {
auto t = CreateFooTable(fbb, 1, 2, test_string, baz_vec, bar_vec);
fbb.Finish(t);
uint8_t *buf = fbb.GetBufferPointer();
@ -79,5 +80,146 @@ void FixedSizedScalarKeyInStructTest() {
static_cast<const Bar *>(nullptr));
}
void StructKeyInStructTest() {
flatbuffers::FlatBufferBuilder fbb;
std::vector<Apple> apples;
float test_float_array1[3] = { 1.5, 2.5, 0 };
float test_float_array2[3] = { 7.5, 2.5, 0 };
float test_float_array3[3] = { 1.5, 2.5, -1 };
apples.push_back(
Apple(2, Color(flatbuffers::make_span(test_float_array1), 3)));
apples.push_back(
Apple(3, Color(flatbuffers::make_span(test_float_array2), 3)));
apples.push_back(
Apple(1, Color(flatbuffers::make_span(test_float_array3), 1)));
auto apples_vec = fbb.CreateVectorOfSortedStructs(&apples);
auto test_string = fbb.CreateString("TEST");
FooTableBuilder foo_builder(fbb);
foo_builder.add_a(1);
foo_builder.add_c(test_string);
foo_builder.add_f(apples_vec);
auto orc = foo_builder.Finish();
fbb.Finish(orc);
uint8_t *buf = fbb.GetBufferPointer();
auto foo_table = GetFooTable(buf);
auto sorted_apple_vec = foo_table->f();
TEST_EQ(sorted_apple_vec->Get(0)->tag(), 1);
TEST_EQ(sorted_apple_vec->Get(1)->tag(), 2);
TEST_EQ(sorted_apple_vec->Get(2)->tag(), 3);
TEST_EQ(sorted_apple_vec
->LookupByKey(Color(flatbuffers::make_span(test_float_array1), 3))
->tag(),
2);
TEST_EQ(sorted_apple_vec->LookupByKey(
Color(flatbuffers::make_span(test_float_array1), 0)),
static_cast<const Apple *>(nullptr));
}
void NestedStructKeyInStructTest() {
flatbuffers::FlatBufferBuilder fbb;
std::vector<Fruit> fruits;
float test_float_array1[3] = { 1.5, 2.5, 0 };
float test_float_array2[3] = { 1.5, 2.5, 0 };
float test_float_array3[3] = { 1.5, 2.5, -1 };
fruits.push_back(
Fruit(Apple(2, Color(flatbuffers::make_span(test_float_array1), 2)), 2));
fruits.push_back(
Fruit(Apple(2, Color(flatbuffers::make_span(test_float_array2), 1)), 1));
fruits.push_back(
Fruit(Apple(2, Color(flatbuffers::make_span(test_float_array3), 3)), 3));
auto test_string = fbb.CreateString("TEST");
auto fruits_vec = fbb.CreateVectorOfSortedStructs(&fruits);
FooTableBuilder foo_builder(fbb);
foo_builder.add_a(1);
foo_builder.add_c(test_string);
foo_builder.add_g(fruits_vec);
auto orc = foo_builder.Finish();
fbb.Finish(orc);
uint8_t *buf = fbb.GetBufferPointer();
auto foo_table = GetFooTable(buf);
auto sorted_fruit_vec = foo_table->g();
TEST_EQ(sorted_fruit_vec->Get(0)->b(), 3);
TEST_EQ(sorted_fruit_vec->Get(1)->b(), 1);
TEST_EQ(sorted_fruit_vec->Get(2)->b(), 2);
TEST_EQ(sorted_fruit_vec->LookupByKey(Apple(2, Color(flatbuffers::make_span(test_float_array2), 1)))->b(), 1);
TEST_EQ(sorted_fruit_vec->LookupByKey(Apple(1, Color(flatbuffers::make_span(test_float_array2), 1))), static_cast<const Fruit *>(nullptr));
}
void FixedSizedStructArrayKeyInStructTest() {
flatbuffers::FlatBufferBuilder fbb;
std::vector<Grain> grains;
uint8_t test_char_array1[3] = { 'u', 's', 'a' };
uint8_t test_char_array2[3] = { 'c', 'h', 'n' };
uint8_t test_char_array3[3] = { 'c', 'h', 'l' };
uint8_t test_char_array4[3] = { 'f', 'r', 'a' };
uint8_t test_char_array5[3] = { 'i', 'n', 'd' };
uint8_t test_char_array6[3] = { 'i', 't', 'a' };
Rice test_rice_array1[3] = {
Rice(flatbuffers::make_span(test_char_array1), 2),
Rice(flatbuffers::make_span(test_char_array2), 1),
Rice(flatbuffers::make_span(test_char_array3), 2)
};
Rice test_rice_array2[3] = {
Rice(flatbuffers::make_span(test_char_array4), 2),
Rice(flatbuffers::make_span(test_char_array5), 1),
Rice(flatbuffers::make_span(test_char_array6), 2)
};
Rice test_rice_array3[3] = {
Rice(flatbuffers::make_span(test_char_array4), 2),
Rice(flatbuffers::make_span(test_char_array6), 1),
Rice(flatbuffers::make_span(test_char_array1), 2)
};
grains.push_back(Grain(flatbuffers::make_span(test_rice_array1), 3));
grains.push_back(Grain(flatbuffers::make_span(test_rice_array2), 1));
grains.push_back(Grain(flatbuffers::make_span(test_rice_array3), 2));
auto test_string = fbb.CreateString("TEST");
auto grains_vec = fbb.CreateVectorOfSortedStructs(&grains);
FooTableBuilder foo_builder(fbb);
foo_builder.add_a(1);
foo_builder.add_c(test_string);
foo_builder.add_h(grains_vec);
auto orc = foo_builder.Finish();
fbb.Finish(orc);
uint8_t *buf = fbb.GetBufferPointer();
auto foo_table = GetFooTable(buf);
auto sorted_grain_vec = foo_table->h();
TEST_EQ(sorted_grain_vec->Get(0)->tag(), 1);
TEST_EQ(sorted_grain_vec->Get(1)->tag(), 2);
TEST_EQ(sorted_grain_vec->Get(2)->tag(), 3);
TEST_EQ(
sorted_grain_vec->LookupByKey(&flatbuffers::CastToArray(test_rice_array1))
->tag(),
3);
Rice test_rice_array[3] = { Rice(flatbuffers::make_span(test_char_array3), 2),
Rice(flatbuffers::make_span(test_char_array2), 1),
Rice(flatbuffers::make_span(test_char_array1),
2) };
TEST_EQ(
sorted_grain_vec->LookupByKey(&flatbuffers::CastToArray(test_rice_array)),
static_cast<const Grain *>(nullptr));
TEST_EQ(
sorted_grain_vec->LookupByKey(&flatbuffers::CastToArray(test_rice_array1))
->tag(),
3);
}
} // namespace tests
} // namespace flatbuffers

View File

@ -5,6 +5,10 @@ namespace flatbuffers {
namespace tests {
void FixedSizedScalarKeyInStructTest();
void StructKeyInStructTest();
void NestedStructKeyInStructTest();
void FixedSizedStructArrayKeyInStructTest();
} // namespace tests
} // namespace flatbuffers

View File

@ -1620,6 +1620,9 @@ int FlatBufferTests(const std::string &tests_data_path) {
VectorSpanTest();
NativeInlineTableVectorTest();
FixedSizedScalarKeyInStructTest();
StructKeyInStructTest();
NestedStructKeyInStructTest();
FixedSizedStructArrayKeyInStructTest();
return 0;
}
} // namespace