diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index b6b669c26c2..4b6da2ba4ba 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -226,9 +226,12 @@ struct Type { struct Value { Value() : constant("0"), + has_non_scalar_constant(false), offset(static_cast(~(static_cast(0U)))) {} Type type; std::string constant; + // not the most elegant solution, but much better than a full refactor. + bool has_non_scalar_constant; voffset_t offset; }; @@ -347,7 +350,7 @@ struct FieldDef : public Definition { return IsScalar() && IsOptional(); } bool IsScalar() const { - return ::flatbuffers::IsScalar(value.type.base_type); + return ::flatbuffers::IsScalar(value.type.base_type); } bool IsOptional() const { return presence == kOptional; } bool IsRequired() const { return presence == kRequired; } @@ -1262,8 +1265,8 @@ class Parser : public ParserState { // it contains non-UTF-8 byte arrays in String values). extern bool GenerateTextFromTable(const Parser &parser, const void *table, - const std::string &tablename, - std::string *text); + const std::string &tablename, + std::string *text); extern const char *GenerateText(const Parser &parser, const void *flatbuffer, std::string *text); extern const char *GenerateTextFile(const Parser &parser, diff --git a/include/flatbuffers/reflection_generated.h b/include/flatbuffers/reflection_generated.h index ca673b1b6b6..7410b44a2d3 100644 --- a/include/flatbuffers/reflection_generated.h +++ b/include/flatbuffers/reflection_generated.h @@ -617,7 +617,8 @@ struct Field FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { VT_DOCUMENTATION = 24, VT_OPTIONAL = 26, VT_PADDING = 28, - VT_OFFSET64 = 30 + VT_OFFSET64 = 30, + VT_DEFAULT_NON_SCALAR = 32 }; const ::flatbuffers::String *name() const { return GetPointer(VT_NAME); @@ -675,6 +676,9 @@ struct Field FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { bool offset64() const { return GetField(VT_OFFSET64, 0) != 0; } + const ::flatbuffers::String *default_non_scalar() const { + return GetPointer(VT_DEFAULT_NON_SCALAR); + } bool Verify(::flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyOffsetRequired(verifier, VT_NAME) && @@ -697,6 +701,8 @@ struct Field FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { VerifyField(verifier, VT_OPTIONAL, 1) && VerifyField(verifier, VT_PADDING, 2) && VerifyField(verifier, VT_OFFSET64, 1) && + VerifyOffset(verifier, VT_DEFAULT_NON_SCALAR) && + verifier.VerifyString(default_non_scalar()) && verifier.EndTable(); } }; @@ -747,6 +753,9 @@ struct FieldBuilder { void add_offset64(bool offset64) { fbb_.AddElement(Field::VT_OFFSET64, static_cast(offset64), 0); } + void add_default_non_scalar(::flatbuffers::Offset<::flatbuffers::String> default_non_scalar) { + fbb_.AddOffset(Field::VT_DEFAULT_NON_SCALAR, default_non_scalar); + } explicit FieldBuilder(::flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -775,10 +784,12 @@ inline ::flatbuffers::Offset CreateField( ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<::flatbuffers::String>>> documentation = 0, bool optional = false, uint16_t padding = 0, - bool offset64 = false) { + bool offset64 = false, + ::flatbuffers::Offset<::flatbuffers::String> default_non_scalar = 0) { FieldBuilder builder_(_fbb); builder_.add_default_real(default_real); builder_.add_default_integer(default_integer); + builder_.add_default_non_scalar(default_non_scalar); builder_.add_documentation(documentation); builder_.add_attributes(attributes); builder_.add_type(type); @@ -809,10 +820,12 @@ inline ::flatbuffers::Offset CreateFieldDirect( const std::vector<::flatbuffers::Offset<::flatbuffers::String>> *documentation = nullptr, bool optional = false, uint16_t padding = 0, - bool offset64 = false) { + bool offset64 = false, + const char *default_non_scalar = nullptr) { auto name__ = name ? _fbb.CreateString(name) : 0; auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables(attributes) : 0; auto documentation__ = documentation ? _fbb.CreateVector<::flatbuffers::Offset<::flatbuffers::String>>(*documentation) : 0; + auto default_non_scalar__ = default_non_scalar ? _fbb.CreateString(default_non_scalar) : 0; return reflection::CreateField( _fbb, name__, @@ -828,7 +841,8 @@ inline ::flatbuffers::Offset CreateFieldDirect( documentation__, optional, padding, - offset64); + offset64, + default_non_scalar__); } struct Object FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { diff --git a/java/src/main/java/com/google/flatbuffers/reflection/Field.java b/java/src/main/java/com/google/flatbuffers/reflection/Field.java index 8cd742e01fc..9270933f02f 100644 --- a/java/src/main/java/com/google/flatbuffers/reflection/Field.java +++ b/java/src/main/java/com/google/flatbuffers/reflection/Field.java @@ -59,6 +59,9 @@ public final class Field extends Table { * If the field uses 64-bit offsets. */ public boolean offset64() { int o = __offset(30); return o != 0 ? 0!=bb.get(o + bb_pos) : false; } + public String defaultNonScalar() { int o = __offset(32); return o != 0 ? __string(o + bb_pos) : null; } + public ByteBuffer defaultNonScalarAsByteBuffer() { return __vector_as_bytebuffer(32, 1); } + public ByteBuffer defaultNonScalarInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 32, 1); } public static int createField(FlatBufferBuilder builder, int nameOffset, @@ -74,10 +77,12 @@ public static int createField(FlatBufferBuilder builder, int documentationOffset, boolean optional, int padding, - boolean offset64) { - builder.startTable(14); + boolean offset64, + int defaultNonScalarOffset) { + builder.startTable(15); Field.addDefaultReal(builder, defaultReal); Field.addDefaultInteger(builder, defaultInteger); + Field.addDefaultNonScalar(builder, defaultNonScalarOffset); Field.addDocumentation(builder, documentationOffset); Field.addAttributes(builder, attributesOffset); Field.addType(builder, typeOffset); @@ -93,7 +98,7 @@ public static int createField(FlatBufferBuilder builder, return Field.endField(builder); } - public static void startField(FlatBufferBuilder builder) { builder.startTable(14); } + public static void startField(FlatBufferBuilder builder) { builder.startTable(15); } public static void addName(FlatBufferBuilder builder, int nameOffset) { builder.addOffset(nameOffset); builder.slot(0); } public static void addType(FlatBufferBuilder builder, int typeOffset) { builder.addOffset(1, typeOffset, 0); } public static void addId(FlatBufferBuilder builder, int id) { builder.addShort(2, (short) id, (short) 0); } @@ -112,6 +117,7 @@ public static int createField(FlatBufferBuilder builder, public static void addOptional(FlatBufferBuilder builder, boolean optional) { builder.addBoolean(11, optional, false); } public static void addPadding(FlatBufferBuilder builder, int padding) { builder.addShort(12, (short) padding, (short) 0); } public static void addOffset64(FlatBufferBuilder builder, boolean offset64) { builder.addBoolean(13, offset64, false); } + public static void addDefaultNonScalar(FlatBufferBuilder builder, int defaultNonScalarOffset) { builder.addOffset(14, defaultNonScalarOffset, 0); } public static int endField(FlatBufferBuilder builder) { int o = builder.endTable(); builder.required(o, 4); // name diff --git a/python/flatbuffers/reflection/Field.py b/python/flatbuffers/reflection/Field.py index 2cce39203bc..557bcc10525 100644 --- a/python/flatbuffers/reflection/Field.py +++ b/python/flatbuffers/reflection/Field.py @@ -163,8 +163,15 @@ def Offset64(self): return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos)) return False + # Field + def DefaultNonScalar(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(32)) + if o != 0: + return self._tab.String(o + self._tab.Pos) + return None + def FieldStart(builder): - builder.StartObject(14) + builder.StartObject(15) def Start(builder): FieldStart(builder) @@ -265,6 +272,12 @@ def FieldAddOffset64(builder, offset64): def AddOffset64(builder, offset64): FieldAddOffset64(builder, offset64) +def FieldAddDefaultNonScalar(builder, defaultNonScalar): + builder.PrependUOffsetTRelativeSlot(14, flatbuffers.number_types.UOffsetTFlags.py_type(defaultNonScalar), 0) + +def AddDefaultNonScalar(builder, defaultNonScalar): + FieldAddDefaultNonScalar(builder, defaultNonScalar) + def FieldEnd(builder): return builder.EndObject() diff --git a/reflection/reflection.fbs b/reflection/reflection.fbs index 985b45160d4..53ebf006ad3 100644 --- a/reflection/reflection.fbs +++ b/reflection/reflection.fbs @@ -88,6 +88,7 @@ table Field { padding:uint16 = 0; /// If the field uses 64-bit offsets. offset64:bool = false; + default_non_scalar:string; } table Object { // Used for both tables and structs. diff --git a/src/binary_annotator.cpp b/src/binary_annotator.cpp index 6612b107303..9c1f6010010 100644 --- a/src/binary_annotator.cpp +++ b/src/binary_annotator.cpp @@ -418,6 +418,12 @@ BinaryAnnotator::VTable *BinaryAnnotator::GetOrBuildVTable( ? std::to_string(field->default_real()) : std::to_string(field->default_integer()); default_label += "> ("; + } else if ((field->type()->base_type() == reflection::String || + field->type()->base_type() == reflection::Vector) && + field->default_non_scalar() != nullptr) { + default_label += "default_non_scalar()->str(); + default_label += "\"> ("; } else { default_label += " ("; } diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index d01e18ef761..ab9f34713d9 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -994,6 +994,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) { "Default values for strings and vectors are not supported in one " "of the specified programming languages"); } + field->value.has_non_scalar_constant = true; } if (IsVector(type) && field->value.constant != "0" && @@ -4042,6 +4043,8 @@ Offset FieldDef::Serialize(FlatBufferBuilder *builder, auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty() ? builder->CreateVectorOfStrings(doc_comment) : 0; + auto default_non_scalar__ = + value.has_non_scalar_constant ? builder->CreateString(value.constant) : 0; double d; StringToNumber(value.constant.c_str(), &d); return reflection::CreateField( @@ -4050,7 +4053,8 @@ Offset FieldDef::Serialize(FlatBufferBuilder *builder, IsInteger(value.type.base_type) ? StringToInt(value.constant.c_str()) : 0, // result may be platform-dependent if underlying is float (not double) IsFloat(value.type.base_type) ? d : 0.0, deprecated, IsRequired(), key, - attr__, docs__, IsOptional(), static_cast(padding), offset64); + attr__, docs__, IsOptional(), static_cast(padding), offset64, + default_non_scalar__); // TODO: value.constant is almost always "0", we could save quite a bit of // space by sharing it. Same for common values of value.type. } @@ -4064,6 +4068,10 @@ bool FieldDef::Deserialize(Parser &parser, const reflection::Field *field) { value.constant = NumToString(field->default_integer()); } else if (IsFloat(value.type.base_type)) { value.constant = FloatToString(field->default_real(), 17); + } else if (IsString(value.type) || IsVector(value.type)) { + value.has_non_scalar_constant = field->default_non_scalar(); + value.constant = + value.has_non_scalar_constant ? field->default_non_scalar()->str() : ""; } presence = FieldDef::MakeFieldPresence(field->optional(), field->required()); padding = field->padding();