From eb1abb51ea856a7b118c0d6a47624470caec0463 Mon Sep 17 00:00:00 2001 From: Wen Sun <30698014+sunwen18@users.noreply.github.com> Date: Fri, 18 Nov 2022 11:04:46 -0800 Subject: [PATCH] Add support for using array of scalar as key field in Cpp (#7623) * add support for using array of scalar as key field * update cmakelist and test.cpp to include the tests * update bazel rule * address comments * clang format * delete comment * delete comment * address the rest of the commnets * address comments * update naming in test file * format build file * buildifier * make keycomparelessthan call keycomparewithvalue * update to use flatbuffer array instead of raw pointer * clang * format * revert format * revert format * update * run generate_code.py * run code generator * revert changes by generate_code.py * fist run make flatc and then run generate_code.py Co-authored-by: Wen Sun --- CMakeLists.txt | 41 +-- include/flatbuffers/reflection_generated.h | 16 +- src/idl_gen_cpp.cpp | 35 ++- src/idl_parser.cpp | 20 +- tests/BUILD.bazel | 4 + .../generated_cpp17/monster_test_generated.h | 8 +- tests/key_field/key_field_sample.fbs | 21 ++ tests/key_field/key_field_sample_generated.h | 260 ++++++++++++++++++ tests/key_field_test.cpp | 72 +++++ tests/key_field_test.h | 12 + tests/monster_test_generated.h | 8 +- .../ext_only/monster_test_generated.hpp | 8 +- .../filesuffix_only/monster_test_suffix.h | 8 +- .../monster_test_suffix.hpp | 8 +- tests/test.cpp | 12 +- 15 files changed, 471 insertions(+), 62 deletions(-) create mode 100644 tests/key_field/key_field_sample.fbs create mode 100644 tests/key_field/key_field_sample_generated.h create mode 100644 tests/key_field_test.cpp create mode 100644 tests/key_field_test.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 85356ca65..34b3612e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,10 +71,10 @@ option(FLATBUFFERS_ENABLE_PCH Only work if CMake supports 'target_precompile_headers'. \" This can speed up compilation time." OFF) -option(FLATBUFFERS_SKIP_MONSTER_EXTRA +option(FLATBUFFERS_SKIP_MONSTER_EXTRA "Skip generating monster_extra.fbs that contains non-supported numerical\" types." OFF) -option(FLATBUFFERS_STRICT_MODE +option(FLATBUFFERS_STRICT_MODE "Build flatbuffers with all warnings as errors (-Werror or /WX)." OFF) @@ -226,6 +226,7 @@ set(FlatBuffers_Tests_SRCS tests/flexbuffers_test.cpp tests/fuzz_test.cpp tests/json_test.cpp + tests/key_field_test.cpp tests/monster_test.cpp tests/optional_scalars_test.cpp tests/parser_test.cpp @@ -264,6 +265,8 @@ set(FlatBuffers_Tests_SRCS ${CMAKE_CURRENT_BINARY_DIR}/tests/native_inline_table_test_generated.h # file generate by running compiler on tests/alignment_test.fbs ${CMAKE_CURRENT_BINARY_DIR}/tests/alignment_test_generated.h + # file generate by running compiler on tests/key_field/key_field_sample.fbs + ${CMAKE_CURRENT_BINARY_DIR}/tests/key_field/key_field_sample_generated.h ) set(FlatBuffers_Tests_CPP17_SRCS @@ -365,8 +368,8 @@ include_directories(grpc) # Creates an interface library that stores the configuration settings that each # target links too. This is a compromise between setting configuration globally -# with add_compile_options() and the more targetted target_compile_options(). -# This way each target in this file can share settings and override them if +# with add_compile_options() and the more targetted target_compile_options(). +# This way each target in this file can share settings and override them if # needed. add_library(ProjectConfig INTERFACE) target_compile_features(ProjectConfig @@ -382,7 +385,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) if(MSVC_LIKE) target_compile_options(ProjectConfig - INTERFACE + INTERFACE /W4 $<$: /WX # Treat all compiler warnings as errors @@ -414,8 +417,8 @@ else() -Wno-error=stringop-overflow > > - -pedantic - -Wextra + -pedantic + -Wextra -Wno-unused-parameter -Wold-style-cast -fsigned-char @@ -429,7 +432,7 @@ else() $<$,3.8>: -Wimplicit-fallthrough -Wextra-semi - $<$: + $<$: -Werror=unused-private-field > > @@ -438,7 +441,7 @@ else() $<$: $<$,4.4>: -Wunused-result - -Wunused-parameter + -Wunused-parameter -Werror=unused-parameter -Wmissing-declarations > @@ -446,7 +449,7 @@ else() -Wzero-as-null-pointer-constant > $<$,7.0>: - -faligned-new + -faligned-new $<$: -Werror=implicit-fallthrough=2 > @@ -476,7 +479,7 @@ if(FLATBUFFERS_BUILD_FLATLIB) add_library(flatbuffers STATIC ${FlatBuffers_Library_SRCS}) # Attach header directory for when build via add_subdirectory(). - target_include_directories(flatbuffers + target_include_directories(flatbuffers INTERFACE $ ) @@ -494,7 +497,7 @@ if(FLATBUFFERS_BUILD_FLATC) endif() target_link_libraries(flatc PRIVATE $) - target_compile_options(flatc + target_compile_options(flatc PUBLIC $<$,$>: /MT @@ -696,13 +699,13 @@ if(FLATBUFFERS_BUILD_GRPCTEST) find_package(gRPC CONFIG REQUIRED) add_executable(grpctest ${FlatBuffers_GRPCTest_SRCS}) add_dependencies(grpctest generated_code) - target_link_libraries(grpctext - PRIVATE + target_link_libraries(grpctext + PRIVATE $ - gRPC::grpc++_unsecure - gRPC::gpr + gRPC::grpc++_unsecure + gRPC::gpr pthread - dl + dl ) endif() @@ -715,8 +718,8 @@ if(FLATBUFFERS_INSTALL) configure_file(CMake/flatbuffers-config-version.cmake.in flatbuffers-config-version.cmake @ONLY) install( - FILES - "CMake/flatbuffers-config.cmake" + FILES + "CMake/flatbuffers-config.cmake" "CMake/BuildFlatBuffers.cmake" "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-config-version.cmake" DESTINATION ${FB_CMAKE_DIR} diff --git a/include/flatbuffers/reflection_generated.h b/include/flatbuffers/reflection_generated.h index ca16429ef..555396bae 100644 --- a/include/flatbuffers/reflection_generated.h +++ b/include/flatbuffers/reflection_generated.h @@ -265,7 +265,7 @@ struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::String *key() const { return GetPointer(VT_KEY); } - bool KeyCompareLessThan(const KeyValue *o) const { + bool KeyCompareLessThan(const KeyValue * const o) const { return *key() < *o->key(); } int KeyCompareWithValue(const char *_key) const { @@ -343,7 +343,7 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { int64_t value() const { return GetField(VT_VALUE, 0); } - bool KeyCompareLessThan(const EnumVal *o) const { + bool KeyCompareLessThan(const EnumVal * const o) const { return value() < o->value(); } int KeyCompareWithValue(int64_t _value) const { @@ -455,7 +455,7 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::String *name() const { return GetPointer(VT_NAME); } - bool KeyCompareLessThan(const Enum *o) const { + bool KeyCompareLessThan(const Enum * const o) const { return *name() < *o->name(); } int KeyCompareWithValue(const char *_name) const { @@ -606,7 +606,7 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::String *name() const { return GetPointer(VT_NAME); } - bool KeyCompareLessThan(const Field *o) const { + bool KeyCompareLessThan(const Field * const o) const { return *name() < *o->name(); } int KeyCompareWithValue(const char *_name) const { @@ -812,7 +812,7 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::String *name() const { return GetPointer(VT_NAME); } - bool KeyCompareLessThan(const Object *o) const { + bool KeyCompareLessThan(const Object * const o) const { return *name() < *o->name(); } int KeyCompareWithValue(const char *_name) const { @@ -964,7 +964,7 @@ struct RPCCall FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::String *name() const { return GetPointer(VT_NAME); } - bool KeyCompareLessThan(const RPCCall *o) const { + bool KeyCompareLessThan(const RPCCall * const o) const { return *name() < *o->name(); } int KeyCompareWithValue(const char *_name) const { @@ -1080,7 +1080,7 @@ struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::String *name() const { return GetPointer(VT_NAME); } - bool KeyCompareLessThan(const Service *o) const { + bool KeyCompareLessThan(const Service * const o) const { return *name() < *o->name(); } int KeyCompareWithValue(const char *_name) const { @@ -1199,7 +1199,7 @@ struct SchemaFile FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::String *filename() const { return GetPointer(VT_FILENAME); } - bool KeyCompareLessThan(const SchemaFile *o) const { + bool KeyCompareLessThan(const SchemaFile * const o) const { return *filename() < *o->filename(); } int KeyCompareWithValue(const char *_filename) const { diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 5cffc18a3..e3d1ff35b 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -2278,12 +2278,19 @@ class CppGenerator : public BaseGenerator { // 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_string = IsString(field.value.type); + const bool is_array = IsArray(field.value.type); - code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {"; + 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 { code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();"; } @@ -2292,7 +2299,27 @@ class CppGenerator : public BaseGenerator { if (is_string) { code_ += " int KeyCompareWithValue(const char *_{{FIELD_NAME}}) const {"; code_ += " return strcmp({{FIELD_NAME}}()->c_str(), _{{FIELD_NAME}});"; - code_ += " }"; + } else if (is_array) { + const auto &elem_type = field.value.type.VectorType(); + 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_ += " for (auto i = 0; i < {{FIELD_NAME}}()->size(); i++) {"; + code_ += " const auto {{FIELD_NAME}}_l = {{FIELD_NAME}}_[i];"; + code_ += " const auto {{FIELD_NAME}}_r = _{{FIELD_NAME}}->Get(i);"; + code_ += " if({{FIELD_NAME}}_l != {{FIELD_NAME}}_r) "; + code_ += + " return static_cast({{FIELD_NAME}}_l > " + "{{FIELD_NAME}}_r)" + " - static_cast({{FIELD_NAME}}_l < {{FIELD_NAME}}_r);"; + code_ += " }"; + code_ += " return 0;"; + } } else { FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type)); auto type = GenTypeBasic(field.value.type, false); @@ -2307,8 +2334,8 @@ class CppGenerator : public BaseGenerator { code_ += " return static_cast({{FIELD_NAME}}() > _{{FIELD_NAME}}) - " "static_cast({{FIELD_NAME}}() < _{{FIELD_NAME}});"; - code_ += " }"; } + code_ += " }"; } void GenTableUnionAsGetters(const FieldDef &field) { diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index c63793bad..bd9780f37 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -1057,8 +1057,12 @@ 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; - if (!IsScalar(type.base_type) && !IsString(type)) { - return Error("'key' field must be string or scalar type"); + auto is_valid = IsScalar(type.base_type) || IsString(type); + if (IsArray(type)) { is_valid |= IsScalar(type.VectorType().base_type); } + if (!is_valid) { + return Error( + "'key' field must be string, scalar type or fixed size array of " + "scalars"); } } @@ -1502,7 +1506,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, if (!struct_def.sortbysize || size == SizeOf(field_value.type.base_type)) { switch (field_value.type.base_type) { - // clang-format off +// clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ case BASE_TYPE_ ## ENUM: \ builder_.Pad(field->padding); \ @@ -1631,7 +1635,7 @@ CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue, // start at the back, since we're building the data backwards. auto &val = field_stack_.back().first; switch (val.type.base_type) { - // clang-format off +// clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE,...) \ case BASE_TYPE_ ## ENUM: \ if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \ @@ -2267,8 +2271,12 @@ template void EnumDef::ChangeEnumValue(EnumVal *ev, T new_value) { } namespace EnumHelper { -template struct EnumValType { typedef int64_t type; }; -template<> struct EnumValType { typedef uint64_t type; }; +template struct EnumValType { + typedef int64_t type; +}; +template<> struct EnumValType { + typedef uint64_t type; +}; } // namespace EnumHelper struct EnumValBuilder { diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index d9048ea29..90930e6ce 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -22,6 +22,9 @@ cc_test( "is_quiet_nan.h", "json_test.cpp", "json_test.h", + "key_field/key_field_sample_generated.h", + "key_field_test.cpp", + "key_field_test.h", "monster_test.cpp", "monster_test.h", "monster_test_bfbs_generated.h", @@ -63,6 +66,7 @@ cc_test( ":evolution_test/evolution_v2.json", ":include_test/include_test1.fbs", ":include_test/sub/include_test2.fbs", + ":key_field/key_field_sample.fbs", ":monster_extra.fbs", ":monster_test.bfbs", ":monster_test.fbs", diff --git a/tests/cpp17/generated_cpp17/monster_test_generated.h b/tests/cpp17/generated_cpp17/monster_test_generated.h index 2fdeeac12..a8bd4c408 100644 --- a/tests/cpp17/generated_cpp17/monster_test_generated.h +++ b/tests/cpp17/generated_cpp17/monster_test_generated.h @@ -730,7 +730,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Ability FLATBUFFERS_FINAL_CLASS { void mutate_id(uint32_t _id) { flatbuffers::WriteScalar(&id_, _id); } - bool KeyCompareLessThan(const Ability *o) const { + bool KeyCompareLessThan(const Ability * const o) const { return id() < o->id(); } int KeyCompareWithValue(uint32_t _id) const { @@ -1094,7 +1094,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool mutate_count(uint16_t _count = 0) { return SetField(VT_COUNT, _count, 0); } - bool KeyCompareLessThan(const Stat *o) const { + bool KeyCompareLessThan(const Stat * const o) const { return count() < o->count(); } int KeyCompareWithValue(uint16_t _count) const { @@ -1207,7 +1207,7 @@ struct Referrable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool mutate_id(uint64_t _id = 0) { return SetField(VT_ID, _id, 0); } - bool KeyCompareLessThan(const Referrable *o) const { + bool KeyCompareLessThan(const Referrable * const o) const { return id() < o->id(); } int KeyCompareWithValue(uint64_t _id) const { @@ -1430,7 +1430,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { flatbuffers::String *mutable_name() { return GetPointer(VT_NAME); } - bool KeyCompareLessThan(const Monster *o) const { + bool KeyCompareLessThan(const Monster * const o) const { return *name() < *o->name(); } int KeyCompareWithValue(const char *_name) const { diff --git a/tests/key_field/key_field_sample.fbs b/tests/key_field/key_field_sample.fbs new file mode 100644 index 000000000..028920d2c --- /dev/null +++ b/tests/key_field/key_field_sample.fbs @@ -0,0 +1,21 @@ +namespace keyfield.sample; + +struct Baz { + a: [uint8:4] (key); // A fixed-sized array of uint8 as a Key + b: uint8 ; +} + +struct Bar { + a: [float:3] (key); // A fixed-sized array of float as a Key + b: uint8; +} + +table FooTable { + a: int; + b: int; + c: string (key); + d: [Baz]; + e: [Bar]; +} +root_type FooTable; + diff --git a/tests/key_field/key_field_sample_generated.h b/tests/key_field/key_field_sample_generated.h new file mode 100644 index 000000000..714de753a --- /dev/null +++ b/tests/key_field/key_field_sample_generated.h @@ -0,0 +1,260 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_KEYFIELDSAMPLE_KEYFIELD_SAMPLE_H_ +#define FLATBUFFERS_GENERATED_KEYFIELDSAMPLE_KEYFIELD_SAMPLE_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 22 && + FLATBUFFERS_VERSION_MINOR == 10 && + FLATBUFFERS_VERSION_REVISION == 26, + "Non-compatible flatbuffers version included"); + +namespace keyfield { +namespace sample { + +struct Baz; + +struct Bar; + +struct FooTable; +struct FooTableBuilder; + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(1) Baz FLATBUFFERS_FINAL_CLASS { + private: + uint8_t a_[4]; + uint8_t b_; + + public: + Baz() + : a_(), + b_(0) { + } + Baz(uint8_t _b) + : a_(), + b_(flatbuffers::EndianScalar(_b)) { + } + Baz(flatbuffers::span _a, uint8_t _b) + : b_(flatbuffers::EndianScalar(_b)) { + flatbuffers::CastToArray(a_).CopyFromSpan(_a); + } + const flatbuffers::Array *a() const { + return &flatbuffers::CastToArray(a_); + } + bool KeyCompareLessThan(const Baz * const o) const { + return KeyCompareWithValue(o->a()) < 0; + } + int KeyCompareWithValue(const flatbuffers::Array *_a) const { + for (auto i = 0; i < a()->size(); i++) { + const auto a_l = a_[i]; + const auto a_r = _a->Get(i); + if(a_l != a_r) + return static_cast(a_l > a_r) - static_cast(a_l < a_r); + } + return 0; + } + uint8_t b() const { + return flatbuffers::EndianScalar(b_); + } +}; +FLATBUFFERS_STRUCT_END(Baz, 5); + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Bar FLATBUFFERS_FINAL_CLASS { + private: + float a_[3]; + uint8_t b_; + int8_t padding0__; int16_t padding1__; + + public: + Bar() + : a_(), + b_(0), + padding0__(0), + padding1__(0) { + (void)padding0__; + (void)padding1__; + } + Bar(uint8_t _b) + : a_(), + b_(flatbuffers::EndianScalar(_b)), + padding0__(0), + padding1__(0) { + (void)padding0__; + (void)padding1__; + } + Bar(flatbuffers::span _a, uint8_t _b) + : b_(flatbuffers::EndianScalar(_b)), + padding0__(0), + padding1__(0) { + flatbuffers::CastToArray(a_).CopyFromSpan(_a); + (void)padding0__; + (void)padding1__; + } + const flatbuffers::Array *a() const { + return &flatbuffers::CastToArray(a_); + } + bool KeyCompareLessThan(const Bar * const o) const { + return KeyCompareWithValue(o->a()) < 0; + } + int KeyCompareWithValue(const flatbuffers::Array *_a) const { + for (auto i = 0; i < a()->size(); i++) { + const auto a_l = a_[i]; + const auto a_r = _a->Get(i); + if(a_l != a_r) + return static_cast(a_l > a_r) - static_cast(a_l < a_r); + } + return 0; + } + uint8_t b() const { + return flatbuffers::EndianScalar(b_); + } +}; +FLATBUFFERS_STRUCT_END(Bar, 16); + +struct FooTable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef FooTableBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_A = 4, + VT_B = 6, + VT_C = 8, + VT_D = 10, + VT_E = 12 + }; + int32_t a() const { + return GetField(VT_A, 0); + } + int32_t b() const { + return GetField(VT_B, 0); + } + const flatbuffers::String *c() const { + return GetPointer(VT_C); + } + bool KeyCompareLessThan(const FooTable * const o) const { + return *c() < *o->c(); + } + int KeyCompareWithValue(const char *_c) const { + return strcmp(c()->c_str(), _c); + } + const flatbuffers::Vector *d() const { + return GetPointer *>(VT_D); + } + const flatbuffers::Vector *e() const { + return GetPointer *>(VT_E); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_A, 4) && + VerifyField(verifier, VT_B, 4) && + VerifyOffsetRequired(verifier, VT_C) && + verifier.VerifyString(c()) && + VerifyOffset(verifier, VT_D) && + verifier.VerifyVector(d()) && + VerifyOffset(verifier, VT_E) && + verifier.VerifyVector(e()) && + verifier.EndTable(); + } +}; + +struct FooTableBuilder { + typedef FooTable Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_a(int32_t a) { + fbb_.AddElement(FooTable::VT_A, a, 0); + } + void add_b(int32_t b) { + fbb_.AddElement(FooTable::VT_B, b, 0); + } + void add_c(flatbuffers::Offset c) { + fbb_.AddOffset(FooTable::VT_C, c); + } + void add_d(flatbuffers::Offset> d) { + fbb_.AddOffset(FooTable::VT_D, d); + } + void add_e(flatbuffers::Offset> e) { + fbb_.AddOffset(FooTable::VT_E, e); + } + explicit FooTableBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + fbb_.Required(o, FooTable::VT_C); + return o; + } +}; + +inline flatbuffers::Offset CreateFooTable( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t a = 0, + int32_t b = 0, + flatbuffers::Offset c = 0, + flatbuffers::Offset> d = 0, + flatbuffers::Offset> e = 0) { + FooTableBuilder builder_(_fbb); + builder_.add_e(e); + builder_.add_d(d); + builder_.add_c(c); + builder_.add_b(b); + builder_.add_a(a); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateFooTableDirect( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t a = 0, + int32_t b = 0, + const char *c = nullptr, + std::vector *d = nullptr, + std::vector *e = nullptr) { + auto c__ = c ? _fbb.CreateString(c) : 0; + auto d__ = d ? _fbb.CreateVectorOfSortedStructs(d) : 0; + auto e__ = e ? _fbb.CreateVectorOfSortedStructs(e) : 0; + return keyfield::sample::CreateFooTable( + _fbb, + a, + b, + c__, + d__, + e__); +} + +inline const keyfield::sample::FooTable *GetFooTable(const void *buf) { + return flatbuffers::GetRoot(buf); +} + +inline const keyfield::sample::FooTable *GetSizePrefixedFooTable(const void *buf) { + return flatbuffers::GetSizePrefixedRoot(buf); +} + +inline bool VerifyFooTableBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifyBuffer(nullptr); +} + +inline bool VerifySizePrefixedFooTableBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifySizePrefixedBuffer(nullptr); +} + +inline void FinishFooTableBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.Finish(root); +} + +inline void FinishSizePrefixedFooTableBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root); +} + +} // namespace sample +} // namespace keyfield + +#endif // FLATBUFFERS_GENERATED_KEYFIELDSAMPLE_KEYFIELD_SAMPLE_H_ diff --git a/tests/key_field_test.cpp b/tests/key_field_test.cpp new file mode 100644 index 000000000..b2bf0af91 --- /dev/null +++ b/tests/key_field_test.cpp @@ -0,0 +1,72 @@ +#include "key_field_test.h" + +#include + +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "key_field/key_field_sample_generated.h" +#include "test_assert.h" + +namespace flatbuffers { +namespace tests { + +using namespace keyfield::sample; + +void FixedSizedScalarKeyInStructTest() { + flatbuffers::FlatBufferBuilder fbb; + std::vector bazs; + uint8_t test_array1[4] = { 8, 2, 3, 0 }; + uint8_t test_array2[4] = { 1, 2, 3, 4 }; + uint8_t test_array3[4] = { 2, 2, 3, 4 }; + uint8_t test_array4[4] = { 3, 2, 3, 4 }; + bazs.push_back(Baz(flatbuffers::make_span(test_array1), 4)); + bazs.push_back(Baz(flatbuffers::make_span(test_array2), 1)); + bazs.push_back(Baz(flatbuffers::make_span(test_array3), 2)); + bazs.push_back(Baz(flatbuffers::make_span(test_array4), 3)); + auto baz_vec = fbb.CreateVectorOfSortedStructs(&bazs); + auto test_string = fbb.CreateString("TEST"); + 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 }; + float test_float_array4[3] = { -1.5, 2.5, 0 }; + std::vector bars; + bars.push_back(Bar(flatbuffers::make_span(test_float_array1), 3)); + bars.push_back(Bar(flatbuffers::make_span(test_float_array2), 4)); + bars.push_back(Bar(flatbuffers::make_span(test_float_array3), 2)); + bars.push_back(Bar(flatbuffers::make_span(test_float_array4), 1)); + auto bar_vec = fbb.CreateVectorOfSortedStructs(&bars); + + auto t = CreateFooTable(fbb, 1, 2, test_string, baz_vec, bar_vec); + fbb.Finish(t); + + uint8_t *buf = fbb.GetBufferPointer(); + auto foo_table = GetFooTable(buf); + + auto sorted_baz_vec = foo_table->d(); + TEST_EQ(sorted_baz_vec->Get(0)->b(), 1); + TEST_EQ(sorted_baz_vec->Get(3)->b(), 4); + TEST_NOTNULL( + sorted_baz_vec->LookupByKey(&flatbuffers::CastToArray(test_array1))); + TEST_EQ( + sorted_baz_vec->LookupByKey(&flatbuffers::CastToArray(test_array1))->b(), + 4); + uint8_t array_int[4] = { 7, 2, 3, 0 }; + TEST_EQ(sorted_baz_vec->LookupByKey(&flatbuffers::CastToArray(array_int)), + static_cast(nullptr)); + + auto sorted_bar_vec = foo_table->e(); + TEST_EQ(sorted_bar_vec->Get(0)->b(), 1); + TEST_EQ(sorted_bar_vec->Get(3)->b(), 4); + TEST_NOTNULL(sorted_bar_vec->LookupByKey( + &flatbuffers::CastToArray(test_float_array1))); + TEST_EQ( + sorted_bar_vec->LookupByKey(&flatbuffers::CastToArray(test_float_array1)) + ->b(), + 3); + float array_float[3] = { -1, -2, -3 }; + TEST_EQ(sorted_bar_vec->LookupByKey(&flatbuffers::CastToArray(array_float)), + static_cast(nullptr)); +} + +} // namespace tests +} // namespace flatbuffers diff --git a/tests/key_field_test.h b/tests/key_field_test.h new file mode 100644 index 000000000..4cc4ddcca --- /dev/null +++ b/tests/key_field_test.h @@ -0,0 +1,12 @@ +#ifndef TESTS_KEY_FIELD_TEST_H +#define TESTS_KEY_FIELD_TEST_H + +namespace flatbuffers { +namespace tests { + +void FixedSizedScalarKeyInStructTest(); + +} // namespace tests +} // namespace flatbuffers + +#endif diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index ce5acf835..932638532 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -825,7 +825,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Ability FLATBUFFERS_FINAL_CLASS { void mutate_id(uint32_t _id) { flatbuffers::WriteScalar(&id_, _id); } - bool KeyCompareLessThan(const Ability *o) const { + bool KeyCompareLessThan(const Ability * const o) const { return id() < o->id(); } int KeyCompareWithValue(uint32_t _id) const { @@ -1123,7 +1123,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool mutate_count(uint16_t _count = 0) { return SetField(VT_COUNT, _count, 0); } - bool KeyCompareLessThan(const Stat *o) const { + bool KeyCompareLessThan(const Stat * const o) const { return count() < o->count(); } int KeyCompareWithValue(uint16_t _count) const { @@ -1213,7 +1213,7 @@ struct Referrable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool mutate_id(uint64_t _id = 0) { return SetField(VT_ID, _id, 0); } - bool KeyCompareLessThan(const Referrable *o) const { + bool KeyCompareLessThan(const Referrable * const o) const { return id() < o->id(); } int KeyCompareWithValue(uint64_t _id) const { @@ -1417,7 +1417,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { flatbuffers::String *mutable_name() { return GetPointer(VT_NAME); } - bool KeyCompareLessThan(const Monster *o) const { + bool KeyCompareLessThan(const Monster * const o) const { return *name() < *o->name(); } int KeyCompareWithValue(const char *_name) const { diff --git a/tests/monster_test_suffix/ext_only/monster_test_generated.hpp b/tests/monster_test_suffix/ext_only/monster_test_generated.hpp index ce5acf835..932638532 100644 --- a/tests/monster_test_suffix/ext_only/monster_test_generated.hpp +++ b/tests/monster_test_suffix/ext_only/monster_test_generated.hpp @@ -825,7 +825,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Ability FLATBUFFERS_FINAL_CLASS { void mutate_id(uint32_t _id) { flatbuffers::WriteScalar(&id_, _id); } - bool KeyCompareLessThan(const Ability *o) const { + bool KeyCompareLessThan(const Ability * const o) const { return id() < o->id(); } int KeyCompareWithValue(uint32_t _id) const { @@ -1123,7 +1123,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool mutate_count(uint16_t _count = 0) { return SetField(VT_COUNT, _count, 0); } - bool KeyCompareLessThan(const Stat *o) const { + bool KeyCompareLessThan(const Stat * const o) const { return count() < o->count(); } int KeyCompareWithValue(uint16_t _count) const { @@ -1213,7 +1213,7 @@ struct Referrable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool mutate_id(uint64_t _id = 0) { return SetField(VT_ID, _id, 0); } - bool KeyCompareLessThan(const Referrable *o) const { + bool KeyCompareLessThan(const Referrable * const o) const { return id() < o->id(); } int KeyCompareWithValue(uint64_t _id) const { @@ -1417,7 +1417,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { flatbuffers::String *mutable_name() { return GetPointer(VT_NAME); } - bool KeyCompareLessThan(const Monster *o) const { + bool KeyCompareLessThan(const Monster * const o) const { return *name() < *o->name(); } int KeyCompareWithValue(const char *_name) const { diff --git a/tests/monster_test_suffix/filesuffix_only/monster_test_suffix.h b/tests/monster_test_suffix/filesuffix_only/monster_test_suffix.h index ce5acf835..932638532 100644 --- a/tests/monster_test_suffix/filesuffix_only/monster_test_suffix.h +++ b/tests/monster_test_suffix/filesuffix_only/monster_test_suffix.h @@ -825,7 +825,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Ability FLATBUFFERS_FINAL_CLASS { void mutate_id(uint32_t _id) { flatbuffers::WriteScalar(&id_, _id); } - bool KeyCompareLessThan(const Ability *o) const { + bool KeyCompareLessThan(const Ability * const o) const { return id() < o->id(); } int KeyCompareWithValue(uint32_t _id) const { @@ -1123,7 +1123,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool mutate_count(uint16_t _count = 0) { return SetField(VT_COUNT, _count, 0); } - bool KeyCompareLessThan(const Stat *o) const { + bool KeyCompareLessThan(const Stat * const o) const { return count() < o->count(); } int KeyCompareWithValue(uint16_t _count) const { @@ -1213,7 +1213,7 @@ struct Referrable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool mutate_id(uint64_t _id = 0) { return SetField(VT_ID, _id, 0); } - bool KeyCompareLessThan(const Referrable *o) const { + bool KeyCompareLessThan(const Referrable * const o) const { return id() < o->id(); } int KeyCompareWithValue(uint64_t _id) const { @@ -1417,7 +1417,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { flatbuffers::String *mutable_name() { return GetPointer(VT_NAME); } - bool KeyCompareLessThan(const Monster *o) const { + bool KeyCompareLessThan(const Monster * const o) const { return *name() < *o->name(); } int KeyCompareWithValue(const char *_name) const { diff --git a/tests/monster_test_suffix/monster_test_suffix.hpp b/tests/monster_test_suffix/monster_test_suffix.hpp index ce5acf835..932638532 100644 --- a/tests/monster_test_suffix/monster_test_suffix.hpp +++ b/tests/monster_test_suffix/monster_test_suffix.hpp @@ -825,7 +825,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Ability FLATBUFFERS_FINAL_CLASS { void mutate_id(uint32_t _id) { flatbuffers::WriteScalar(&id_, _id); } - bool KeyCompareLessThan(const Ability *o) const { + bool KeyCompareLessThan(const Ability * const o) const { return id() < o->id(); } int KeyCompareWithValue(uint32_t _id) const { @@ -1123,7 +1123,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool mutate_count(uint16_t _count = 0) { return SetField(VT_COUNT, _count, 0); } - bool KeyCompareLessThan(const Stat *o) const { + bool KeyCompareLessThan(const Stat * const o) const { return count() < o->count(); } int KeyCompareWithValue(uint16_t _count) const { @@ -1213,7 +1213,7 @@ struct Referrable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool mutate_id(uint64_t _id = 0) { return SetField(VT_ID, _id, 0); } - bool KeyCompareLessThan(const Referrable *o) const { + bool KeyCompareLessThan(const Referrable * const o) const { return id() < o->id(); } int KeyCompareWithValue(uint64_t _id) const { @@ -1417,7 +1417,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { flatbuffers::String *mutable_name() { return GetPointer(VT_NAME); } - bool KeyCompareLessThan(const Monster *o) const { + bool KeyCompareLessThan(const Monster * const o) const { return *name() < *o->name(); } int KeyCompareWithValue(const char *_name) const { diff --git a/tests/test.cpp b/tests/test.cpp index 65198a67a..db2916276 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -20,8 +20,8 @@ #include #include -#include "evolution_test.h" #include "alignment_test.h" +#include "evolution_test.h" #include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" #include "flatbuffers/minireflect.h" @@ -29,10 +29,11 @@ #include "flatbuffers/util.h" #include "fuzz_test.h" #include "json_test.h" +#include "key_field_test.h" #include "monster_test.h" #include "monster_test_generated.h" -#include "optional_scalars_test.h" #include "native_inline_table_test_generated.h" +#include "optional_scalars_test.h" #include "parser_test.h" #include "proto_test.h" #include "reflection_test.h" @@ -1418,7 +1419,7 @@ void NativeInlineTableVectorTest() { TEST_ASSERT(unpacked.t == test.t); } -void DoNotRequireEofTest(const std::string& tests_data_path) { +void DoNotRequireEofTest(const std::string &tests_data_path) { std::string schemafile; bool ok = flatbuffers::LoadFile( (tests_data_path + "monster_test.fbs").c_str(), false, &schemafile); @@ -1432,7 +1433,7 @@ void DoNotRequireEofTest(const std::string& tests_data_path) { flatbuffers::Parser parser(opt); ok = parser.Parse(schemafile.c_str(), include_directories); TEST_EQ(ok, true); - + const char *str = R"(This string contains two monsters, the first one is { "name": "Blob", "hp": 5 @@ -1449,7 +1450,7 @@ void DoNotRequireEofTest(const std::string& tests_data_path) { const Monster *monster = GetMonster(parser.builder_.GetBufferPointer()); TEST_EQ_STR(monster->name()->c_str(), "Blob"); TEST_EQ(monster->hp(), 5); - + tableStart += parser.BytesConsumed(); tableStart = std::strchr(tableStart + 1, '{'); @@ -1564,6 +1565,7 @@ int FlatBufferTests(const std::string &tests_data_path) { JsonUnsortedArrayTest(); VectorSpanTest(); NativeInlineTableVectorTest(); + FixedSizedScalarKeyInStructTest(); return 0; } } // namespace