From 802a3a056a66f6d744d03739341918486e1de612 Mon Sep 17 00:00:00 2001 From: Wen Sun <30698014+sunwen18@users.noreply.github.com> Date: Tue, 24 Jan 2023 16:37:13 -0800 Subject: [PATCH] [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 Co-authored-by: Derek Bailey --- src/idl_gen_cpp.cpp | 137 ++++- src/idl_parser.cpp | 9 +- tests/key_field/key_field_sample.fbs | 28 + tests/key_field/key_field_sample_generated.h | 567 ++++++++++++++++++- tests/key_field_test.cpp | 142 +++++ tests/key_field_test.h | 4 + tests/test.cpp | 3 + 7 files changed, 853 insertions(+), 37 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index ad534b64d..970709d0e 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -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({{LHS}} > {{RHS}}) - " + "static_cast({{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({{LHS}}_elem > {{RHS}}_elem) - " + "static_cast({{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(lhs > rhs)" " - static_cast(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); diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 06095e621..9477c457f 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -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 " diff --git a/tests/key_field/key_field_sample.fbs b/tests/key_field/key_field_sample.fbs index 028920d2c..e19969bb1 100644 --- a/tests/key_field/key_field_sample.fbs +++ b/tests/key_field/key_field_sample.fbs @@ -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; diff --git a/tests/key_field/key_field_sample_generated.h b/tests/key_field/key_field_sample_generated.h index 2a4ce6383..6a5b9b423 100644 --- a/tests/key_field/key_field_sample_generated.h +++ b/tests/key_field/key_field_sample_generated.h @@ -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(lhs > rhs) - static_cast(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(lhs > rhs) - static_cast(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 _rgb, uint8_t _tag) + : tag_(::flatbuffers::EndianScalar(_tag)), + padding0__(0), + padding1__(0) { + ::flatbuffers::CastToArray(rgb_).CopyFromSpan(_rgb); + (void)padding0__; + (void)padding1__; + } + const ::flatbuffers::Array *rgb() const { + return &::flatbuffers::CastToArray(rgb_); + } + ::flatbuffers::Array *mutable_rgb() { + return &::flatbuffers::CastToArray(rgb_); + } + bool KeyCompareLessThan(const Color * const o) const { + return KeyCompareWithValue(o->rgb()) < 0; + } + int KeyCompareWithValue(const ::flatbuffers::Array *_rgb) const { + const ::flatbuffers::Array *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(lhs > rhs) - static_cast(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(lhs_color_tag > rhs_color_tag) - static_cast(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(lhs_a_tag > rhs_a_tag) - static_cast(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 _origin, uint32_t _quantity) + : padding0__(0), + quantity_(::flatbuffers::EndianScalar(_quantity)) { + ::flatbuffers::CastToArray(origin_).CopyFromSpan(_origin); + (void)padding0__; + } + const ::flatbuffers::Array *origin() const { + return &::flatbuffers::CastToArray(origin_); + } + ::flatbuffers::Array *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 _a, uint8_t _tag) + : tag_(::flatbuffers::EndianScalar(_tag)), + padding0__(0), + padding1__(0) { + ::flatbuffers::CastToArray(a_).CopyFromSpan(_a); + (void)padding0__; + (void)padding1__; + } + const ::flatbuffers::Array *a() const { + return &::flatbuffers::CastToArray(a_); + } + ::flatbuffers::Array *mutable_a() { + return &::flatbuffers::CastToArray(a_); + } + bool KeyCompareLessThan(const Grain * const o) const { + return KeyCompareWithValue(o->a()) < 0; + } + int KeyCompareWithValue(const ::flatbuffers::Array *_a) const { + const ::flatbuffers::Array *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(lhs_a_origin_elem > rhs_a_origin_elem) - static_cast(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(lhs_a_quantity > rhs_a_quantity) - static_cast(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 d{}; std::vector e{}; + std::vector f{}; + std::vector g{}; + std::vector 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(VT_A, 0); @@ -228,6 +610,24 @@ struct FooTable FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { ::flatbuffers::Vector *mutable_e() { return GetPointer<::flatbuffers::Vector *>(VT_E); } + const ::flatbuffers::Vector *f() const { + return GetPointer *>(VT_F); + } + ::flatbuffers::Vector *mutable_f() { + return GetPointer<::flatbuffers::Vector *>(VT_F); + } + const ::flatbuffers::Vector *g() const { + return GetPointer *>(VT_G); + } + ::flatbuffers::Vector *mutable_g() { + return GetPointer<::flatbuffers::Vector *>(VT_G); + } + const ::flatbuffers::Vector *h() const { + return GetPointer *>(VT_H); + } + ::flatbuffers::Vector *mutable_h() { + return GetPointer<::flatbuffers::Vector *>(VT_H); + } bool Verify(::flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(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> e) { fbb_.AddOffset(FooTable::VT_E, e); } + void add_f(::flatbuffers::Offset<::flatbuffers::Vector> f) { + fbb_.AddOffset(FooTable::VT_F, f); + } + void add_g(::flatbuffers::Offset<::flatbuffers::Vector> g) { + fbb_.AddOffset(FooTable::VT_G, g); + } + void add_h(::flatbuffers::Offset<::flatbuffers::Vector> h) { + fbb_.AddOffset(FooTable::VT_H, h); + } explicit FooTableBuilder(::flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -282,8 +697,14 @@ inline ::flatbuffers::Offset CreateFooTable( int32_t b = 0, ::flatbuffers::Offset<::flatbuffers::String> c = 0, ::flatbuffers::Offset<::flatbuffers::Vector> d = 0, - ::flatbuffers::Offset<::flatbuffers::Vector> e = 0) { + ::flatbuffers::Offset<::flatbuffers::Vector> e = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> f = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> g = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> 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 CreateFooTableDirect( int32_t b = 0, const char *c = nullptr, std::vector *d = nullptr, - std::vector *e = nullptr) { + std::vector *e = nullptr, + std::vector *f = nullptr, + std::vector *g = nullptr, + std::vector *h = nullptr) { auto c__ = c ? _fbb.CreateString(c) : 0; auto d__ = d ? _fbb.CreateVectorOfSortedStructs(d) : 0; auto e__ = e ? _fbb.CreateVectorOfSortedStructs(e) : 0; + auto f__ = f ? _fbb.CreateVectorOfSortedStructs(f) : 0; + auto g__ = g ? _fbb.CreateVectorOfSortedStructs(g) : 0; + auto h__ = h ? _fbb.CreateVectorOfSortedStructs(h) : 0; return keyfield::sample::CreateFooTable( _fbb, a, b, c__, d__, - e__); + e__, + f__, + g__, + h__); } ::flatbuffers::Offset 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::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const FooTableT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) { @@ -357,13 +793,19 @@ inline ::flatbuffers::Offset 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; } diff --git a/tests/key_field_test.cpp b/tests/key_field_test.cpp index da762d20a..7194e6d69 100644 --- a/tests/key_field_test.cpp +++ b/tests/key_field_test.cpp @@ -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(nullptr)); } +void StructKeyInStructTest() { + flatbuffers::FlatBufferBuilder fbb; + std::vector 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(nullptr)); +} + +void NestedStructKeyInStructTest() { + flatbuffers::FlatBufferBuilder fbb; + std::vector 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(nullptr)); + +} + +void FixedSizedStructArrayKeyInStructTest() { + flatbuffers::FlatBufferBuilder fbb; + std::vector 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(nullptr)); + TEST_EQ( + sorted_grain_vec->LookupByKey(&flatbuffers::CastToArray(test_rice_array1)) + ->tag(), + 3); +} + } // namespace tests } // namespace flatbuffers diff --git a/tests/key_field_test.h b/tests/key_field_test.h index 4cc4ddcca..bfced61a1 100644 --- a/tests/key_field_test.h +++ b/tests/key_field_test.h @@ -5,6 +5,10 @@ namespace flatbuffers { namespace tests { void FixedSizedScalarKeyInStructTest(); +void StructKeyInStructTest(); +void NestedStructKeyInStructTest(); +void FixedSizedStructArrayKeyInStructTest(); + } // namespace tests } // namespace flatbuffers diff --git a/tests/test.cpp b/tests/test.cpp index 0ad755a32..19f9e0da8 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1620,6 +1620,9 @@ int FlatBufferTests(const std::string &tests_data_path) { VectorSpanTest(); NativeInlineTableVectorTest(); FixedSizedScalarKeyInStructTest(); + StructKeyInStructTest(); + NestedStructKeyInStructTest(); + FixedSizedStructArrayKeyInStructTest(); return 0; } } // namespace