diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md index 74045129e..2808c49c6 100644 --- a/docs/source/CppUsage.md +++ b/docs/source/CppUsage.md @@ -88,6 +88,14 @@ convenient accessors for all fields, e.g. `hp()`, `mana()`, etc: *Note: That we never stored a `mana` value, so it will return the default.* +The following attributes are supported: + +- `shared` (on a field): For string fields, this enables the usage of string + pooling (i.e. `CreateSharedString`) as default serialization behavior. + + Specifically, `CreateXxxDirect` functions and `Pack` functions for object + based API (see below) will use `CreateSharedString` to create strings. + ## Object based API. {#flatbuffers_cpp_object_based_api} FlatBuffers is all about memory efficiency, which is why its base API is written diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index e48edb01e..3c318817f 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -258,6 +258,7 @@ struct FieldDef : public Definition { : deprecated(false), required(false), key(false), + shared(false), native_inline(false), flexbuffer(false), nested_flatbuffer(NULL), @@ -273,6 +274,8 @@ struct FieldDef : public Definition { // written in new data nor accessed in new code. bool required; // Field must always be present. bool key; // Field functions as a key for creating sorted vectors. + bool shared; // Field will be using string pooling (i.e. CreateSharedString) + // as default serialization behavior if field is a string. bool native_inline; // Field will be defined inline (instead of as a pointer) // for native tables if field is a struct. bool flexbuffer; // This field contains FlexBuffer data. @@ -608,6 +611,7 @@ class Parser : public ParserState { known_attributes_["deprecated"] = true; known_attributes_["required"] = true; known_attributes_["key"] = true; + known_attributes_["shared"] = true; known_attributes_["hash"] = true; known_attributes_["id"] = true; known_attributes_["force_align"] = true; diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 9884081ad..9294953ee 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -2083,9 +2083,14 @@ class CppGenerator : public BaseGenerator { if (!field.deprecated) { code_.SetValue("FIELD_NAME", Name(field)); if (field.value.type.base_type == BASE_TYPE_STRING) { + if (!field.shared) { + code_.SetValue("CREATE_STRING", "CreateString"); + } else { + code_.SetValue("CREATE_STRING", "CreateSharedString"); + } code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? " - "_fbb.CreateString({{FIELD_NAME}}) : 0;"; + "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;"; } else if (field.value.type.base_type == BASE_TYPE_VECTOR) { code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\"; const auto vtype = field.value.type.VectorType(); @@ -2294,8 +2299,16 @@ class CppGenerator : public BaseGenerator { switch (field.value.type.base_type) { // String fields are of the form: // _fbb.CreateString(_o->field) + // or + // _fbb.CreateSharedString(_o->field) case BASE_TYPE_STRING: { - code += "_fbb.CreateString(" + value + ")"; + if (!field.shared) { + code += "_fbb.CreateString("; + } else { + code += "_fbb.CreateSharedString("; + } + code += value; + code.push_back(')'); // For optional fields, check to see if there actually is any data // in _o->field before attempting to access it. If there isn't, diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index a1d6cb060..32a9a7209 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -767,6 +767,9 @@ CheckedError Parser::ParseField(StructDef &struct_def) { return Error("'key' field must be string or scalar type"); } } + field->shared = field->attributes.Lookup("shared") != nullptr; + if (field->shared && field->value.type.base_type != BASE_TYPE_STRING) + return Error("shared can only be defined on strings"); auto field_native_custom_alloc = field->attributes.Lookup("native_custom_alloc"); @@ -777,7 +780,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) { field->native_inline = field->attributes.Lookup("native_inline") != nullptr; if (field->native_inline && !IsStruct(field->value.type)) - return Error("native_inline can only be defined on structs'"); + return Error("native_inline can only be defined on structs"); auto nested = field->attributes.Lookup("nested_flatbuffer"); if (nested) {