Document requirement for custom string types to implement empty() and be constructible from std::string.

Add new option --cpp-str-flex-ctor to construct custom string types not via std::string, but (char * + length).
This commit is contained in:
Luca Longinotti
2019-03-01 16:15:36 +01:00
parent 28cb2e92d5
commit 92b90d7f0f
5 changed files with 44 additions and 9 deletions

View File

@@ -120,7 +120,13 @@ Additional options:
- `--cpp-ptr-type T` : Set object API pointer type (default std::unique_ptr) - `--cpp-ptr-type T` : Set object API pointer type (default std::unique_ptr)
- `--cpp-str-type T` : Set object API string type (default std::string) - `--cpp-str-type T` : Set object API string type (default std::string)
- T::c_str() and T::length() must be supported. T::c_str(), T::length() and T::empty() must be supported.
The custom type also needs to be constructible from std::string (see the
--cpp-str-flex-ctor option to change this behavior).
- `--cpp-str-flex-ctor` : Don't construct custom string types by passing
std::string from Flatbuffers, but (char* + length). This allows efficient
construction of custom string types, including zero-copy construction.
- `--object-prefix` : Customise class prefix for C++ object-based API. - `--object-prefix` : Customise class prefix for C++ object-based API.

View File

@@ -255,14 +255,24 @@ you, so you'll have to manage their lifecycles manually. To reference the
pointer type specified by the `--cpp-ptr-type` argument to `flatc` from a pointer type specified by the `--cpp-ptr-type` argument to `flatc` from a
flatbuffer field set the `cpp_ptr_type` attribute to `default_ptr_type`. flatbuffer field set the `cpp_ptr_type` attribute to `default_ptr_type`.
# Using different string type. # Using different string type.
By default the object tree is built out of `std::string`, but you can 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 influence this either globally (using the `--cpp-str-type` argument to
`flatc`) or per field using the `cpp_str_type` attribute. `flatc`) or per field using the `cpp_str_type` attribute.
The type must support T::c_str() and T::length() as member functions. The type must support T::c_str(), T::length() and T::empty() as member functions.
Further, the type must be constructible from std::string, as by default a
std::string instance is constructed and then used to initialize the custom
string type. This behavior impedes efficient and zero-copy construction of
custom string types; the `--cpp-str-flex-ctor` argument to `flatc` or the
per field attribute `cpp_str_flex_ctor` can be used to change this behavior,
so that the custom string type is constructed by passing the pointer and
length of the FlatBuffers String. The custom string class will require a
constructor in the following format: custom_str_class(const char *, uint32_t).
Please note that the character array is not guaranteed to be NUL terminated,
you should always use the provided size to determine end of string.
## Reflection (& Resizing) ## Reflection (& Resizing)

View File

@@ -410,6 +410,7 @@ struct IDLOptions {
bool gen_compare; bool gen_compare;
std::string cpp_object_api_pointer_type; std::string cpp_object_api_pointer_type;
std::string cpp_object_api_string_type; std::string cpp_object_api_string_type;
bool cpp_object_api_string_flexible_constructor;
bool gen_nullable; bool gen_nullable;
bool gen_generated; bool gen_generated;
std::string object_prefix; std::string object_prefix;
@@ -486,6 +487,7 @@ struct IDLOptions {
generate_object_based_api(false), generate_object_based_api(false),
gen_compare(false), gen_compare(false),
cpp_object_api_pointer_type("std::unique_ptr"), cpp_object_api_pointer_type("std::unique_ptr"),
cpp_object_api_string_flexible_constructor(false),
gen_nullable(false), gen_nullable(false),
gen_generated(false), gen_generated(false),
object_suffix("T"), object_suffix("T"),
@@ -627,6 +629,7 @@ class Parser : public ParserState {
known_attributes_["cpp_ptr_type"] = true; known_attributes_["cpp_ptr_type"] = true;
known_attributes_["cpp_ptr_type_get"] = true; known_attributes_["cpp_ptr_type_get"] = true;
known_attributes_["cpp_str_type"] = true; known_attributes_["cpp_str_type"] = true;
known_attributes_["cpp_str_flex_ctor"] = true;
known_attributes_["native_inline"] = true; known_attributes_["native_inline"] = true;
known_attributes_["native_custom_alloc"] = true; known_attributes_["native_custom_alloc"] = true;
known_attributes_["native_type"] = true; known_attributes_["native_type"] = true;

View File

@@ -107,7 +107,11 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const {
" file.\n" " file.\n"
" --cpp-ptr-type T Set object API pointer type (default std::unique_ptr).\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" " --cpp-str-type T Set object API string type (default std::string).\n"
" T::c_str() and T::length() must be supported.\n" " T::c_str(), T::length() and T::empty() must be supported.\n"
" The custom type also needs to be constructible from std::string\n"
" (see the --cpp-str-flex-ctor option to change this behavior).\n"
" --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n"
" from Flatbuffers, but (char* + length).\n"
" --object-prefix Customise class prefix for C++ object-based API.\n" " --object-prefix Customise class prefix for C++ object-based API.\n"
" --object-suffix Customise class suffix for C++ object-based API.\n" " --object-suffix Customise class suffix for C++ object-based API.\n"
" Default value is \"T\".\n" " Default value is \"T\".\n"
@@ -247,6 +251,8 @@ int FlatCompiler::Compile(int argc, const char **argv) {
} else if (arg == "--cpp-str-type") { } else if (arg == "--cpp-str-type") {
if (++argi >= argc) Error("missing type following" + arg, true); if (++argi >= argc) Error("missing type following" + arg, true);
opts.cpp_object_api_string_type = argv[argi]; opts.cpp_object_api_string_type = argv[argi];
} else if (arg == "--cpp-str-flex-ctor") {
opts.cpp_object_api_string_flexible_constructor = true;
} else if (arg == "--gen-nullable") { } else if (arg == "--gen-nullable") {
opts.gen_nullable = true; opts.gen_nullable = true;
} else if (arg == "--gen-generated") { } else if (arg == "--gen-generated") {

View File

@@ -578,6 +578,12 @@ class CppGenerator : public BaseGenerator {
return ret; return ret;
} }
bool FlexibleStringConstructor(const FieldDef *field) {
auto attr = field ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr) : false;
auto ret = attr ? attr : parser_.opts.cpp_object_api_string_flexible_constructor;
return (ret && NativeString(field) != "std::string"); // Only for custom string types.
}
std::string GenTypeNativePtr(const std::string &type, const FieldDef *field, std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
bool is_constructor) { bool is_constructor) {
auto &ptr_type = PtrType(field); auto &ptr_type = PtrType(field);
@@ -2138,7 +2144,11 @@ class CppGenerator : public BaseGenerator {
bool invector, const FieldDef &afield) { bool invector, const FieldDef &afield) {
switch (type.base_type) { switch (type.base_type) {
case BASE_TYPE_STRING: { case BASE_TYPE_STRING: {
return val + "->str()"; if (FlexibleStringConstructor(&afield)) {
return NativeString(&afield) + "(" + val + "->c_str(), " + val + "->size())";
} else {
return val + "->str()";
}
} }
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
const auto name = WrapInNameSpace(*type.struct_def); const auto name = WrapInNameSpace(*type.struct_def);
@@ -2169,7 +2179,7 @@ class CppGenerator : public BaseGenerator {
break; break;
} }
} }
}; }
std::string GenUnpackFieldStatement(const FieldDef &field, std::string GenUnpackFieldStatement(const FieldDef &field,
const FieldDef *union_field) { const FieldDef *union_field) {