From f2071e4f80bf7ccd924337c7bf1bf33c79e3fc3e Mon Sep 17 00:00:00 2001 From: Alexander Gallego Date: Mon, 20 Mar 2017 19:02:04 -0400 Subject: [PATCH] Add arbitrary string type to the native object API (#4218) * Custom strings are very common for optimizations around small objects or growth style optimizations, i.e.: grow at 1.57 times vs doubling vs.. A second common strategy is to cooperate w/ the memory allocator see FBString[1] and seastar[2] string for examples. [1] fbstring: https://github.com/facebook/folly/blob/master/folly/docs/FBString.md [2] sstring: https://github.com/scylladb/seastar/blob/master/core/sstring.hh --- docs/source/CppUsage.md | 9 +++++++++ include/flatbuffers/flatbuffers.h | 9 +++++++++ include/flatbuffers/idl.h | 3 ++- src/flatc.cpp | 5 +++++ src/idl_gen_cpp.cpp | 11 ++++++++++- 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md index 8b82338f8..0e226fc75 100755 --- a/docs/source/CppUsage.md +++ b/docs/source/CppUsage.md @@ -200,6 +200,15 @@ pointer type (`my_ptr`), or by specifying `naked` as the type to get `T *` pointers. Unlike the smart pointers, naked pointers do not manage memory for you, so you'll have to manage their lifecycles manually. + +# Using different string type. + +By default the object tree is built out of `std::string`, but you can +influence this either globally (using the `--cpp-str-type` argument to +`flatc`) or per field using the `cpp_str_type` attribute. + +The type must support T::c_str() and T::length() as member functions. + ## Reflection (& Resizing) There is experimental support for reflection in FlatBuffers, allowing you to diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index ce657c04e..ea78aeeea 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -980,6 +980,15 @@ FLATBUFFERS_FINAL_CLASS return str ? CreateString(str->c_str(), str->Length()) : 0; } + /// @brief Store a string in the buffer, which can contain any binary data. + /// @param[in] str A const reference to a std::string like type with support + /// of T::c_str() and T::length() to store in the buffer. + /// @return Returns the offset in the buffer where the string starts. + template + Offset CreateString(const T &str) { + return CreateString(str.c_str(), str.length()); + } + /// @brief Store a string in the buffer, which can contain any binary data. /// If a string with this exact contents has already been serialized before, /// instead simply returns the offset of the existing string. diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 5b7a72a3c..d4d737d30 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -353,6 +353,7 @@ struct IDLOptions { bool escape_proto_identifiers; bool generate_object_based_api; std::string cpp_object_api_pointer_type; + std::string cpp_object_api_string_type; bool union_value_namespacing; bool allow_non_utf8; std::string include_prefix; @@ -479,6 +480,7 @@ class Parser : public ParserState { known_attributes_["idempotent"] = true; known_attributes_["cpp_type"] = true; known_attributes_["cpp_ptr_type"] = true; + known_attributes_["cpp_str_type"] = true; known_attributes_["native_inline"] = true; known_attributes_["native_type"] = true; known_attributes_["native_default"] = true; @@ -743,4 +745,3 @@ bool GenerateGoGRPC(const Parser &parser, } // namespace flatbuffers #endif // FLATBUFFERS_IDL_H_ - diff --git a/src/flatc.cpp b/src/flatc.cpp index 20207de13..8eef56170 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -86,6 +86,8 @@ std::string FlatCompiler::GetUsageString(const char* program_name) const { " --escape-proto-ids Disable appending '_' in namespaces names.\n" " --gen-object-api Generate an additional object-based API.\n" " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr)\n" + " --cpp-str-type T Set object API string type (default std::string)\n" + " T::c_str() and T::length() must be supported\n" " --no-js-exports Removes Node.js style export lines in JS.\n" " --goog-js-export Uses goog.exports* for closure compiler exporting in JS.\n" " --raw-binary Allow binaries without file_indentifier to be read.\n" @@ -178,6 +180,9 @@ int FlatCompiler::Compile(int argc, const char** argv) { } else if (arg == "--cpp-ptr-type") { if (++argi >= argc) Error("missing type following" + arg, true); opts.cpp_object_api_pointer_type = argv[argi]; + } else if (arg == "--cpp-str-type") { + if (++argi >= argc) Error("missing type following" + arg, true); + opts.cpp_object_api_string_type = argv[argi]; } else if(arg == "--gen-all") { opts.generate_all = true; opts.include_dependence_headers = false; diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 958af8456..19172aa93 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -362,6 +362,15 @@ class CppGenerator : public BaseGenerator { return attr ? attr->constant : parser_.opts.cpp_object_api_pointer_type; } + const std::string NativeString(const FieldDef *field) { + auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr; + auto &ret = attr ? attr->constant : parser_.opts.cpp_object_api_string_type; + if (ret.empty()) { + return "std::string"; + } + return ret; + } + std::string GenTypeNativePtr(const std::string &type, const FieldDef *field, bool is_constructor) { auto &ptr_type = PtrType(field); @@ -383,7 +392,7 @@ class CppGenerator : public BaseGenerator { const FieldDef &field) { switch (type.base_type) { case BASE_TYPE_STRING: { - return "std::string"; + return NativeString(&field); } case BASE_TYPE_VECTOR: { const auto type_name = GenTypeNative(type.VectorType(), true, field);