From 42b13940b82e1e8f5032d24cfcccb6a618af8980 Mon Sep 17 00:00:00 2001 From: Valentyn Pavliuchenko Date: Mon, 24 Feb 2025 12:28:51 +0200 Subject: [PATCH 1/9] Use "FLATBUFFERS_NOEXCEPT" instead of bare "noexcept". --- include/flatbuffers/array.h | 2 +- include/flatbuffers/detached_buffer.h | 4 ++-- include/flatbuffers/flatbuffer_builder.h | 4 ++-- include/flatbuffers/vector_downward.h | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/flatbuffers/array.h b/include/flatbuffers/array.h index f4bfbf054c4..6a0603b1fa7 100644 --- a/include/flatbuffers/array.h +++ b/include/flatbuffers/array.h @@ -245,7 +245,7 @@ const Array &CastToArrayOfEnum(const T (&arr)[length]) { template bool operator==(const Array &lhs, - const Array &rhs) noexcept { + const Array &rhs) FLATBUFFERS_NOEXCEPT { return std::addressof(lhs) == std::addressof(rhs) || (lhs.size() == rhs.size() && std::memcmp(lhs.Data(), rhs.Data(), rhs.size() * sizeof(T)) == 0); diff --git a/include/flatbuffers/detached_buffer.h b/include/flatbuffers/detached_buffer.h index 36d3f6d6deb..8324f0d64a3 100644 --- a/include/flatbuffers/detached_buffer.h +++ b/include/flatbuffers/detached_buffer.h @@ -45,7 +45,7 @@ class DetachedBuffer { cur_(cur), size_(sz) {} - DetachedBuffer(DetachedBuffer &&other) noexcept + DetachedBuffer(DetachedBuffer &&other) FLATBUFFERS_NOEXCEPT : allocator_(other.allocator_), own_allocator_(other.own_allocator_), buf_(other.buf_), @@ -55,7 +55,7 @@ class DetachedBuffer { other.reset(); } - DetachedBuffer &operator=(DetachedBuffer &&other) noexcept { + DetachedBuffer &operator=(DetachedBuffer &&other) FLATBUFFERS_NOEXCEPT { if (this == &other) return *this; destroy(); diff --git a/include/flatbuffers/flatbuffer_builder.h b/include/flatbuffers/flatbuffer_builder.h index 9ceca8207b6..db459367a2a 100644 --- a/include/flatbuffers/flatbuffer_builder.h +++ b/include/flatbuffers/flatbuffer_builder.h @@ -112,7 +112,7 @@ template class FlatBufferBuilderImpl { } /// @brief Move constructor for FlatBufferBuilder. - FlatBufferBuilderImpl(FlatBufferBuilderImpl &&other) noexcept + FlatBufferBuilderImpl(FlatBufferBuilderImpl &&other) FLATBUFFERS_NOEXCEPT : buf_(1024, nullptr, false, AlignOf(), static_cast(Is64Aware ? FLATBUFFERS_MAX_64_BUFFER_SIZE : FLATBUFFERS_MAX_BUFFER_SIZE)), @@ -133,7 +133,7 @@ template class FlatBufferBuilderImpl { } /// @brief Move assignment operator for FlatBufferBuilder. - FlatBufferBuilderImpl &operator=(FlatBufferBuilderImpl &&other) noexcept { + FlatBufferBuilderImpl &operator=(FlatBufferBuilderImpl &&other) FLATBUFFERS_NOEXCEPT { // Move construct a temporary and swap idiom FlatBufferBuilderImpl temp(std::move(other)); Swap(temp); diff --git a/include/flatbuffers/vector_downward.h b/include/flatbuffers/vector_downward.h index 2b5a92cf171..48f23bd1474 100644 --- a/include/flatbuffers/vector_downward.h +++ b/include/flatbuffers/vector_downward.h @@ -48,7 +48,7 @@ template class vector_downward { cur_(nullptr), scratch_(nullptr) {} - vector_downward(vector_downward &&other) noexcept + vector_downward(vector_downward &&other) FLATBUFFERS_NOEXCEPT // clang-format on : allocator_(other.allocator_), own_allocator_(other.own_allocator_), @@ -70,7 +70,7 @@ template class vector_downward { other.scratch_ = nullptr; } - vector_downward &operator=(vector_downward &&other) noexcept { + vector_downward &operator=(vector_downward &&other) FLATBUFFERS_NOEXCEPT { // Move construct a temporary and swap idiom vector_downward temp(std::move(other)); swap(temp); From 7637ddab57cba9a77d20960189e439101d1deeb0 Mon Sep 17 00:00:00 2001 From: Valentyn Pavliuchenko Date: Mon, 24 Feb 2025 12:28:58 +0200 Subject: [PATCH 2/9] Old compiler support: use "FLATBUFFERS_CONSTEXPR" instead of bare "constexpr". --- src/idl_gen_fbs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/idl_gen_fbs.cpp b/src/idl_gen_fbs.cpp index f9844854d44..cd5ee4ab666 100644 --- a/src/idl_gen_fbs.cpp +++ b/src/idl_gen_fbs.cpp @@ -196,7 +196,7 @@ static ProtobufToFbsIdMap MapProtoIdsToFieldsId( if (!ProtobufIdSanityCheck(struct_def, gap_action, no_log)) { return {}; } - static constexpr int UNION_ID = -1; + static FLATBUFFERS_CONSTEXPR int UNION_ID = -1; using ProtoIdFieldNamePair = std::pair; std::vector proto_ids; From eff3a72c276c7d376316b03f49b2c38deb59d084 Mon Sep 17 00:00:00 2001 From: Valentyn Pavliuchenko Date: Mon, 24 Feb 2025 12:29:04 +0200 Subject: [PATCH 3/9] Fixed compilation by old compilers that doesn't support defaulting move constructors. --- include/flatbuffers/flatc.h | 2 +- include/flatbuffers/idl.h | 2 ++ samples/monster_generated.h | 2 ++ src/flatc.cpp | 9 ++++----- src/idl_gen_cpp.cpp | 2 ++ tests/64bit/test_64bit_generated.h | 2 ++ tests/cpp17/generated_cpp17/monster_test_generated.h | 2 ++ tests/monster_test_generated.h | 2 ++ .../ext_only/monster_test_generated.hpp | 2 ++ .../filesuffix_only/monster_test_suffix.h | 2 ++ tests/monster_test_suffix/monster_test_suffix.hpp | 2 ++ tests/namespace_test/namespace_test2_generated.h | 6 ++++++ 12 files changed, 29 insertions(+), 6 deletions(-) diff --git a/include/flatbuffers/flatc.h b/include/flatbuffers/flatc.h index e98eb80d7fb..ecf77953241 100644 --- a/include/flatbuffers/flatc.h +++ b/include/flatbuffers/flatc.h @@ -116,7 +116,7 @@ class FlatCompiler { void ValidateOptions(const FlatCOptions &options); - Parser GetConformParser(const FlatCOptions &options); + void GetConformParser(const FlatCOptions &options, Parser &conform_parser); std::unique_ptr GenerateCode(const FlatCOptions &options, Parser &conform_parser); diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index c84999a5485..380693a00fb 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -1009,8 +1009,10 @@ class Parser : public ParserState { Parser(const Parser &) = delete; Parser &operator=(const Parser &) = delete; +#ifdef FLATBUFFERS_DEFAULT_DECLARATION Parser(Parser &&) = default; Parser &operator=(Parser &&) = default; +#endif ~Parser() { for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) { diff --git a/samples/monster_generated.h b/samples/monster_generated.h index 10141753c12..fdbfed9282b 100644 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -248,7 +248,9 @@ struct MonsterT : public ::flatbuffers::NativeTable { std::vector path{}; MonsterT() = default; MonsterT(const MonsterT &o); +#ifdef FLATBUFFERS_DEFAULT_DECLARATION MonsterT(MonsterT&&) FLATBUFFERS_NOEXCEPT = default; +#endif MonsterT &operator=(MonsterT o) FLATBUFFERS_NOEXCEPT; }; diff --git a/src/flatc.cpp b/src/flatc.cpp index d06e858a11d..fab52eba39d 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -778,9 +778,8 @@ void FlatCompiler::ValidateOptions(const FlatCOptions &options) { } } -flatbuffers::Parser FlatCompiler::GetConformParser( - const FlatCOptions &options) { - flatbuffers::Parser conform_parser; +void FlatCompiler::GetConformParser( + const FlatCOptions &options, flatbuffers::Parser &conform_parser) { // conform parser should check advanced options, // so, it have to have knowledge about languages: @@ -801,7 +800,6 @@ flatbuffers::Parser FlatCompiler::GetConformParser( options.conform_include_directories); } } - return conform_parser; } std::unique_ptr FlatCompiler::GenerateCode(const FlatCOptions &options, @@ -985,7 +983,8 @@ std::unique_ptr FlatCompiler::GenerateCode(const FlatCOptions &options, int FlatCompiler::Compile(const FlatCOptions &options) { // TODO(derekbailey): change to std::optional - Parser conform_parser = GetConformParser(options); + Parser conform_parser; + GetConformParser(options, conform_parser); // TODO(derekbailey): split to own method. if (!options.annotate_schema.empty()) { diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 37fbccc5920..3c7e756ec77 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -2018,9 +2018,11 @@ class CppGenerator : public BaseGenerator { code_.SetValue("NATIVE_NAME", NativeName(Name(struct_def), &struct_def, opts_)); code_ += " {{NATIVE_NAME}}(const {{NATIVE_NAME}} &o);"; + code_ += "#ifdef FLATBUFFERS_DEFAULT_DECLARATION"; code_ += " {{NATIVE_NAME}}({{NATIVE_NAME}}&&) FLATBUFFERS_NOEXCEPT = " "default;"; + code_ += "#endif"; code_ += " {{NATIVE_NAME}} &operator=({{NATIVE_NAME}} o) FLATBUFFERS_NOEXCEPT;"; } diff --git a/tests/64bit/test_64bit_generated.h b/tests/64bit/test_64bit_generated.h index 4233f843015..5f8aa497ffd 100644 --- a/tests/64bit/test_64bit_generated.h +++ b/tests/64bit/test_64bit_generated.h @@ -170,7 +170,9 @@ struct RootTableT : public ::flatbuffers::NativeTable { std::vector forced_aligned_vector{}; RootTableT() = default; RootTableT(const RootTableT &o); +#ifdef FLATBUFFERS_DEFAULT_DECLARATION RootTableT(RootTableT&&) FLATBUFFERS_NOEXCEPT = default; +#endif RootTableT &operator=(RootTableT o) FLATBUFFERS_NOEXCEPT; }; diff --git a/tests/cpp17/generated_cpp17/monster_test_generated.h b/tests/cpp17/generated_cpp17/monster_test_generated.h index 037027fb9f0..2290a48a051 100644 --- a/tests/cpp17/generated_cpp17/monster_test_generated.h +++ b/tests/cpp17/generated_cpp17/monster_test_generated.h @@ -1331,7 +1331,9 @@ struct MonsterT : public ::flatbuffers::NativeTable { double double_inf_default = std::numeric_limits::infinity(); MonsterT() = default; MonsterT(const MonsterT &o); +#ifdef FLATBUFFERS_DEFAULT_DECLARATION MonsterT(MonsterT&&) FLATBUFFERS_NOEXCEPT = default; +#endif MonsterT &operator=(MonsterT o) FLATBUFFERS_NOEXCEPT; }; diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index df6367e1314..1f686b19224 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -1327,7 +1327,9 @@ struct MonsterT : public ::flatbuffers::NativeTable { double double_inf_default = std::numeric_limits::infinity(); MonsterT() = default; MonsterT(const MonsterT &o); +#ifdef FLATBUFFERS_DEFAULT_DECLARATION MonsterT(MonsterT&&) FLATBUFFERS_NOEXCEPT = default; +#endif MonsterT &operator=(MonsterT o) FLATBUFFERS_NOEXCEPT; }; 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 fd292b0f327..ac80f37de20 100644 --- a/tests/monster_test_suffix/ext_only/monster_test_generated.hpp +++ b/tests/monster_test_suffix/ext_only/monster_test_generated.hpp @@ -1319,7 +1319,9 @@ struct MonsterT : public ::flatbuffers::NativeTable { double double_inf_default = std::numeric_limits::infinity(); MonsterT() = default; MonsterT(const MonsterT &o); +#ifdef FLATBUFFERS_DEFAULT_DECLARATION MonsterT(MonsterT&&) FLATBUFFERS_NOEXCEPT = default; +#endif MonsterT &operator=(MonsterT o) FLATBUFFERS_NOEXCEPT; }; 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 fd292b0f327..ac80f37de20 100644 --- a/tests/monster_test_suffix/filesuffix_only/monster_test_suffix.h +++ b/tests/monster_test_suffix/filesuffix_only/monster_test_suffix.h @@ -1319,7 +1319,9 @@ struct MonsterT : public ::flatbuffers::NativeTable { double double_inf_default = std::numeric_limits::infinity(); MonsterT() = default; MonsterT(const MonsterT &o); +#ifdef FLATBUFFERS_DEFAULT_DECLARATION MonsterT(MonsterT&&) FLATBUFFERS_NOEXCEPT = default; +#endif MonsterT &operator=(MonsterT o) FLATBUFFERS_NOEXCEPT; }; diff --git a/tests/monster_test_suffix/monster_test_suffix.hpp b/tests/monster_test_suffix/monster_test_suffix.hpp index fd292b0f327..ac80f37de20 100644 --- a/tests/monster_test_suffix/monster_test_suffix.hpp +++ b/tests/monster_test_suffix/monster_test_suffix.hpp @@ -1319,7 +1319,9 @@ struct MonsterT : public ::flatbuffers::NativeTable { double double_inf_default = std::numeric_limits::infinity(); MonsterT() = default; MonsterT(const MonsterT &o); +#ifdef FLATBUFFERS_DEFAULT_DECLARATION MonsterT(MonsterT&&) FLATBUFFERS_NOEXCEPT = default; +#endif MonsterT &operator=(MonsterT o) FLATBUFFERS_NOEXCEPT; }; diff --git a/tests/namespace_test/namespace_test2_generated.h b/tests/namespace_test/namespace_test2_generated.h index cf3a528d794..96e3c0b6902 100644 --- a/tests/namespace_test/namespace_test2_generated.h +++ b/tests/namespace_test/namespace_test2_generated.h @@ -75,7 +75,9 @@ struct TableInFirstNST : public ::flatbuffers::NativeTable { std::unique_ptr foo_struct{}; TableInFirstNST() = default; TableInFirstNST(const TableInFirstNST &o); +#ifdef FLATBUFFERS_DEFAULT_DECLARATION TableInFirstNST(TableInFirstNST&&) FLATBUFFERS_NOEXCEPT = default; +#endif TableInFirstNST &operator=(TableInFirstNST o) FLATBUFFERS_NOEXCEPT; }; @@ -207,7 +209,9 @@ struct TableInCT : public ::flatbuffers::NativeTable { std::unique_ptr refer_to_a2{}; TableInCT() = default; TableInCT(const TableInCT &o); +#ifdef FLATBUFFERS_DEFAULT_DECLARATION TableInCT(TableInCT&&) FLATBUFFERS_NOEXCEPT = default; +#endif TableInCT &operator=(TableInCT o) FLATBUFFERS_NOEXCEPT; }; @@ -294,7 +298,9 @@ struct SecondTableInAT : public ::flatbuffers::NativeTable { std::unique_ptr refer_to_c{}; SecondTableInAT() = default; SecondTableInAT(const SecondTableInAT &o); +#ifdef FLATBUFFERS_DEFAULT_DECLARATION SecondTableInAT(SecondTableInAT&&) FLATBUFFERS_NOEXCEPT = default; +#endif SecondTableInAT &operator=(SecondTableInAT o) FLATBUFFERS_NOEXCEPT; }; From 7b416743e48ffe41f36d75f3cfc0df801d6ab159 Mon Sep 17 00:00:00 2001 From: Valentyn Pavliuchenko Date: Mon, 24 Feb 2025 12:29:11 +0200 Subject: [PATCH 4/9] Fixed getting reference to a temporary + fixed compilation and subtle FlatCOptions copying bugs on VS2013. --- include/flatbuffers/flatc.h | 11 ++++++++++- src/flatc.cpp | 11 ++++------- src/flatc_main.cpp | 4 ++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/include/flatbuffers/flatc.h b/include/flatbuffers/flatc.h index ecf77953241..51b765b2423 100644 --- a/include/flatbuffers/flatc.h +++ b/include/flatbuffers/flatc.h @@ -34,6 +34,15 @@ extern void LogCompilerWarn(const std::string &warn); extern void LogCompilerError(const std::string &err); struct FlatCOptions { + FlatCOptions() = default; + FlatCOptions(const FlatCOptions&) = delete; + FlatCOptions(FlatCOptions&&) = delete; + + ~FlatCOptions() = default; + + FlatCOptions& operator=(const FlatCOptions&) = delete; + FlatCOptions& operator=(FlatCOptions&&) = delete; + IDLOptions opts; std::string program_name; @@ -95,7 +104,7 @@ class FlatCompiler { std::string GetUsageString(const std::string &program_name) const; // Parse the FlatC options from command line arguments. - FlatCOptions ParseFromCommandLineArguments(int argc, const char **argv); + void ParseFromCommandLineArguments(int argc, const char **argv, FlatCOptions& options); private: void ParseFile(flatbuffers::Parser &parser, const std::string &filename, diff --git a/src/flatc.cpp b/src/flatc.cpp index fab52eba39d..8cf8bdc8246 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -431,12 +431,11 @@ void FlatCompiler::AnnotateBinaries(const uint8_t *binary_schema, } } -FlatCOptions FlatCompiler::ParseFromCommandLineArguments(int argc, - const char **argv) { +void FlatCompiler::ParseFromCommandLineArguments(int argc, + const char **argv, + FlatCOptions& options) { if (argc <= 1) { Error("Need to provide at least one argument."); } - FlatCOptions options; - options.program_name = std::string(argv[0]); IDLOptions &opts = options.opts; @@ -734,7 +733,7 @@ FlatCOptions FlatCompiler::ParseFromCommandLineArguments(int argc, auto code_generator_it = code_generators_.find(arg); if (code_generator_it == code_generators_.end()) { Error("unknown commandline argument: " + arg, true); - return options; + return; } std::shared_ptr code_generator = @@ -754,8 +753,6 @@ FlatCOptions FlatCompiler::ParseFromCommandLineArguments(int argc, options.filenames.push_back(flatbuffers::PosixPath(argv[argi])); } } - - return options; } void FlatCompiler::ValidateOptions(const FlatCOptions &options) { diff --git a/src/flatc_main.cpp b/src/flatc_main.cpp index 45f95a08f73..064949a3cde 100644 --- a/src/flatc_main.cpp +++ b/src/flatc_main.cpp @@ -176,8 +176,8 @@ int main(int argc, const char *argv[]) { flatbuffers::NewTsCodeGenerator()); // Create the FlatC options by parsing the command line arguments. - const flatbuffers::FlatCOptions &options = - flatc.ParseFromCommandLineArguments(argc, argv); + flatbuffers::FlatCOptions options; + flatc.ParseFromCommandLineArguments(argc, argv, options); // Compile with the extracted FlatC options. return flatc.Compile(options); From cad8e91fc9eae1bdc1b6419b1f13d5618c4cfe0d Mon Sep 17 00:00:00 2001 From: Valentyn Pavliuchenko Date: Mon, 24 Feb 2025 12:29:18 +0200 Subject: [PATCH 5/9] Fixed build error with Visual Studio 2013 ("you cannot construct an instance of a lambda"). --- src/flatc.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/flatc.cpp b/src/flatc.cpp index 8cf8bdc8246..eab13d40ef4 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -272,8 +272,11 @@ const static FlatCOption flatc_options[] = { "The handlers will use the generated classes rather than raw bytes." }, }; -auto cmp = [](FlatCOption a, FlatCOption b) { return a.long_opt < b.long_opt; }; -static std::set language_options(cmp); +struct cmp { + bool operator()(const FlatCOption& a, const FlatCOption& b) const { return a.long_opt < b.long_opt; } +}; + +static std::set language_options((cmp())); static void AppendTextWrappedString(std::stringstream &ss, std::string &text, size_t max_col, size_t start_col) { From 17365e1a775e73fe87485254debd031ec4e2ebd2 Mon Sep 17 00:00:00 2001 From: Valentyn Pavliuchenko Date: Mon, 24 Feb 2025 12:29:21 +0200 Subject: [PATCH 6/9] Fixed build error on VS2013. --- tests/monster_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/monster_test.cpp b/tests/monster_test.cpp index b546d2074d8..38cdc22e9c6 100644 --- a/tests/monster_test.cpp +++ b/tests/monster_test.cpp @@ -96,7 +96,7 @@ flatbuffers::DetachedBuffer CreateFlatBufferTest(std::string &buffer) { #endif // Make sure the template deduces an initializer as std::vector - builder.CreateVectorOfStrings({ "hello", "world" }); + builder.CreateVectorOfStrings(std::vector{ "hello", "world" }); // Create many vectors of strings std::vector manyNames; From 1a9f41e1e65a4e62ff289f5ba4a51d22c785d5d5 Mon Sep 17 00:00:00 2001 From: Valentyn Pavliuchenko Date: Mon, 24 Feb 2025 12:29:25 +0200 Subject: [PATCH 7/9] Fixed VS2013-specific warnings. --- include/flatbuffers/base.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/flatbuffers/base.h b/include/flatbuffers/base.h index 84cb0a7d16d..16783ac1e8f 100644 --- a/include/flatbuffers/base.h +++ b/include/flatbuffers/base.h @@ -172,6 +172,15 @@ namespace flatbuffers { #else #define FLATBUFFERS_CONSTEXPR const #define FLATBUFFERS_CONSTEXPR_CPP11 + #if defined _MSC_VER && _MSC_VER == 1800 + // disable VS2013 warning when if() condition is a constant expression + #pragma warning (disable: 4127) + #endif +#endif + +#if defined _MSC_VER && _MSC_VER == 1800 + // disabled the warning about behavior change that now conforms to the standard + #pragma warning (disable: 4351) #endif #if (defined(__cplusplus) && __cplusplus >= 201402L) || \ From a3bf13ad4e6154e86e10892f1500c29d1c67a2fc Mon Sep 17 00:00:00 2001 From: Valentyn Pavliuchenko Date: Mon, 24 Feb 2025 12:29:28 +0200 Subject: [PATCH 8/9] Fixed float to string and string to float conversions on VS2013. --- include/flatbuffers/util.h | 63 +++++++++++++++++++++++++++++++ src/annotated_binary_text_gen.cpp | 3 ++ 2 files changed, 66 insertions(+) diff --git a/include/flatbuffers/util.h b/include/flatbuffers/util.h index 82b37fb9867..99f70d79141 100644 --- a/include/flatbuffers/util.h +++ b/include/flatbuffers/util.h @@ -149,9 +149,45 @@ template<> inline std::string NumToString(char t) { return NumToString(static_cast(t)); } +#if defined _MSC_VER && _MSC_VER <= 1800 +#define FLATBUFFERS_EXPLICIT_INF_NAN_CONVERSION +#endif + +template +bool ExplicitlyConvertSpecialValues(T value, std::string &result, typename std::enable_if::value>::type* = nullptr) { +#ifdef FLATBUFFERS_EXPLICIT_INF_NAN_CONVERSION + if (value == std::numeric_limits::infinity()) { + result = "inf"; + return true; + } + if (value == -std::numeric_limits::infinity()) { + result = "-inf"; + return true; + } + if (std::isnan(value)) { + result = std::signbit(value) ? "-nan" : "nan"; + return true; + } +#else + (void)value; + (void)result; +#endif + return false; +} + +template +bool ExplicitlyConvertSpecialValues(T value, std::string &result, typename std::enable_if::value>::type* = nullptr) { + (void)value; + (void)result; + return false; +} // Special versions for floats/doubles. template std::string FloatToString(T t, int precision) { // clang-format off + std::string res; + if (ExplicitlyConvertSpecialValues(t, res)) { + return res; + } #ifndef FLATBUFFERS_PREFER_PRINTF // to_string() prints different numbers of digits for floats depending on @@ -306,12 +342,39 @@ inline bool StringToIntegerImpl(T *val, const char *const str, } } +inline bool MatchFloatToString(const char *const str, const char *const constant_str, const char *& end) { + if (strcmp(str, constant_str) == 0) { + end = const_cast(str + strlen(constant_str)); + return true; + } + return false; +} + template inline bool StringToFloatImpl(T *val, const char *const str) { // Type T must be either float or double. FLATBUFFERS_ASSERT(str && val); auto end = str; +#ifdef FLATBUFFERS_EXPLICIT_INF_NAN_CONVERSION + if (MatchFloatToString(str, "inf", end) || + MatchFloatToString(str, "+inf", end) || + MatchFloatToString(str, "infinity", end) || + MatchFloatToString(str, "+infinity", end)) { + *val = std::numeric_limits::infinity(); + } else if (MatchFloatToString(str, "-inf", end) || + MatchFloatToString(str, "-infinity", end)) { + *val = -std::numeric_limits::infinity(); + } else if (MatchFloatToString(str, "nan", end) || + MatchFloatToString(str, "+nan", end)) { + *val = std::numeric_limits::quiet_NaN(); + } else if (MatchFloatToString(str, "-nan", end)) { + *val = -std::numeric_limits::quiet_NaN(); + } else { + strtoval_impl(val, str, const_cast(&end)); + } +#else strtoval_impl(val, str, const_cast(&end)); +#endif auto done = (end != str) && (*end == '\0'); if (!done) *val = 0; // erase partial result if (done && std::isnan(*val)) { *val = std::numeric_limits::quiet_NaN(); } diff --git a/src/annotated_binary_text_gen.cpp b/src/annotated_binary_text_gen.cpp index 87ab231ee28..f3dbfe54a02 100644 --- a/src/annotated_binary_text_gen.cpp +++ b/src/annotated_binary_text_gen.cpp @@ -53,6 +53,9 @@ static bool IsOffset(const BinaryRegionType type) { template std::string ToString(T value) { if (std::is_floating_point::value) { + std::string res; + if (ExplicitlyConvertSpecialValues(value, res)) + return res; std::stringstream ss; ss << value; return ss.str(); From 8989319b3bd0209cb8118bc8166193aaa25d9ac2 Mon Sep 17 00:00:00 2001 From: Valentyn Pavliuchenko Date: Mon, 24 Feb 2025 12:29:33 +0200 Subject: [PATCH 9/9] Fixed compilation on VS2013 by providing workarounds for VS2013 buggy template template pack handling. --- include/flatbuffers/flatbuffer_builder.h | 107 +++++++++++++++++++---- src/idl_gen_cpp.cpp | 8 +- tests/64bit/offset64_test.cpp | 6 +- tests/64bit/test_64bit_generated.h | 12 +-- 4 files changed, 102 insertions(+), 31 deletions(-) diff --git a/include/flatbuffers/flatbuffer_builder.h b/include/flatbuffers/flatbuffer_builder.h index db459367a2a..87377db31e0 100644 --- a/include/flatbuffers/flatbuffer_builder.h +++ b/include/flatbuffers/flatbuffer_builder.h @@ -726,19 +726,21 @@ template class FlatBufferBuilderImpl { /// @brief Serialize an array into a FlatBuffer `vector`. /// @tparam T The data type of the array elements. - /// @tparam OffsetT the type of offset to return + /// @tparam OffsetT the type of offset to return. /// @tparam VectorT the type of vector to cast to. + /// @tparam SizeT the size type to use in the VectorT vector. /// @param[in] v A pointer to the array of type `T` to serialize into the /// buffer as a `vector`. /// @param[in] len The number of elements to serialize. /// @return Returns a typed `TOffset` into the serialized data indicating /// where the vector is stored. - template class OffsetT = Offset, - template class VectorT = Vector> - OffsetT> CreateVector(const T *v, size_t len) { + template class OffsetT, + template class VectorT, + typename SizeT = typename VectorT::size_type> + OffsetT> CreateVector(const T *v, size_t len) { // The type of the length field in the vector. - typedef typename VectorT::size_type LenT; - typedef typename OffsetT>::offset_type offset_type; + typedef typename VectorT::size_type LenT; + typedef typename OffsetT>::offset_type offset_type; // If this assert hits, you're specifying a template argument that is // causing the wrong overload to be selected, remove it. AssertScalarT(); @@ -758,7 +760,20 @@ template class FlatBufferBuilderImpl { #endif // clang-format on } - return OffsetT>(EndVector(len)); + return OffsetT>(EndVector(len)); + } + + /// @brief Serialize an array into a FlatBuffer `vector`. + /// @tparam T The data type of the array elements. + /// @tparam OffsetT the type of offset to return + /// @param[in] v A pointer to the array of type `T` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `TOffset` into the serialized data indicating + /// where the vector is stored. + template class OffsetT = Offset> + OffsetT> CreateVector(const T *v, size_t len) { + return CreateVector::size_type>(v, len); } /// @brief Serialize an array like object into a FlatBuffer `vector`. @@ -800,10 +815,22 @@ template class FlatBufferBuilderImpl { return CreateVector(data(v), v.size()); } - template class VectorT = Vector64, + template class VectorT, + typename SizeT, int &...ExplicitArgumentBarrier, typename T> + Offset64> CreateVector64(const std::vector &v) { + return CreateVector(data(v), v.size()); + } + + template class VectorT, + int &...ExplicitArgumentBarrier, typename T> Offset64> CreateVector64(const std::vector &v) { - return CreateVector(data(v), v.size()); + return CreateVector64::size_type>(v); + } + + template + Offset64> CreateVector64(const std::vector &v) { + return CreateVector64::size_type>(v); } // vector may be implemented using a bit-set, so we can't access it as @@ -899,23 +926,38 @@ template class FlatBufferBuilderImpl { /// @brief Serialize an array of structs into a FlatBuffer `vector`. /// @tparam T The data type of the struct array elements. + /// @tparam OffsetT the type of offset to return. + /// @tparam VectorT the type of vector to cast to. + /// @tparam SizeT the size type to use in the VectorT vector. /// @param[in] v A pointer to the array of type `T` to serialize into the /// buffer as a `vector`. /// @param[in] len The number of elements to serialize. /// @return Returns a typed `Offset` into the serialized data indicating /// where the vector is stored. template class OffsetT = Offset, - template class VectorT = Vector> - OffsetT> CreateVectorOfStructs(const T *v, size_t len) { + template class VectorT, typename SizeT = typename VectorT::size_type> + OffsetT> CreateVectorOfStructs(const T *v, size_t len) { // The type of the length field in the vector. - typedef typename VectorT::size_type LenT; - typedef typename OffsetT>::offset_type offset_type; + typedef typename VectorT::size_type LenT; + typedef typename OffsetT>::offset_type offset_type; StartVector(len, sizeof(T), AlignOf()); if (len > 0) { PushBytes(reinterpret_cast(v), sizeof(T) * len); } - return OffsetT>(EndVector(len)); + return OffsetT>(EndVector(len)); + } + + /// @brief Serialize an array of structs into a FlatBuffer `vector`. + /// @tparam T The data type of the struct array elements. + /// @param[in] v A pointer to the array of type `T` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVectorOfStructs(const T *v, size_t len) { + return CreateVectorOfStructs::size_type>(v, len); } /// @brief Serialize an array of structs into a FlatBuffer `vector`. @@ -959,22 +1001,51 @@ template class FlatBufferBuilderImpl { /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`. /// @tparam T The data type of the `std::vector` struct elements. + /// @tparam OffsetT the type of offset to return. + /// @tparam VectorT the type of vector to cast to. + /// @tparam Alloc the allocator used by the parameter. + /// @tparam SizeT the size type to use in the VectorT vector. /// @param[in] v A const reference to the `std::vector` of structs to /// serialize into the buffer as a `vector`. /// @return Returns a typed `Offset` into the serialized data indicating /// where the vector is stored. template class OffsetT = Offset, template class VectorT = Vector, - typename Alloc = std::allocator> + typename Alloc = std::allocator, typename SizeT = typename VectorT::size_type> OffsetT> CreateVectorOfStructs( const std::vector &v) { return CreateVectorOfStructs(data(v), v.size()); } - template class VectorT = Vector64, int &..., typename T> + /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`. + /// @tparam T The data type of the `std::vector` struct elements. + /// @param[in] v A const reference to the `std::vector` of structs to + /// serialize into the buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVectorOfStructs( + const std::vector> &v) { + return CreateVectorOfStructs::size_type>(data(v), v.size()); + } + + template class VectorT, typename SizeT, + int &..., typename T> + Offset64> CreateVectorOfStructs64( + const std::vector &v) { + return CreateVectorOfStructs(data(v), v.size()); + } + + template + Offset64> CreateVectorOfStructs64( + const std::vector &v) { + return CreateVectorOfStructs::size_type>(data(v), v.size()); + } + + template class VectorT, int &..., typename T> Offset64> CreateVectorOfStructs64( const std::vector &v) { - return CreateVectorOfStructs(data(v), v.size()); + return CreateVectorOfStructs64::size_type>(data(v), v.size()); } /// @brief Serialize an array of native structs into a FlatBuffer `vector`. @@ -1087,7 +1158,7 @@ template class FlatBufferBuilderImpl { template Offset> CreateVectorOfSortedStructs(T *v, size_t len) { std::stable_sort(v, v + len, StructKeyComparator()); - return CreateVectorOfStructs(v, len); + return CreateVectorOfStructs(v, len); } /// @brief Serialize an array of native structs into a FlatBuffer `vector` in diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 3c7e756ec77..619dd5a8a05 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -3147,7 +3147,7 @@ class CppGenerator : public BaseGenerator { code_ += "_fbb.CreateVectorOfStructs\\"; if (field->offset64) { // This is normal 32-bit vector, with 64-bit addressing. - code_ += "64<::flatbuffers::Vector>\\"; + code_ += "64<::flatbuffers::Vector, ::flatbuffers::uoffset_t>\\"; } else { code_ += "<" + type + ">\\"; } @@ -3166,7 +3166,7 @@ class CppGenerator : public BaseGenerator { // If the field uses 64-bit addressing, create a 64-bit vector. code_.SetValue("64OFFSET", field->offset64 ? "64" : ""); code_.SetValue("TYPE", - field->offset64 ? "::flatbuffers::Vector" : type); + field->offset64 ? "::flatbuffers::Vector, ::flatbuffers::uoffset_t" : type); code_ += "_fbb.CreateVector{{64OFFSET}}<{{TYPE}}>\\"; } @@ -3499,7 +3499,7 @@ class CppGenerator : public BaseGenerator { code += "_fbb.CreateVectorOfStructs"; if (field.offset64) { // This is normal 32-bit vector, with 64-bit addressing. - code += "64<::flatbuffers::Vector>"; + code += "64<::flatbuffers::Vector, ::flatbuffers::uoffset_t>"; } } code += "(" + value + ")"; @@ -3576,7 +3576,7 @@ class CppGenerator : public BaseGenerator { code += "_fbb.CreateVector"; if (field.offset64) { // This is normal 32-bit vector, with 64-bit addressing. - code += "64<::flatbuffers::Vector>"; + code += "64<::flatbuffers::Vector, ::flatbuffers::uoffset_t>"; } code += "(" + value + ")"; } diff --git a/tests/64bit/offset64_test.cpp b/tests/64bit/offset64_test.cpp index ce9e022eeba..2fdaf95d632 100644 --- a/tests/64bit/offset64_test.cpp +++ b/tests/64bit/offset64_test.cpp @@ -41,7 +41,7 @@ void Offset64Test() { // Then serialize all the fields that have 64-bit offsets, as these must be // serialized before any 32-bit fields are added to the buffer. const Offset64> far_vector_offset = - builder.CreateVector64(far_data); + builder.CreateVector64(far_data); const Offset64 far_string_offset = builder.CreateString("some far string"); @@ -136,7 +136,7 @@ void Offset64NestedFlatBuffer() { fbb.Clear(); const Offset64> nested_flatbuffer_offset = - fbb.CreateVector64(nested_data); + fbb.CreateVector64(nested_data); // Now that we are done with the 64-bit fields, we can create and add the // normal fields. @@ -387,7 +387,7 @@ void Offset64ManyVectors() { // of putting all 64-bit things at the tail of the buffer. std::array>, kNumVectors> offsets_64bit; for (size_t i = 0; i < kNumVectors; ++i) { - offsets_64bit[i] = builder.CreateVector64(data); + offsets_64bit[i] = builder.CreateVector64(data); } // Create some unrelated, 64-bit offset value for later testing. diff --git a/tests/64bit/test_64bit_generated.h b/tests/64bit/test_64bit_generated.h index 5f8aa497ffd..4a692f2ba58 100644 --- a/tests/64bit/test_64bit_generated.h +++ b/tests/64bit/test_64bit_generated.h @@ -148,7 +148,7 @@ inline ::flatbuffers::Offset CreateWrapperTable( inline ::flatbuffers::Offset CreateWrapperTableDirect( ::flatbuffers::FlatBufferBuilder64 &_fbb, const std::vector *vector = nullptr) { - auto vector__ = vector ? _fbb.CreateVector64<::flatbuffers::Vector>(*vector) : 0; + auto vector__ = vector ? _fbb.CreateVector64<::flatbuffers::Vector, ::flatbuffers::uoffset_t>(*vector) : 0; return CreateWrapperTable( _fbb, vector__); @@ -373,11 +373,11 @@ inline ::flatbuffers::Offset CreateRootTableDirect( const std::vector *big_struct_vector = nullptr, const std::vector<::flatbuffers::Offset> *many_vectors = nullptr, const std::vector *forced_aligned_vector = nullptr) { - auto far_vector__ = far_vector ? _fbb.CreateVector64<::flatbuffers::Vector>(*far_vector) : 0; + auto far_vector__ = far_vector ? _fbb.CreateVector64<::flatbuffers::Vector, ::flatbuffers::uoffset_t>(*far_vector) : 0; auto far_string__ = far_string ? _fbb.CreateString<::flatbuffers::Offset64>(far_string) : 0; auto big_vector__ = big_vector ? _fbb.CreateVector64(*big_vector) : 0; auto nested_root__ = nested_root ? _fbb.CreateVector64(*nested_root) : 0; - auto far_struct_vector__ = far_struct_vector ? _fbb.CreateVectorOfStructs64<::flatbuffers::Vector>(*far_struct_vector) : 0; + auto far_struct_vector__ = far_struct_vector ? _fbb.CreateVectorOfStructs64<::flatbuffers::Vector, ::flatbuffers::uoffset_t>(*far_struct_vector) : 0; auto big_struct_vector__ = big_struct_vector ? _fbb.CreateVectorOfStructs64(*big_struct_vector) : 0; if (forced_aligned_vector) { _fbb.ForceVectorAlignment64(forced_aligned_vector->size(), sizeof(uint8_t), 32); } auto forced_aligned_vector__ = forced_aligned_vector ? _fbb.CreateVector64(*forced_aligned_vector) : 0; @@ -430,7 +430,7 @@ inline ::flatbuffers::Offset CreateWrapperTable(::flatbuffers::Fla (void)_rehasher; (void)_o; struct _VectorArgs { ::flatbuffers::FlatBufferBuilder64 *__fbb; const WrapperTableT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; - auto _vector = _o->vector.size() ? _fbb.CreateVector64<::flatbuffers::Vector>(_o->vector) : 0; + auto _vector = _o->vector.size() ? _fbb.CreateVector64<::flatbuffers::Vector, ::flatbuffers::uoffset_t>(_o->vector) : 0; return CreateWrapperTable( _fbb, _vector); @@ -513,13 +513,13 @@ inline ::flatbuffers::Offset CreateRootTable(::flatbuffers::FlatBuffe (void)_rehasher; (void)_o; struct _VectorArgs { ::flatbuffers::FlatBufferBuilder64 *__fbb; const RootTableT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; - auto _far_vector = _o->far_vector.size() ? _fbb.CreateVector64<::flatbuffers::Vector>(_o->far_vector) : 0; + auto _far_vector = _o->far_vector.size() ? _fbb.CreateVector64<::flatbuffers::Vector, ::flatbuffers::uoffset_t>(_o->far_vector) : 0; auto _a = _o->a; auto _far_string = _o->far_string.empty() ? 0 : _fbb.CreateString<::flatbuffers::Offset64>(_o->far_string); auto _big_vector = _o->big_vector.size() ? _fbb.CreateVector64(_o->big_vector) : 0; auto _near_string = _o->near_string.empty() ? 0 : _fbb.CreateString(_o->near_string); auto _nested_root = _o->nested_root.size() ? _fbb.CreateVector64(_o->nested_root) : 0; - auto _far_struct_vector = _o->far_struct_vector.size() ? _fbb.CreateVectorOfStructs64<::flatbuffers::Vector>(_o->far_struct_vector) : 0; + auto _far_struct_vector = _o->far_struct_vector.size() ? _fbb.CreateVectorOfStructs64<::flatbuffers::Vector, ::flatbuffers::uoffset_t>(_o->far_struct_vector) : 0; auto _big_struct_vector = _o->big_struct_vector.size() ? _fbb.CreateVectorOfStructs64(_o->big_struct_vector) : 0; auto _many_vectors = _o->many_vectors.size() ? _fbb.CreateVector<::flatbuffers::Offset> (_o->many_vectors.size(), [](size_t i, _VectorArgs *__va) { return CreateWrapperTable(*__va->__fbb, __va->__o->many_vectors[i].get(), __va->__rehasher); }, &_va ) : 0; _fbb.ForceVectorAlignment64(_o->forced_aligned_vector.size(), sizeof(uint8_t), 32);