| Index: third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_message.cc
|
| diff --git a/third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_message.cc
|
| index 32671d42013dffc73eae1df58ba80551668e3ba2..bf272596cb2409e824530e2c6c13dba5af82dbe8 100644
|
| --- a/third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_message.cc
|
| +++ b/third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_message.cc
|
| @@ -66,11 +66,12 @@ int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) {
|
| // The first item in the object structure is our uint32[] for has bits.
|
| // We then want to order things to make the instances as small as
|
| // possible. So we follow the has bits with:
|
| - // 1. Bools (1 byte)
|
| - // 2. Anything always 4 bytes - float, *32, enums
|
| - // 3. Anything that is always a pointer (they will be 8 bytes on 64 bit
|
| + // 1. Anything always 4 bytes - float, *32, enums
|
| + // 2. Anything that is always a pointer (they will be 8 bytes on 64 bit
|
| // builds and 4 bytes on 32bit builds.
|
| - // 4. Anything always 8 bytes - double, *64
|
| + // 3. Anything always 8 bytes - double, *64
|
| + //
|
| + // NOTE: Bools aren't listed, they were stored in the has bits.
|
| //
|
| // Why? Using 64bit builds as an example, this means worse case, we have
|
| // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes
|
| @@ -115,9 +116,9 @@ int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) {
|
| case FieldDescriptor::TYPE_ENUM:
|
| return 2;
|
|
|
| - // 1 byte.
|
| + // 0 bytes. Stored in the has bits.
|
| case FieldDescriptor::TYPE_BOOL:
|
| - return 1;
|
| + return 99; // End of the list (doesn't really matter).
|
| }
|
|
|
| // Some compilers report reaching end of function even though all cases of
|
| @@ -174,10 +175,11 @@ const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) {
|
| } // namespace
|
|
|
| MessageGenerator::MessageGenerator(const string& root_classname,
|
| - const Descriptor* descriptor)
|
| + const Descriptor* descriptor,
|
| + const Options& options)
|
| : root_classname_(root_classname),
|
| descriptor_(descriptor),
|
| - field_generators_(descriptor),
|
| + field_generators_(descriptor, options),
|
| class_name_(ClassName(descriptor_)) {
|
| for (int i = 0; i < descriptor_->extension_count(); i++) {
|
| extension_generators_.push_back(
|
| @@ -196,7 +198,9 @@ MessageGenerator::MessageGenerator(const string& root_classname,
|
|
|
| for (int i = 0; i < descriptor_->nested_type_count(); i++) {
|
| MessageGenerator* generator =
|
| - new MessageGenerator(root_classname_, descriptor_->nested_type(i));
|
| + new MessageGenerator(root_classname_,
|
| + descriptor_->nested_type(i),
|
| + options);
|
| nested_message_generators_.push_back(generator);
|
| }
|
| }
|
| @@ -230,11 +234,6 @@ void MessageGenerator::DetermineForwardDeclarations(set<string>* fwd_decls) {
|
| if (!IsMapEntryMessage(descriptor_)) {
|
| for (int i = 0; i < descriptor_->field_count(); i++) {
|
| const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
|
| - // If it is a the field is repeated, the type will be and *Array, and we
|
| - // don't need any forward decl.
|
| - if (fieldDescriptor->is_repeated()) {
|
| - continue;
|
| - }
|
| field_generators_.get(fieldDescriptor)
|
| .DetermineForwardDeclarations(fwd_decls);
|
| }
|
| @@ -322,8 +321,9 @@ void MessageGenerator::GenerateMessageHeader(io::Printer* printer) {
|
| }
|
|
|
| printer->Print(
|
| - "$comments$@interface $classname$ : GPBMessage\n\n",
|
| + "$comments$$deprecated_attribute$@interface $classname$ : GPBMessage\n\n",
|
| "classname", class_name_,
|
| + "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_, false, true),
|
| "comments", message_comments);
|
|
|
| vector<char> seen_oneofs(descriptor_->oneof_decl_count(), 0);
|
| @@ -406,32 +406,28 @@ void MessageGenerator::GenerateSource(io::Printer* printer) {
|
| sort(sorted_extensions.begin(), sorted_extensions.end(),
|
| ExtensionRangeOrdering());
|
|
|
| - // TODO(thomasvl): Finish optimizing has bit. The current behavior is as
|
| - // follows:
|
| - // 1. objectivec_field.cc's SetCommonFieldVariables() defaults the has_index
|
| - // to the field's index in the list of fields.
|
| - // 2. RepeatedFieldGenerator::RepeatedFieldGenerator() sets has_index to
|
| - // GPBNoHasBit because repeated fields & map<> fields don't use the has
|
| - // bit.
|
| - // 3. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative
|
| - // index that groups all the elements on of the oneof.
|
| - // So in has_storage, we need enough bits for the single fields that aren't
|
| - // in any oneof, and then one int32 for each oneof (to store the field
|
| - // number). So we could save a little space by not using the field's index
|
| - // and instead make a second pass only assigning indexes for the fields
|
| - // that would need it. The only savings would come when messages have over
|
| - // a multiple of 32 fields with some number being repeated or in oneofs to
|
| - // drop the count below that 32 multiple; so it hasn't seemed worth doing
|
| - // at the moment.
|
| - size_t num_has_bits = descriptor_->field_count();
|
| + // Assign has bits:
|
| + // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing
|
| + // who needs has bits and assigning them.
|
| + // 2. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative
|
| + // index that groups all the elements in the oneof.
|
| + size_t num_has_bits = field_generators_.CalculateHasBits();
|
| size_t sizeof_has_storage = (num_has_bits + 31) / 32;
|
| + if (sizeof_has_storage == 0) {
|
| + // In the case where no field needs has bits, don't let the _has_storage_
|
| + // end up as zero length (zero length arrays are sort of a grey area
|
| + // since it has to be at the start of the struct). This also ensures a
|
| + // field with only oneofs keeps the required negative indices they need.
|
| + sizeof_has_storage = 1;
|
| + }
|
| // Tell all the fields the oneof base.
|
| for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
|
| iter != oneof_generators_.end(); ++iter) {
|
| (*iter)->SetOneofIndexBase(sizeof_has_storage);
|
| }
|
| field_generators_.SetOneofIndexBase(sizeof_has_storage);
|
| - // Add an int32 for each oneof to store which is set.
|
| + // sizeof_has_storage needs enough bits for the single fields that aren't in
|
| + // any oneof, and then one int32 for each oneof (to store the field number).
|
| sizeof_has_storage += descriptor_->oneof_decl_count();
|
|
|
| printer->Print(
|
| @@ -458,47 +454,26 @@ void MessageGenerator::GenerateSource(io::Printer* printer) {
|
| " static GPBDescriptor *descriptor = nil;\n"
|
| " if (!descriptor) {\n");
|
|
|
| - bool has_oneofs = oneof_generators_.size();
|
| - if (has_oneofs) {
|
| - printer->Print(
|
| - " static GPBMessageOneofDescription oneofs[] = {\n");
|
| - printer->Indent();
|
| - printer->Indent();
|
| - printer->Indent();
|
| - for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
|
| - iter != oneof_generators_.end(); ++iter) {
|
| - (*iter)->GenerateDescription(printer);
|
| - }
|
| - printer->Outdent();
|
| - printer->Outdent();
|
| - printer->Outdent();
|
| - printer->Print(
|
| - " };\n");
|
| - }
|
| -
|
| TextFormatDecodeData text_format_decode_data;
|
| bool has_fields = descriptor_->field_count() > 0;
|
| + bool need_defaults = field_generators_.DoesAnyFieldHaveNonZeroDefault();
|
| + string field_description_type;
|
| + if (need_defaults) {
|
| + field_description_type = "GPBMessageFieldDescriptionWithDefault";
|
| + } else {
|
| + field_description_type = "GPBMessageFieldDescription";
|
| + }
|
| if (has_fields) {
|
| - // TODO(thomasvl): The plugin's FieldGenerator::GenerateFieldDescription()
|
| - // wraps the fieldOptions's value of this structure in an CPP gate so
|
| - // they can be compiled away; but that still results in a const char* in
|
| - // the structure for a NULL pointer for every message field. If the
|
| - // fieldOptions are moved to a separate payload like the TextFormat extra
|
| - // data is, then it would shrink that static data shrinking the binaries
|
| - // a little more.
|
| - // TODO(thomasvl): proto3 syntax doens't need a defaultValue in the
|
| - // structure because primitive types are always zero. If we add a second
|
| - // structure and a different initializer, we can avoid the wasted static
|
| - // storage for every field in a proto3 message.
|
| printer->Print(
|
| - " static GPBMessageFieldDescription fields[] = {\n");
|
| + " static $field_description_type$ fields[] = {\n",
|
| + "field_description_type", field_description_type);
|
| printer->Indent();
|
| printer->Indent();
|
| printer->Indent();
|
| for (int i = 0; i < descriptor_->field_count(); ++i) {
|
| const FieldGenerator& field_generator =
|
| field_generators_.get(sorted_fields[i]);
|
| - field_generator.GenerateFieldDescription(printer);
|
| + field_generator.GenerateFieldDescription(printer, need_defaults);
|
| if (field_generator.needs_textformat_name_support()) {
|
| text_format_decode_data.AddString(sorted_fields[i]->number(),
|
| field_generator.generated_objc_name(),
|
| @@ -512,111 +487,89 @@ void MessageGenerator::GenerateSource(io::Printer* printer) {
|
| " };\n");
|
| }
|
|
|
| - bool has_enums = enum_generators_.size();
|
| - if (has_enums) {
|
| + map<string, string> vars;
|
| + vars["classname"] = class_name_;
|
| + vars["rootclassname"] = root_classname_;
|
| + vars["fields"] = has_fields ? "fields" : "NULL";
|
| + if (has_fields) {
|
| + vars["fields_count"] =
|
| + "(uint32_t)(sizeof(fields) / sizeof(" + field_description_type + "))";
|
| + } else {
|
| + vars["fields_count"] = "0";
|
| + }
|
| +
|
| + std::vector<string> init_flags;
|
| + if (need_defaults) {
|
| + init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault");
|
| + }
|
| + if (descriptor_->options().message_set_wire_format()) {
|
| + init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat");
|
| + }
|
| + vars["init_flags"] = BuildFlagsString(init_flags);
|
| +
|
| + printer->Print(
|
| + vars,
|
| + " GPBDescriptor *localDescriptor =\n"
|
| + " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n"
|
| + " rootClass:[$rootclassname$ class]\n"
|
| + " file:$rootclassname$_FileDescriptor()\n"
|
| + " fields:$fields$\n"
|
| + " fieldCount:$fields_count$\n"
|
| + " storageSize:sizeof($classname$__storage_)\n"
|
| + " flags:$init_flags$];\n");
|
| + if (oneof_generators_.size() != 0) {
|
| printer->Print(
|
| - " static GPBMessageEnumDescription enums[] = {\n");
|
| - printer->Indent();
|
| - printer->Indent();
|
| - printer->Indent();
|
| - for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin();
|
| - iter != enum_generators_.end(); ++iter) {
|
| - printer->Print("{ .enumDescriptorFunc = $name$_EnumDescriptor },\n",
|
| - "name", (*iter)->name());
|
| + " static const char *oneofs[] = {\n");
|
| + for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
|
| + iter != oneof_generators_.end(); ++iter) {
|
| + printer->Print(
|
| + " \"$name$\",\n",
|
| + "name", (*iter)->DescriptorName());
|
| }
|
| - printer->Outdent();
|
| - printer->Outdent();
|
| - printer->Outdent();
|
| printer->Print(
|
| - " };\n");
|
| + " };\n"
|
| + " [localDescriptor setupOneofs:oneofs\n"
|
| + " count:(uint32_t)(sizeof(oneofs) / sizeof(char*))\n"
|
| + " firstHasIndex:$first_has_index$];\n",
|
| + "first_has_index", oneof_generators_[0]->HasIndexAsString());
|
| }
|
| -
|
| - bool has_extensions = sorted_extensions.size();
|
| - if (has_extensions) {
|
| + if (text_format_decode_data.num_entries() != 0) {
|
| + const string text_format_data_str(text_format_decode_data.Data());
|
| printer->Print(
|
| - " static GPBExtensionRange ranges[] = {\n");
|
| - printer->Indent();
|
| - printer->Indent();
|
| - printer->Indent();
|
| - for (int i = 0; i < sorted_extensions.size(); i++) {
|
| - printer->Print("{ .start = $start$, .end = $end$ },\n",
|
| - "start", SimpleItoa(sorted_extensions[i]->start),
|
| - "end", SimpleItoa(sorted_extensions[i]->end));
|
| + "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"
|
| + " static const char *extraTextFormatInfo =");
|
| + static const int kBytesPerLine = 40; // allow for escaping
|
| + for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) {
|
| + printer->Print(
|
| + "\n \"$data$\"",
|
| + "data", EscapeTrigraphs(
|
| + CEscape(text_format_data_str.substr(i, kBytesPerLine))));
|
| }
|
| - printer->Outdent();
|
| - printer->Outdent();
|
| - printer->Outdent();
|
| printer->Print(
|
| - " };\n");
|
| + ";\n"
|
| + " [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n"
|
| + "#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n");
|
| }
|
| -
|
| - map<string, string> vars;
|
| - vars["classname"] = class_name_;
|
| - vars["rootclassname"] = root_classname_;
|
| - vars["fields"] = has_fields ? "fields" : "NULL";
|
| - vars["fields_count"] =
|
| - has_fields ? "sizeof(fields) / sizeof(GPBMessageFieldDescription)" : "0";
|
| - vars["oneofs"] = has_oneofs ? "oneofs" : "NULL";
|
| - vars["oneof_count"] =
|
| - has_oneofs ? "sizeof(oneofs) / sizeof(GPBMessageOneofDescription)" : "0";
|
| - vars["enums"] = has_enums ? "enums" : "NULL";
|
| - vars["enum_count"] =
|
| - has_enums ? "sizeof(enums) / sizeof(GPBMessageEnumDescription)" : "0";
|
| - vars["ranges"] = has_extensions ? "ranges" : "NULL";
|
| - vars["range_count"] =
|
| - has_extensions ? "sizeof(ranges) / sizeof(GPBExtensionRange)" : "0";
|
| - vars["wireformat"] =
|
| - descriptor_->options().message_set_wire_format() ? "YES" : "NO";
|
| -
|
| - if (text_format_decode_data.num_entries() == 0) {
|
| + if (sorted_extensions.size() != 0) {
|
| printer->Print(
|
| - vars,
|
| - " GPBDescriptor *localDescriptor =\n"
|
| - " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n"
|
| - " rootClass:[$rootclassname$ class]\n"
|
| - " file:$rootclassname$_FileDescriptor()\n"
|
| - " fields:$fields$\n"
|
| - " fieldCount:$fields_count$\n"
|
| - " oneofs:$oneofs$\n"
|
| - " oneofCount:$oneof_count$\n"
|
| - " enums:$enums$\n"
|
| - " enumCount:$enum_count$\n"
|
| - " ranges:$ranges$\n"
|
| - " rangeCount:$range_count$\n"
|
| - " storageSize:sizeof($classname$__storage_)\n"
|
| - " wireFormat:$wireformat$];\n");
|
| - } else {
|
| - vars["extraTextFormatInfo"] = CEscape(text_format_decode_data.Data());
|
| - printer->Print(
|
| - vars,
|
| - "#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"
|
| - " const char *extraTextFormatInfo = NULL;\n"
|
| - "#else\n"
|
| - " static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n"
|
| - "#endif // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"
|
| - " GPBDescriptor *localDescriptor =\n"
|
| - " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n"
|
| - " rootClass:[$rootclassname$ class]\n"
|
| - " file:$rootclassname$_FileDescriptor()\n"
|
| - " fields:$fields$\n"
|
| - " fieldCount:$fields_count$\n"
|
| - " oneofs:$oneofs$\n"
|
| - " oneofCount:$oneof_count$\n"
|
| - " enums:$enums$\n"
|
| - " enumCount:$enum_count$\n"
|
| - " ranges:$ranges$\n"
|
| - " rangeCount:$range_count$\n"
|
| - " storageSize:sizeof($classname$__storage_)\n"
|
| - " wireFormat:$wireformat$\n"
|
| - " extraTextFormatInfo:extraTextFormatInfo];\n");
|
| + " static const GPBExtensionRange ranges[] = {\n");
|
| + for (int i = 0; i < sorted_extensions.size(); i++) {
|
| + printer->Print(" { .start = $start$, .end = $end$ },\n",
|
| + "start", SimpleItoa(sorted_extensions[i]->start),
|
| + "end", SimpleItoa(sorted_extensions[i]->end));
|
| }
|
| printer->Print(
|
| - " NSAssert(descriptor == nil, @\"Startup recursed!\");\n"
|
| - " descriptor = localDescriptor;\n"
|
| - " }\n"
|
| - " return descriptor;\n"
|
| - "}\n\n"
|
| - "@end\n\n");
|
| + " };\n"
|
| + " [localDescriptor setupExtensionRanges:ranges\n"
|
| + " count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n");
|
| + }
|
| + printer->Print(
|
| + " NSAssert(descriptor == nil, @\"Startup recursed!\");\n"
|
| + " descriptor = localDescriptor;\n"
|
| + " }\n"
|
| + " return descriptor;\n"
|
| + "}\n\n"
|
| + "@end\n\n");
|
|
|
| for (int i = 0; i < descriptor_->field_count(); i++) {
|
| field_generators_.get(descriptor_->field(i))
|
|
|