aboutsummaryrefslogtreecommitdiff
path: root/src/google/protobuf/compiler/cpp/cpp_message.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/compiler/cpp/cpp_message.cc')
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc3151
1 files changed, 1796 insertions, 1355 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 6274ba29..778fc406 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -32,25 +32,30 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <google/protobuf/compiler/cpp/cpp_message.h>
+
#include <algorithm>
#include <google/protobuf/stubs/hash.h>
#include <map>
#include <memory>
-#ifndef _SHARED_PTR_H
-#include <google/protobuf/stubs/shared_ptr.h>
-#endif
#include <utility>
#include <vector>
-#include <google/protobuf/compiler/cpp/cpp_message.h>
-#include <google/protobuf/compiler/cpp/cpp_field.h>
+
#include <google/protobuf/compiler/cpp/cpp_enum.h>
#include <google/protobuf/compiler/cpp/cpp_extension.h>
+#include <google/protobuf/compiler/cpp/cpp_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/io/printer.h>
+#include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h>
+#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/generated_message_table_driven.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map_entry_lite.h>
#include <google/protobuf/wire_format.h>
-#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
namespace google {
@@ -103,167 +108,19 @@ struct ExtensionRangeSorter {
}
};
-// Returns true if the "required" restriction check should be ignored for the
-// given field.
-inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field,
- const Options& options) {
- return false;
-}
-
-// Returns true if the message type has any required fields. If it doesn't,
-// we can optimize out calls to its IsInitialized() method.
-//
-// already_seen is used to avoid checking the same type multiple times
-// (and also to protect against recursion).
-static bool HasRequiredFields(const Descriptor* type, const Options& options,
- hash_set<const Descriptor*>* already_seen) {
- if (already_seen->count(type) > 0) {
- // Since the first occurrence of a required field causes the whole
- // function to return true, we can assume that if the type is already
- // in the cache it didn't have any required fields.
- return false;
- }
- already_seen->insert(type);
-
- // If the type has extensions, an extension with message type could contain
- // required fields, so we have to be conservative and assume such an
- // extension exists.
- if (type->extension_range_count() > 0) return true;
-
- for (int i = 0; i < type->field_count(); i++) {
- const FieldDescriptor* field = type->field(i);
- if (field->is_required()) {
- return true;
- }
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
- !ShouldIgnoreRequiredFieldCheck(field, options)) {
- if (HasRequiredFields(field->message_type(), options, already_seen)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static bool HasRequiredFields(const Descriptor* type, const Options& options) {
- hash_set<const Descriptor*> already_seen;
- return HasRequiredFields(type, options, &already_seen);
-}
-
-// This returns an estimate of the compiler's alignment for the field. This
-// can't guarantee to be correct because the generated code could be compiled on
-// different systems with different alignment rules. The estimates below assume
-// 64-bit pointers.
-int EstimateAlignmentSize(const FieldDescriptor* field) {
- if (field == NULL) return 0;
- if (field->is_repeated()) return 8;
+bool IsPOD(const FieldDescriptor* field) {
+ if (field->is_repeated() || field->is_extension()) return false;
switch (field->cpp_type()) {
- case FieldDescriptor::CPPTYPE_BOOL:
- return 1;
-
- case FieldDescriptor::CPPTYPE_INT32:
- case FieldDescriptor::CPPTYPE_UINT32:
case FieldDescriptor::CPPTYPE_ENUM:
- case FieldDescriptor::CPPTYPE_FLOAT:
- return 4;
-
+ case FieldDescriptor::CPPTYPE_INT32:
case FieldDescriptor::CPPTYPE_INT64:
+ case FieldDescriptor::CPPTYPE_UINT32:
case FieldDescriptor::CPPTYPE_UINT64:
+ case FieldDescriptor::CPPTYPE_FLOAT:
case FieldDescriptor::CPPTYPE_DOUBLE:
- case FieldDescriptor::CPPTYPE_STRING:
- case FieldDescriptor::CPPTYPE_MESSAGE:
- return 8;
- }
- GOOGLE_LOG(FATAL) << "Can't get here.";
- return -1; // Make compiler happy.
-}
-
-// FieldGroup is just a helper for OptimizePadding below. It holds a vector of
-// fields that are grouped together because they have compatible alignment, and
-// a preferred location in the final field ordering.
-class FieldGroup {
- public:
- FieldGroup()
- : preferred_location_(0) {}
-
- // A group with a single field.
- FieldGroup(float preferred_location, const FieldDescriptor* field)
- : preferred_location_(preferred_location),
- fields_(1, field) {}
-
- // Append the fields in 'other' to this group.
- void Append(const FieldGroup& other) {
- if (other.fields_.empty()) {
- return;
- }
- // Preferred location is the average among all the fields, so we weight by
- // the number of fields on each FieldGroup object.
- preferred_location_ =
- (preferred_location_ * fields_.size() +
- (other.preferred_location_ * other.fields_.size())) /
- (fields_.size() + other.fields_.size());
- fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end());
- }
-
- void SetPreferredLocation(float location) { preferred_location_ = location; }
- const std::vector<const FieldDescriptor*>& fields() const { return fields_; }
-
- // FieldGroup objects sort by their preferred location.
- bool operator<(const FieldGroup& other) const {
- return preferred_location_ < other.preferred_location_;
- }
-
- private:
- // "preferred_location_" is an estimate of where this group should go in the
- // final list of fields. We compute this by taking the average index of each
- // field in this group in the original ordering of fields. This is very
- // approximate, but should put this group close to where its member fields
- // originally went.
- float preferred_location_;
- std::vector<const FieldDescriptor*> fields_;
- // We rely on the default copy constructor and operator= so this type can be
- // used in a vector.
-};
-
-// Helper for the code that emits the Clear() method.
-bool CanInitializeByZeroing(const FieldDescriptor* field) {
- if (field->is_repeated() || field->is_extension()) return false;
- switch (field->cpp_type()) {
- case internal::WireFormatLite::CPPTYPE_ENUM:
- return field->default_value_enum()->number() == 0;
- case internal::WireFormatLite::CPPTYPE_INT32:
- return field->default_value_int32() == 0;
- case internal::WireFormatLite::CPPTYPE_INT64:
- return field->default_value_int64() == 0;
- case internal::WireFormatLite::CPPTYPE_UINT32:
- return field->default_value_uint32() == 0;
- case internal::WireFormatLite::CPPTYPE_UINT64:
- return field->default_value_uint64() == 0;
- case internal::WireFormatLite::CPPTYPE_FLOAT:
- return field->default_value_float() == 0;
- case internal::WireFormatLite::CPPTYPE_DOUBLE:
- return field->default_value_double() == 0;
- case internal::WireFormatLite::CPPTYPE_BOOL:
- return field->default_value_bool() == false;
- default:
- return false;
- }
-}
-
-bool IsPOD(const FieldDescriptor* field) {
- if (field->is_repeated() || field->is_extension()) return false;
- switch (field->cpp_type()) {
- case internal::WireFormatLite::CPPTYPE_ENUM:
- case internal::WireFormatLite::CPPTYPE_INT32:
- case internal::WireFormatLite::CPPTYPE_INT64:
- case internal::WireFormatLite::CPPTYPE_UINT32:
- case internal::WireFormatLite::CPPTYPE_UINT64:
- case internal::WireFormatLite::CPPTYPE_FLOAT:
- case internal::WireFormatLite::CPPTYPE_DOUBLE:
- case internal::WireFormatLite::CPPTYPE_BOOL:
+ case FieldDescriptor::CPPTYPE_BOOL:
return true;
- case internal::WireFormatLite::CPPTYPE_STRING:
+ case FieldDescriptor::CPPTYPE_STRING:
return false;
default:
return false;
@@ -284,132 +141,6 @@ bool CanConstructByZeroing(const FieldDescriptor* field,
return ret;
}
-// Reorder 'fields' so that if the fields are output into a c++ class in the new
-// order, fields of similiar family (see below) are together and within each
-// family, alignment padding is minimized.
-//
-// We try to do this while keeping each field as close as possible to its
-// declaration order (from the .proto file) so that we don't reduce cache
-// locality much for function that access each field in order. This is also the
-// only (weak) signal we have for author intent concerning field layout.
-//
-// TODO(ckennelly): If/when we have profiles available for the compiler, use
-// those rather than respect declaration order.
-//
-// We classify each field into a particular "family" of fields, that we perform
-// the same operation on in our generated functions.
-//
-// REPEATED is placed first, as the C++ compiler automatically initializes
-// these fields in layout order.
-//
-// STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and
-// calls ArenaStringPtr::Destroy on each.
-//
-//
-// MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls
-// delete on each. We initialize these fields with a NULL pointer (see
-// MessageFieldGenerator::GenerateConstructorCode), which allows them to be
-// memset.
-//
-// ZERO_INITIALIZABLE is memset in Clear/SharedCtor
-//
-// OTHER these fields are initialized one-by-one.
-void OptimizePadding(std::vector<const FieldDescriptor*>* fields,
- const Options& options) {
- // The sorted numeric order of Family determines the declaration order in the
- // memory layout.
- enum Family {
- REPEATED = 0,
- STRING = 1,
- MESSAGE = 2,
- ZERO_INITIALIZABLE = 4,
- OTHER = 5,
- kMaxFamily
- };
-
- // First divide fields into those that align to 1 byte, 4 bytes or 8 bytes.
- std::vector<FieldGroup> aligned_to_1[kMaxFamily];
- std::vector<FieldGroup> aligned_to_4[kMaxFamily];
- std::vector<FieldGroup> aligned_to_8[kMaxFamily];
- for (int i = 0; i < fields->size(); ++i) {
- const FieldDescriptor* field = (*fields)[i];
-
- Family f = OTHER;
- if (field->is_repeated()) {
- f = REPEATED;
- } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
- f = STRING;
- } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- f = MESSAGE;
-
- } else if (CanInitializeByZeroing(field)) {
- f = ZERO_INITIALIZABLE;
- }
-
- switch (EstimateAlignmentSize(field)) {
- case 1: aligned_to_1[f].push_back(FieldGroup(i, field)); break;
- case 4: aligned_to_4[f].push_back(FieldGroup(i, field)); break;
- case 8: aligned_to_8[f].push_back(FieldGroup(i, field)); break;
- default:
- GOOGLE_LOG(FATAL) << "Unknown alignment size.";
- }
- }
-
- // For each family, group fields to optimize padding.
- for (int f = 0; f < kMaxFamily; f++) {
- // Now group fields aligned to 1 byte into sets of 4, and treat those like a
- // single field aligned to 4 bytes.
- for (int i = 0; i < aligned_to_1[f].size(); i += 4) {
- FieldGroup field_group;
- for (int j = i; j < aligned_to_1[f].size() && j < i + 4; ++j) {
- field_group.Append(aligned_to_1[f][j]);
- }
- aligned_to_4[f].push_back(field_group);
- }
- // Sort by preferred location to keep fields as close to their declaration
- // order as possible. Using stable_sort ensures that the output is
- // consistent across runs.
- std::stable_sort(aligned_to_4[f].begin(), aligned_to_4[f].end());
-
- // Now group fields aligned to 4 bytes (or the 4-field groups created above)
- // into pairs, and treat those like a single field aligned to 8 bytes.
- for (int i = 0; i < aligned_to_4[f].size(); i += 2) {
- FieldGroup field_group;
- for (int j = i; j < aligned_to_4[f].size() && j < i + 2; ++j) {
- field_group.Append(aligned_to_4[f][j]);
- }
- if (i == aligned_to_4[f].size() - 1) {
- if (f == OTHER) {
- // Move incomplete 4-byte block to the beginning. This is done to
- // pair with the (possible) leftover blocks from the
- // ZERO_INITIALIZABLE family.
- field_group.SetPreferredLocation(-1);
- } else {
- // Move incomplete 4-byte block to the end.
- field_group.SetPreferredLocation(fields->size() + 1);
- }
- }
- aligned_to_8[f].push_back(field_group);
- }
- // Sort by preferred location.
- std::stable_sort(aligned_to_8[f].begin(), aligned_to_8[f].end());
- }
-
- // Now pull out all the FieldDescriptors in order.
- fields->clear();
- for (int f = 0; f < kMaxFamily; ++f) {
- for (int i = 0; i < aligned_to_8[f].size(); ++i) {
- fields->insert(fields->end(),
- aligned_to_8[f][i].fields().begin(),
- aligned_to_8[f][i].fields().end());
- }
- }
-}
-
-string MessageTypeProtoName(const FieldDescriptor* field) {
- return field->message_type()->full_name();
-}
-
// Emits an if-statement with a condition that evaluates to true if |field| is
// considered non-default (will be sent over the wire), for message types
// without true field presence. Should only be called if
@@ -464,25 +195,31 @@ bool HasHasMethod(const FieldDescriptor* field) {
void CollectMapInfo(const Descriptor* descriptor,
std::map<string, string>* variables) {
GOOGLE_CHECK(IsMapEntryMessage(descriptor));
+ std::map<string, string>& vars = *variables;
const FieldDescriptor* key = descriptor->FindFieldByName("key");
const FieldDescriptor* val = descriptor->FindFieldByName("value");
- (*variables)["key"] = PrimitiveTypeName(key->cpp_type());
+ vars["key_cpp"] = PrimitiveTypeName(key->cpp_type());
switch (val->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
- (*variables)["val"] = FieldMessageTypeName(val);
+ vars["val_cpp"] = FieldMessageTypeName(val);
break;
case FieldDescriptor::CPPTYPE_ENUM:
- (*variables)["val"] = ClassName(val->enum_type(), true);
+ vars["val_cpp"] = ClassName(val->enum_type(), true);
break;
default:
- (*variables)["val"] = PrimitiveTypeName(val->cpp_type());
+ vars["val_cpp"] = PrimitiveTypeName(val->cpp_type());
+ }
+ vars["key_wire_type"] = "::google::protobuf::internal::WireFormatLite::TYPE_" +
+ ToUpper(DeclaredTypeMethodName(key->type()));
+ vars["val_wire_type"] = "::google::protobuf::internal::WireFormatLite::TYPE_" +
+ ToUpper(DeclaredTypeMethodName(val->type()));
+ if (descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3 &&
+ val->type() == FieldDescriptor::TYPE_ENUM) {
+ const EnumValueDescriptor* default_value = val->default_value_enum();
+ vars["default_enum_value"] = Int32ToString(default_value->number());
+ } else {
+ vars["default_enum_value"] = "0";
}
- (*variables)["key_wire_type"] =
- "::google::protobuf::internal::WireFormatLite::TYPE_" +
- ToUpper(DeclaredTypeMethodName(key->type()));
- (*variables)["val_wire_type"] =
- "::google::protobuf::internal::WireFormatLite::TYPE_" +
- ToUpper(DeclaredTypeMethodName(val->type()));
}
// Does the given field have a private (internal helper only) has_$name$()
@@ -495,33 +232,233 @@ bool HasPrivateHasMethod(const FieldDescriptor* field) {
}
+bool TableDrivenParsingEnabled(
+ const Descriptor* descriptor, const Options& options) {
+ if (!options.table_driven_parsing) {
+ return false;
+ }
+
+ // Consider table-driven parsing. We only do this if:
+ // - We have has_bits for fields. This avoids a check on every field we set
+ // when are present (the common case).
+ if (!HasFieldPresence(descriptor->file())) {
+ return false;
+ }
+
+ const double table_sparseness = 0.5;
+ int max_field_number = 0;
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ const FieldDescriptor* field = descriptor->field(i);
+ if (max_field_number < field->number()) {
+ max_field_number = field->number();
+ }
+
+ // - There are no weak fields.
+ if (field->options().weak()) {
+ return false;
+ }
+ }
+
+ // - There range of field numbers is "small"
+ if (max_field_number >= (2 << 14)) {
+ return false;
+ }
+
+ // - Field numbers are relatively dense within the actual number of fields.
+ // We check for strictly greater than in the case where there are no fields
+ // (only extensions) so max_field_number == descriptor->field_count() == 0.
+ if (max_field_number * table_sparseness > descriptor->field_count()) {
+ return false;
+ }
+
+ // - This is not a MapEntryMessage.
+ if (IsMapEntryMessage(descriptor)) {
+ return false;
+ }
+
+ return true;
+}
+
+void SetUnknkownFieldsVariable(const Descriptor* descriptor,
+ const Options& options,
+ std::map<string, string>* variables) {
+ if (UseUnknownFieldSet(descriptor->file(), options)) {
+ (*variables)["unknown_fields_type"] = "::google::protobuf::UnknownFieldSet";
+ } else {
+ (*variables)["unknown_fields_type"] = "::std::string";
+ }
+ if (AlwaysPreserveUnknownFields(descriptor)) {
+ (*variables)["have_unknown_fields"] =
+ "_internal_metadata_.have_unknown_fields()";
+ (*variables)["unknown_fields"] = "_internal_metadata_.unknown_fields()";
+ } else {
+ (*variables)["have_unknown_fields"] =
+ "(_internal_metadata_.have_unknown_fields() && "
+ " ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())";
+ (*variables)["unknown_fields"] =
+ "(::google::protobuf::internal::GetProto3PreserveUnknownsDefault()"
+ " ? _internal_metadata_.unknown_fields()"
+ " : _internal_metadata_.default_instance())";
+ }
+ (*variables)["mutable_unknown_fields"] =
+ "_internal_metadata_.mutable_unknown_fields()";
+}
+
+bool IsCrossFileMapField(const FieldDescriptor* field) {
+ if (!field->is_map()) {
+ return false;
+ }
+
+ const Descriptor* d = field->message_type();
+ const FieldDescriptor* value = d->FindFieldByNumber(2);
+
+ return IsCrossFileMessage(value);
+}
+
+bool IsCrossFileMaybeMap(const FieldDescriptor* field) {
+ if (IsCrossFileMapField(field)) {
+ return true;
+ }
+
+ return IsCrossFileMessage(field);
+}
+
+bool IsRequired(const std::vector<const FieldDescriptor*>& v) {
+ return v.front()->is_required();
+}
+
+// Allows chunking repeated fields together and non-repeated fields if the
+// fields share the same has_byte index.
+// TODO(seongkim): use lambda with capture instead of functor.
+class MatchRepeatedAndHasByte {
+ public:
+ MatchRepeatedAndHasByte(const std::vector<int>* has_bit_indices,
+ bool has_field_presence)
+ : has_bit_indices_(*has_bit_indices),
+ has_field_presence_(has_field_presence) {}
+
+ // Returns true if the following conditions are met:
+ // --both fields are repeated fields
+ // --both fields are non-repeated fields with either has_field_presence is
+ // false or have the same has_byte index.
+ bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const {
+ return a->is_repeated() == b->is_repeated() &&
+ (!has_field_presence_ || a->is_repeated() ||
+ has_bit_indices_[a->index()] / 8 ==
+ has_bit_indices_[b->index()] / 8);
+ }
+
+ private:
+ const std::vector<int>& has_bit_indices_;
+ const bool has_field_presence_;
+};
+
+// Allows chunking required fields separately after chunking with
+// MatchRepeatedAndHasByte.
+class MatchRepeatedAndHasByteAndRequired : public MatchRepeatedAndHasByte {
+ public:
+ MatchRepeatedAndHasByteAndRequired(const std::vector<int>* has_bit_indices,
+ bool has_field_presence)
+ : MatchRepeatedAndHasByte(has_bit_indices, has_field_presence) {}
+
+ bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const {
+ return MatchRepeatedAndHasByte::operator()(a, b) &&
+ a->is_required() == b->is_required();
+ }
+};
+
+// Allows chunking zero-initializable fields separately after chunking with
+// MatchRepeatedAndHasByte.
+class MatchRepeatedAndHasByteAndZeroInits : public MatchRepeatedAndHasByte {
+ public:
+ MatchRepeatedAndHasByteAndZeroInits(const std::vector<int>* has_bit_indices,
+ bool has_field_presence)
+ : MatchRepeatedAndHasByte(has_bit_indices, has_field_presence) {}
+
+ bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const {
+ return MatchRepeatedAndHasByte::operator()(a, b) &&
+ CanInitializeByZeroing(a) == CanInitializeByZeroing(b);
+ }
+};
+
+// Collects neighboring fields based on a given criteria (equivalent predicate).
+template <typename Predicate>
+std::vector<std::vector<const FieldDescriptor*> > CollectFields(
+ const std::vector<const FieldDescriptor*>& fields,
+ const Predicate& equivalent) {
+ std::vector<std::vector<const FieldDescriptor*> > chunks;
+ if (fields.empty()) {
+ return chunks;
+ }
+
+ const FieldDescriptor* last_field = fields.front();
+ std::vector<const FieldDescriptor*> chunk;
+ for (int i = 0; i < fields.size(); i++) {
+ if (!equivalent(last_field, fields[i]) && !chunk.empty()) {
+ chunks.push_back(chunk);
+ chunk.clear();
+ }
+ chunk.push_back(fields[i]);
+ last_field = fields[i];
+ }
+ if (!chunk.empty()) {
+ chunks.push_back(chunk);
+ }
+ return chunks;
+}
+
+// Returns a bit mask based on has_bit index of "fields" that are typically on
+// the same chunk. It is used in a group presence check where _has_bits_ is
+// masked to tell if any thing in "fields" is present.
+uint32 GenChunkMask(const std::vector<const FieldDescriptor*>& fields,
+ const std::vector<int>& has_bit_indices) {
+ GOOGLE_CHECK(!fields.empty());
+ int first_index_offset = has_bit_indices[fields.front()->index()] / 32;
+ uint32 chunk_mask = 0;
+ for (int i = 0; i < fields.size(); i++) {
+ const FieldDescriptor* field = fields[i];
+ // "index" defines where in the _has_bits_ the field appears.
+ int index = has_bit_indices[field->index()];
+ GOOGLE_CHECK_EQ(first_index_offset, index / 32);
+ chunk_mask |= static_cast<uint32>(1) << (index % 32);
+ }
+ GOOGLE_CHECK_NE(0, chunk_mask);
+ return chunk_mask;
+}
+
} // anonymous namespace
// ===================================================================
MessageGenerator::MessageGenerator(const Descriptor* descriptor,
- const Options& options)
+ int index_in_file_messages,
+ const Options& options,
+ SCCAnalyzer* scc_analyzer)
: descriptor_(descriptor),
+ index_in_file_messages_(index_in_file_messages),
classname_(ClassName(descriptor, false)),
options_(options),
- field_generators_(descriptor, options),
+ field_generators_(descriptor, options, scc_analyzer),
max_has_bit_index_(0),
- nested_generators_(new google::protobuf::scoped_ptr<
- MessageGenerator>[descriptor->nested_type_count()]),
enum_generators_(
- new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]),
- extension_generators_(new google::protobuf::scoped_ptr<
- ExtensionGenerator>[descriptor->extension_count()]),
- use_dependent_base_(false) {
-
+ new std::unique_ptr<EnumGenerator>[descriptor->enum_type_count()]),
+ extension_generators_(new std::unique_ptr<
+ ExtensionGenerator>[descriptor->extension_count()]),
+ num_weak_fields_(0),
+ message_layout_helper_(new PaddingOptimizer()),
+ scc_analyzer_(scc_analyzer) {
// Compute optimized field order to be used for layout and initialization
// purposes.
for (int i = 0; i < descriptor_->field_count(); i++) {
- if (!descriptor_->field(i)->containing_oneof()) {
- optimized_order_.push_back(descriptor_->field(i));
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (field->options().weak()) {
+ num_weak_fields_++;
+ } else if (!field->containing_oneof()) {
+ optimized_order_.push_back(field);
}
}
- OptimizePadding(&optimized_order_, options_);
+
+ message_layout_helper_->OptimizeLayout(&optimized_order_, options_);
if (HasFieldPresence(descriptor_->file())) {
// We use -1 as a sentinel.
@@ -537,11 +474,6 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
}
}
- for (int i = 0; i < descriptor->nested_type_count(); i++) {
- nested_generators_[i].reset(
- new MessageGenerator(descriptor->nested_type(i), options));
- }
-
for (int i = 0; i < descriptor->enum_type_count(); i++) {
enum_generators_[i].reset(
new EnumGenerator(descriptor->enum_type(i), options));
@@ -557,14 +489,12 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
if (descriptor->field(i)->is_required()) {
++num_required_fields_;
}
- if (options.proto_h && IsFieldDependent(descriptor->field(i))) {
- use_dependent_base_ = true;
- }
- }
- if (options.proto_h && descriptor->oneof_decl_count() > 0) {
- // Always make oneofs dependent.
- use_dependent_base_ = true;
}
+
+ table_driven_ = TableDrivenParsingEnabled(descriptor_, options_);
+
+ scc_name_ =
+ ClassName(scc_analyzer_->GetSCC(descriptor_)->GetRepresentative(), false);
}
MessageGenerator::~MessageGenerator() {}
@@ -582,13 +512,6 @@ size_t MessageGenerator::HasBitsSize() const {
return sizeof_has_bits;
}
-void MessageGenerator::Flatten(std::vector<MessageGenerator*>* list) {
- for (int i = 0; i < descriptor_->nested_type_count(); i++) {
- nested_generators_[i]->Flatten(list);
- }
- list->push_back(this);
-}
-
void MessageGenerator::AddGenerators(
std::vector<EnumGenerator*>* enum_generators,
std::vector<ExtensionGenerator*>* extension_generators) {
@@ -602,33 +525,10 @@ void MessageGenerator::AddGenerators(
void MessageGenerator::FillMessageForwardDeclarations(
std::map<string, const Descriptor*>* class_names) {
- if (IsMapEntryMessage(descriptor_)) return;
(*class_names)[classname_] = descriptor_;
}
void MessageGenerator::
-GenerateDependentFieldAccessorDeclarations(io::Printer* printer) {
- for (int i = 0; i < descriptor_->field_count(); i++) {
- const FieldDescriptor* field = descriptor_->field(i);
-
- PrintFieldComment(printer, field);
-
- std::map<string, string> vars;
- SetCommonFieldVariables(field, &vars, options_);
-
- if (use_dependent_base_ && IsFieldDependent(field)) {
- // If the message is dependent, the inline clear_*() method will need
- // to delete the message type, so it must be in the dependent base
- // class. (See also GenerateFieldAccessorDeclarations.)
- printer->Print(vars, "$deprecated_attr$void clear_$name$();\n");
- }
- // Generate type-specific accessor declarations.
- field_generators_.get(field).GenerateDependentAccessorDeclarations(printer);
- printer->Print("\n");
- }
-}
-
-void MessageGenerator::
GenerateFieldAccessorDeclarations(io::Printer* printer) {
// optimized_fields_ does not contain fields where
// field->containing_oneof() != NULL
@@ -644,7 +544,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
ordered_fields.begin(), optimized_order_.begin(), optimized_order_.end());
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
- if (field->containing_oneof() == NULL) {
+ if (field->containing_oneof() == NULL && !field->options().weak()) {
continue;
}
ordered_fields.push_back(field);
@@ -659,40 +559,26 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
SetCommonFieldVariables(field, &vars, options_);
vars["constant_name"] = FieldConstantName(field);
- bool dependent_field = use_dependent_base_ && IsFieldDependent(field);
- if (dependent_field &&
- field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
- !field->is_map()) {
- // If this field is dependent, the dependent base class determines
- // the message type from the derived class (which is a template
- // parameter). This typedef is for that:
- printer->Print(
- "private:\n"
- "typedef $field_type$ $dependent_type$;\n"
- "public:\n",
- "field_type", FieldMessageTypeName(field),
- "dependent_type", DependentTypeName(field));
- }
-
if (field->is_repeated()) {
- printer->Print(vars, "$deprecated_attr$int $name$_size() const;\n");
+ printer->Print(vars, "$deprecated_attr$int ${$$name$_size$}$() const;\n");
+ printer->Annotate("{", "}", field);
} else if (HasHasMethod(field)) {
- printer->Print(vars, "$deprecated_attr$bool has_$name$() const;\n");
+ printer->Print(vars, "$deprecated_attr$bool ${$has_$name$$}$() const;\n");
+ printer->Annotate("{", "}", field);
} else if (HasPrivateHasMethod(field)) {
printer->Print(vars,
- "private:\n"
- "bool has_$name$() const;\n"
- "public:\n");
+ "private:\n"
+ "bool ${$has_$name$$}$() const;\n"
+ "public:\n");
+ printer->Annotate("{", "}", field);
}
- if (!dependent_field) {
- // If this field is dependent, then its clear_() method is in the
- // depenent base class. (See also GenerateDependentAccessorDeclarations.)
- printer->Print(vars, "$deprecated_attr$void clear_$name$();\n");
- }
+ printer->Print(vars, "$deprecated_attr$void ${$clear_$name$$}$();\n");
+ printer->Annotate("{", "}", field);
printer->Print(vars,
"$deprecated_attr$static const int $constant_name$ = "
"$number$;\n");
+ printer->Annotate("constant_name", field);
// Generate type-specific accessor declarations.
field_generators_.get(field).GenerateAccessorDeclarations(printer);
@@ -710,6 +596,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
printer->Print(
+ "void clear_$oneof_name$();\n"
"$camel_oneof_name$Case $oneof_name$_case() const;\n",
"camel_oneof_name",
UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true),
@@ -718,65 +605,17 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
}
void MessageGenerator::
-GenerateDependentFieldAccessorDefinitions(io::Printer* printer) {
- if (!use_dependent_base_) return;
-
- printer->Print("// $classname$\n\n", "classname",
- DependentBaseClassTemplateName(descriptor_));
-
- for (int i = 0; i < descriptor_->field_count(); i++) {
- const FieldDescriptor* field = descriptor_->field(i);
-
- if (field->options().weak()) continue;
-
- PrintFieldComment(printer, field);
-
- // These functions are not really dependent: they are part of the
- // (non-dependent) derived class. However, they need to live outside
- // any #ifdef guards, so we treat them as if they were dependent.
- //
- // See the comment in FileGenerator::GenerateInlineFunctionDefinitions
- // for a more complete explanation.
- if (use_dependent_base_ && IsFieldDependent(field)) {
- std::map<string, string> vars;
- SetCommonFieldVariables(field, &vars, options_);
- vars["inline"] = "inline ";
- if (field->containing_oneof()) {
- vars["field_name"] = UnderscoresToCamelCase(field->name(), true);
- vars["oneof_name"] = field->containing_oneof()->name();
- vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
- GenerateOneofMemberHasBits(field, vars, printer);
- } else if (!field->is_repeated()) {
- // There will be no header guard, so this always has to be inline.
- GenerateSingularFieldHasBits(field, vars, printer);
- }
- // vars needed for clear_(), which is in the dependent base:
- // (See also GenerateDependentFieldAccessorDeclarations.)
- vars["tmpl"] = "template<class T>\n";
- vars["dependent_classname"] =
- DependentBaseClassTemplateName(descriptor_) + "<T>";
- vars["this_message"] = DependentBaseDownCast();
- vars["this_const_message"] = DependentBaseConstDownCast();
- GenerateFieldClear(field, vars, printer);
- }
-
- // Generate type-specific accessors.
- field_generators_.get(field)
- .GenerateDependentInlineAccessorDefinitions(printer);
-
- printer->Print("\n");
- }
-
- // Generate has_$name$() and clear_has_$name$() functions for oneofs
- // Similar to other has-bits, these must always be in the header if we
- // are using a dependent base class.
- GenerateOneofHasBits(printer, true /* is_inline */);
-}
-
-void MessageGenerator::
GenerateSingularFieldHasBits(const FieldDescriptor* field,
std::map<string, string> vars,
io::Printer* printer) {
+ if (field->options().weak()) {
+ printer->Print(
+ vars,
+ "inline bool $classname$::has_$name$() const {\n"
+ " return _weak_field_map_.Has($number$);\n"
+ "}\n");
+ return;
+ }
if (HasFieldPresence(descriptor_->file())) {
// N.B.: without field presence, we do not use has-bits or generate
// has_$name$() methods.
@@ -787,16 +626,13 @@ GenerateSingularFieldHasBits(const FieldDescriptor* field,
vars["has_mask"] = StrCat(strings::Hex(1u << (has_bit_index % 32),
strings::ZERO_PAD_8));
printer->Print(vars,
- "$inline$"
- "bool $classname$::has_$name$() const {\n"
+ "inline bool $classname$::has_$name$() const {\n"
" return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
"}\n"
- "$inline$"
- "void $classname$::set_has_$name$() {\n"
+ "inline void $classname$::set_has_$name$() {\n"
" _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
"}\n"
- "$inline$"
- "void $classname$::clear_has_$name$() {\n"
+ "inline void $classname$::clear_has_$name$() {\n"
" _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
"}\n");
} else {
@@ -805,15 +641,13 @@ GenerateSingularFieldHasBits(const FieldDescriptor* field,
bool is_lazy = false;
if (is_lazy) {
printer->Print(vars,
- "$inline$"
- "bool $classname$::has_$name$() const {\n"
+ "inline bool $classname$::has_$name$() const {\n"
" return !$name$_.IsCleared();\n"
"}\n");
} else {
printer->Print(
vars,
- "$inline$"
- "bool $classname$::has_$name$() const {\n"
+ "inline bool $classname$::has_$name$() const {\n"
" return this != internal_default_instance() && $name$_ != NULL;\n"
"}\n");
}
@@ -822,7 +656,7 @@ GenerateSingularFieldHasBits(const FieldDescriptor* field,
}
void MessageGenerator::
-GenerateOneofHasBits(io::Printer* printer, bool is_inline) {
+GenerateOneofHasBits(io::Printer* printer) {
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
std::map<string, string> vars;
vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
@@ -830,15 +664,12 @@ GenerateOneofHasBits(io::Printer* printer, bool is_inline) {
vars["cap_oneof_name"] =
ToUpper(descriptor_->oneof_decl(i)->name());
vars["classname"] = classname_;
- vars["inline"] = (is_inline ? "inline " : "");
printer->Print(
vars,
- "$inline$"
- "bool $classname$::has_$oneof_name$() const {\n"
+ "inline bool $classname$::has_$oneof_name$() const {\n"
" return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n"
"}\n"
- "$inline$"
- "void $classname$::clear_has_$oneof_name$() {\n"
+ "inline void $classname$::clear_has_$oneof_name$() {\n"
" _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n"
"}\n");
}
@@ -855,13 +686,11 @@ GenerateOneofMemberHasBits(const FieldDescriptor* field,
// method, so that generated code is slightly cleaner (vs. comparing
// _oneof_case_[index] against a constant everywhere).
printer->Print(vars,
- "$inline$"
- "bool $classname$::has_$name$() const {\n"
+ "inline bool $classname$::has_$name$() const {\n"
" return $oneof_name$_case() == k$field_name$;\n"
"}\n");
printer->Print(vars,
- "$inline$"
- "void $classname$::set_has_$name$() {\n"
+ "inline void $classname$::set_has_$name$() {\n"
" _oneof_case_[$oneof_index$] = k$field_name$;\n"
"}\n");
}
@@ -869,14 +698,14 @@ GenerateOneofMemberHasBits(const FieldDescriptor* field,
void MessageGenerator::
GenerateFieldClear(const FieldDescriptor* field,
const std::map<string, string>& vars,
+ bool is_inline,
io::Printer* printer) {
- // Generate clear_$name$() (See GenerateFieldAccessorDeclarations and
- // GenerateDependentFieldAccessorDeclarations, $dependent_classname$ is
- // set by the Generate*Definitions functions.)
+ // Generate clear_$name$().
+ if (is_inline) {
+ printer->Print("inline ");
+ }
printer->Print(vars,
- "$tmpl$"
- "$inline$"
- "void $dependent_classname$::clear_$name$() {\n");
+ "void $classname$::clear_$name$() {\n");
printer->Indent();
@@ -884,21 +713,20 @@ GenerateFieldClear(const FieldDescriptor* field,
// Clear this field only if it is the active field in this oneof,
// otherwise ignore
printer->Print(vars,
- "if ($this_message$has_$name$()) {\n");
+ "if (has_$name$()) {\n");
printer->Indent();
field_generators_.get(field)
.GenerateClearingCode(printer);
printer->Print(vars,
- "$this_message$clear_has_$oneof_name$();\n");
+ "clear_has_$oneof_name$();\n");
printer->Outdent();
printer->Print("}\n");
} else {
field_generators_.get(field)
.GenerateClearingCode(printer);
if (HasFieldPresence(descriptor_->file())) {
- if (!field->is_repeated()) {
- printer->Print(vars,
- "$this_message$clear_has_$name$();\n");
+ if (!field->is_repeated() && !field->options().weak()) {
+ printer->Print(vars, "clear_has_$name$();\n");
}
}
}
@@ -908,7 +736,7 @@ GenerateFieldClear(const FieldDescriptor* field,
}
void MessageGenerator::
-GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
+GenerateFieldAccessorDefinitions(io::Printer* printer) {
printer->Print("// $classname$\n\n", "classname", classname_);
for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -918,96 +746,74 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
std::map<string, string> vars;
SetCommonFieldVariables(field, &vars, options_);
- vars["inline"] = is_inline ? "inline " : "";
- if (use_dependent_base_ && IsFieldDependent(field)) {
- vars["tmpl"] = "template<class T>\n";
- vars["dependent_classname"] =
- DependentBaseClassTemplateName(descriptor_) + "<T>";
- vars["this_message"] = "reinterpret_cast<T*>(this)->";
- vars["this_const_message"] = "reinterpret_cast<const T*>(this)->";
- } else {
- vars["tmpl"] = "";
- vars["dependent_classname"] = vars["classname"];
- vars["this_message"] = "";
- vars["this_const_message"] = "";
- }
// Generate has_$name$() or $name$_size().
if (field->is_repeated()) {
printer->Print(vars,
- "$inline$"
- "int $classname$::$name$_size() const {\n"
+ "inline int $classname$::$name$_size() const {\n"
" return $name$_.size();\n"
"}\n");
} else if (field->containing_oneof()) {
vars["field_name"] = UnderscoresToCamelCase(field->name(), true);
vars["oneof_name"] = field->containing_oneof()->name();
vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
- if (!use_dependent_base_ || !IsFieldDependent(field)) {
- GenerateOneofMemberHasBits(field, vars, printer);
- }
+ GenerateOneofMemberHasBits(field, vars, printer);
} else {
// Singular field.
- if (!use_dependent_base_ || !IsFieldDependent(field)) {
- GenerateSingularFieldHasBits(field, vars, printer);
- }
+ GenerateSingularFieldHasBits(field, vars, printer);
}
- if (!use_dependent_base_ || !IsFieldDependent(field)) {
- GenerateFieldClear(field, vars, printer);
+ if (!IsCrossFileMaybeMap(field)) {
+ GenerateFieldClear(field, vars, true, printer);
}
// Generate type-specific accessors.
- field_generators_.get(field).GenerateInlineAccessorDefinitions(printer,
- is_inline);
+ field_generators_.get(field).GenerateInlineAccessorDefinitions(printer);
printer->Print("\n");
}
- if (!use_dependent_base_) {
- // Generate has_$name$() and clear_has_$name$() functions for oneofs
- // If we aren't using a dependent base, they can be with the other functions
- // that are #ifdef-guarded.
- GenerateOneofHasBits(printer, is_inline);
- }
-}
-
-void MessageGenerator::
-GenerateDependentBaseClassDefinition(io::Printer* printer) {
- if (!use_dependent_base_) {
- return;
- }
-
- std::map<string, string> vars;
- vars["classname"] = DependentBaseClassTemplateName(descriptor_);
- vars["full_name"] = descriptor_->full_name();
- vars["superclass"] = SuperClassName(descriptor_, options_);
-
- printer->Print(vars,
- "template <class T>\n"
- "class $classname$ : public $superclass$ "
- "/* @@protoc_insertion_point(dep_base_class_definition:$full_name$) */ {\n"
- " public:\n");
- printer->Indent();
-
- printer->Print(vars,
- "$classname$() {}\n"
- "virtual ~$classname$() {}\n"
- "\n");
-
- // Generate dependent accessor methods for all fields.
- GenerateDependentFieldAccessorDeclarations(printer);
-
- printer->Outdent();
- printer->Print("};\n");
+ // Generate has_$name$() and clear_has_$name$() functions for oneofs.
+ GenerateOneofHasBits(printer);
}
void MessageGenerator::
GenerateClassDefinition(io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) return;
- if (use_dependent_base_) {
- GenerateDependentBaseClassDefinition(printer);
- printer->Print("\n");
+ if (IsMapEntryMessage(descriptor_)) {
+ std::map<string, string> vars;
+ vars["classname"] = classname_;
+ CollectMapInfo(descriptor_, &vars);
+ vars["lite"] =
+ HasDescriptorMethods(descriptor_->file(), options_) ? "" : "Lite";
+ printer->Print(
+ vars,
+ "class $classname$ : public "
+ "::google::protobuf::internal::MapEntry$lite$<$classname$, \n"
+ " $key_cpp$, $val_cpp$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$ > {\n"
+ "public:\n"
+ " typedef ::google::protobuf::internal::MapEntry$lite$<$classname$, \n"
+ " $key_cpp$, $val_cpp$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$ > SuperType;\n"
+ " $classname$();\n"
+ " $classname$(::google::protobuf::Arena* arena);\n"
+ " void MergeFrom(const $classname$& other);\n"
+ " static const $classname$* internal_default_instance() { return "
+ "reinterpret_cast<const "
+ "$classname$*>(&_$classname$_default_instance_); }\n");
+ if (HasDescriptorMethods(descriptor_->file(), options_)) {
+ printer->Print(
+ " void MergeFrom(const ::google::protobuf::Message& other) final;\n"
+ " ::google::protobuf::Metadata GetMetadata() const;\n"
+ "};\n");
+ } else {
+ printer->Print("};\n");
+ }
+ return;
}
std::map<string, string> vars;
@@ -1020,49 +826,63 @@ GenerateClassDefinition(io::Printer* printer) {
} else {
vars["dllexport"] = options_.dllexport_decl + " ";
}
- if (use_dependent_base_) {
- vars["superclass"] =
- DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">";
- } else {
- vars["superclass"] = SuperClassName(descriptor_, options_);
- }
+ vars["superclass"] = SuperClassName(descriptor_, options_);
printer->Print(vars,
"class $dllexport$$classname$ : public $superclass$ "
"/* @@protoc_insertion_point(class_definition:$full_name$) */ "
"{\n");
printer->Annotate("classname", descriptor_);
- if (use_dependent_base_) {
- printer->Print(vars, " friend class $superclass$;\n");
- }
printer->Print(" public:\n");
printer->Indent();
+ printer->Print(
+ vars,
+ "$classname$();\n"
+ "virtual ~$classname$();\n"
+ "\n"
+ "$classname$(const $classname$& from);\n"
+ "\n"
+ "inline $classname$& operator=(const $classname$& from) {\n"
+ " CopyFrom(from);\n"
+ " return *this;\n"
+ "}\n");
+
+ if (options_.table_driven_serialization) {
+ printer->Print(
+ "private:\n"
+ "const void* InternalGetTable() const;\n"
+ "public:\n"
+ "\n");
+ }
+
+ // Generate move constructor and move assignment operator.
printer->Print(vars,
- "$classname$();\n"
- "virtual ~$classname$();\n"
- "\n"
- "$classname$(const $classname$& from);\n"
+ "#if LANG_CXX11\n"
+ "$classname$($classname$&& from) noexcept\n"
+ " : $classname$() {\n"
+ " *this = ::std::move(from);\n"
+ "}\n"
"\n"
- "inline $classname$& operator=(const $classname$& from) {\n"
- " CopyFrom(from);\n"
+ "inline $classname$& operator=($classname$&& from) noexcept {\n"
+ " if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {\n"
+ " if (this != &from) InternalSwap(&from);\n"
+ " } else {\n"
+ " CopyFrom(from);\n"
+ " }\n"
" return *this;\n"
"}\n"
- "\n");
+ "#endif\n");
- if (PreserveUnknownFields(descriptor_)) {
- string type = UseUnknownFieldSet(descriptor_->file(), options_)
- ? "::google::protobuf::UnknownFieldSet"
- : "::std::string";
- printer->Print(
- "inline const $type$& unknown_fields() const {\n"
- " return _internal_metadata_.unknown_fields();\n"
- "}\n"
- "\n"
- "inline $type$* mutable_unknown_fields() {\n"
- " return _internal_metadata_.mutable_unknown_fields();\n"
- "}\n"
- "\n",
- "type", type );
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
+ if (PublicUnknownFieldsAccessors(descriptor_)) {
+ printer->Print(vars,
+ "inline const $unknown_fields_type$& unknown_fields() const {\n"
+ " return $unknown_fields$;\n"
+ "}\n"
+ "inline $unknown_fields_type$* mutable_unknown_fields() {\n"
+ " return $mutable_unknown_fields$;\n"
+ "}\n"
+ "\n");
}
// N.B.: We exclude GetArena() when arena support is disabled, falling back on
@@ -1072,10 +892,10 @@ GenerateClassDefinition(io::Printer* printer) {
// virtual method version of GetArenaNoVirtual(), required for generic dispatch given a
// MessageLite* (e.g., in RepeatedField::AddAllocated()).
printer->Print(
- "inline ::google::protobuf::Arena* GetArena() const PROTOBUF_FINAL {\n"
+ "inline ::google::protobuf::Arena* GetArena() const final {\n"
" return GetArenaNoVirtual();\n"
"}\n"
- "inline void* GetMaybeArenaPointer() const PROTOBUF_FINAL {\n"
+ "inline void* GetMaybeArenaPointer() const final {\n"
" return MaybeArenaPtr();\n"
"}\n");
}
@@ -1119,15 +939,18 @@ GenerateClassDefinition(io::Printer* printer) {
}
// TODO(gerbens) make this private, while still granting other protos access.
+ vars["message_index"] = SimpleItoa(index_in_file_messages_);
printer->Print(
vars,
+ "static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY\n"
"static inline const $classname$* internal_default_instance() {\n"
" return reinterpret_cast<const $classname$*>(\n"
" &_$classname$_default_instance_);\n"
"}\n"
+ "static constexpr int kIndexInFileMessages =\n"
+ " $message_index$;\n"
"\n");
-
if (SupportsArenas(descriptor_)) {
printer->Print(vars,
"void UnsafeArenaSwap($classname$* other);\n");
@@ -1144,39 +967,48 @@ GenerateClassDefinition(io::Printer* printer) {
"template<typename T> bool Is() const {\n"
" return _any_metadata_.Is<T>();\n"
"}\n"
+ "static bool ParseAnyTypeUrl(const string& type_url,\n"
+ " string* full_type_name);\n"
"\n");
}
- vars["new_final"] = " PROTOBUF_FINAL";
+ vars["new_final"] = " final";
printer->Print(vars,
"void Swap($classname$* other);\n"
+ "friend void swap($classname$& a, $classname$& b) {\n"
+ " a.Swap(&b);\n"
+ "}\n"
"\n"
"// implements Message ----------------------------------------------\n"
"\n"
- "inline $classname$* New() const$new_final$ { return New(NULL); }\n"
+ "inline $classname$* New() const$new_final$ {\n"
+ " return CreateMaybeMessage<$classname$>(NULL);\n"
+ "}\n"
"\n"
- "$classname$* New(::google::protobuf::Arena* arena) const$new_final$;\n");
+ "$classname$* New(::google::protobuf::Arena* arena) const$new_final$ {\n"
+ " return CreateMaybeMessage<$classname$>(arena);\n"
+ "}\n");
// For instances that derive from Message (rather than MessageLite), some
// methods are virtual and should be marked as final.
string use_final = HasDescriptorMethods(descriptor_->file(), options_) ?
- " PROTOBUF_FINAL" : "";
+ " final" : "";
if (HasGeneratedMethods(descriptor_->file(), options_)) {
if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print(vars,
- "void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;\n"
- "void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;\n");
+ "void CopyFrom(const ::google::protobuf::Message& from) final;\n"
+ "void MergeFrom(const ::google::protobuf::Message& from) final;\n");
} else {
printer->Print(vars,
"void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)\n"
- " PROTOBUF_FINAL;\n");
+ " final;\n");
}
- vars["clear_final"] = " PROTOBUF_FINAL";
- vars["is_initialized_final"] = " PROTOBUF_FINAL";
- vars["merge_partial_final"] = " PROTOBUF_FINAL";
+ vars["clear_final"] = " final";
+ vars["is_initialized_final"] = " final";
+ vars["merge_partial_final"] = " final";
printer->Print(
vars,
@@ -1185,11 +1017,16 @@ GenerateClassDefinition(io::Printer* printer) {
"void Clear()$clear_final$;\n"
"bool IsInitialized() const$is_initialized_final$;\n"
"\n"
- "size_t ByteSizeLong() const PROTOBUF_FINAL;\n"
+ "size_t ByteSizeLong() const final;\n"
"bool MergePartialFromCodedStream(\n"
- " ::google::protobuf::io::CodedInputStream* input)$merge_partial_final$;\n"
- "void SerializeWithCachedSizes(\n"
- " ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;\n");
+ " ::google::protobuf::io::CodedInputStream* input)$merge_partial_final$;\n");
+ if (!options_.table_driven_serialization ||
+ descriptor_->options().message_set_wire_format()) {
+ printer->Print(
+ "void SerializeWithCachedSizes(\n"
+ " ::google::protobuf::io::CodedOutputStream* output) const "
+ "final;\n");
+ }
// DiscardUnknownFields() is implemented in message.cc using reflections. We
// need to implement this function in generated code for messages.
if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
@@ -1199,28 +1036,24 @@ GenerateClassDefinition(io::Printer* printer) {
}
if (HasFastArraySerialization(descriptor_->file(), options_)) {
printer->Print(
- "::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(\n"
- " bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;\n"
- "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output)\n"
- " const PROTOBUF_FINAL {\n"
- " return InternalSerializeWithCachedSizesToArray(\n"
- " ::google::protobuf::io::CodedOutputStream::"
- "IsDefaultSerializationDeterministic(), output);\n"
- "}\n");
+ "::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(\n"
+ " bool deterministic, ::google::protobuf::uint8* target) const final;\n");
}
}
printer->Print(
- "int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }\n"
- "private:\n"
- "void SharedCtor();\n"
- "void SharedDtor();\n"
- "void SetCachedSize(int size) const$final$;\n"
- "void InternalSwap($classname$* other);\n",
- "classname", classname_,
- "final", use_final);
+ "int GetCachedSize() const final { return _cached_size_.Get(); }"
+ "\n\nprivate:\n"
+ "void SharedCtor();\n"
+ "void SharedDtor();\n"
+ "void SetCachedSize(int size) const$final$;\n"
+ "void InternalSwap($classname$* other);\n",
+ "classname", classname_, "final", use_final);
if (SupportsArenas(descriptor_)) {
printer->Print(
+ // TODO(gerbens) Make this private! Currently people are deriving from
+ // protos to give access to this constructor, breaking the invariants
+ // we rely on.
"protected:\n"
"explicit $classname$(::google::protobuf::Arena* arena);\n"
"private:\n"
@@ -1255,11 +1088,11 @@ GenerateClassDefinition(io::Printer* printer) {
if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print(
- "::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;\n"
+ "::google::protobuf::Metadata GetMetadata() const final;\n"
"\n");
} else {
printer->Print(
- "::std::string GetTypeName() const PROTOBUF_FINAL;\n"
+ "::std::string GetTypeName() const final;\n"
"\n");
}
@@ -1274,6 +1107,8 @@ GenerateClassDefinition(io::Printer* printer) {
printer->Print("typedef $nested_full_name$ $nested_name$;\n",
"nested_name", nested_type->name(),
"nested_full_name", ClassName(nested_type, false));
+ printer->Annotate("nested_full_name", nested_type);
+ printer->Annotate("nested_name", nested_type);
}
}
@@ -1312,7 +1147,8 @@ GenerateClassDefinition(io::Printer* printer) {
for (int i = 0; i < descriptor_->field_count(); i++) {
- if (!descriptor_->field(i)->is_repeated()) {
+ if (!descriptor_->field(i)->is_repeated() &&
+ !descriptor_->field(i)->options().weak()) {
// set_has_***() generated in all proto1/2 code and in oneofs (only) for
// messages without true field presence.
if (HasFieldPresence(descriptor_->file()) ||
@@ -1335,7 +1171,6 @@ GenerateClassDefinition(io::Printer* printer) {
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
printer->Print(
"inline bool has_$oneof_name$() const;\n"
- "void clear_$oneof_name$();\n"
"inline void clear_has_$oneof_name$();\n\n",
"oneof_name", descriptor_->oneof_decl(i)->name());
}
@@ -1353,7 +1188,8 @@ GenerateClassDefinition(io::Printer* printer) {
bool need_to_emit_cached_size = true;
// TODO(kenton): Make _cached_size_ an atomic<int> when C++ supports it.
- const string cached_size_decl = "mutable int _cached_size_;\n";
+ const string cached_size_decl =
+ "mutable ::google::protobuf::internal::CachedSize _cached_size_;\n";
const size_t sizeof_has_bits = HasBitsSize();
const string has_bits_decl = sizeof_has_bits == 0 ? "" :
@@ -1385,7 +1221,7 @@ GenerateClassDefinition(io::Printer* printer) {
if (SupportsArenas(descriptor_)) {
printer->Print(
- "friend class ::google::protobuf::Arena;\n"
+ "template <typename T> friend class ::google::protobuf::Arena::InternalHelper;\n"
"typedef void InternalArenaConstructable_;\n"
"typedef void DestructorSkippable_;\n");
}
@@ -1451,6 +1287,10 @@ GenerateClassDefinition(io::Printer* printer) {
"\n");
}
+ if (num_weak_fields_) {
+ printer->Print(
+ "::google::protobuf::internal::WeakFieldMap _weak_field_map_;\n");
+ }
// Generate _any_metadata_ for the Any type.
if (IsAnyMessage(descriptor_)) {
printer->Print(vars,
@@ -1459,13 +1299,10 @@ GenerateClassDefinition(io::Printer* printer) {
// The TableStruct struct needs access to the private parts, in order to
// construct the offsets of all members.
- // Some InitDefault and Shutdown are defined as static member functions of
- // TableStruct such that they are also allowed to access private members.
- printer->Print(
- "friend struct $dllexport_decl$ $file_namespace$::TableStruct;\n",
- // Vars.
- "dllexport_decl", options_.dllexport_decl, "file_namespace",
- FileLevelNamespace(descriptor_->file()->name()));
+ printer->Print("friend struct ::$file_namespace$::TableStruct;\n",
+ // Vars.
+ "scc_name", scc_name_, "file_namespace",
+ FileLevelNamespace(descriptor_));
printer->Outdent();
printer->Print("};");
@@ -1473,21 +1310,9 @@ GenerateClassDefinition(io::Printer* printer) {
}
void MessageGenerator::
-GenerateDependentInlineMethods(io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) return;
- for (int i = 0; i < descriptor_->field_count(); i++) {
- if (descriptor_->field(i)->options().weak()) {
- field_generators_.get(descriptor_->field(i))
- .GenerateDependentInlineAccessorDefinitions(printer);
- }
- }
- GenerateDependentFieldAccessorDefinitions(printer);
-}
-
-void MessageGenerator::
-GenerateInlineMethods(io::Printer* printer, bool is_inline) {
+GenerateInlineMethods(io::Printer* printer) {
if (IsMapEntryMessage(descriptor_)) return;
- GenerateFieldAccessorDefinitions(printer, is_inline);
+ GenerateFieldAccessorDefinitions(printer);
// Generate oneof_case() functions.
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
@@ -1497,11 +1322,9 @@ GenerateInlineMethods(io::Printer* printer, bool is_inline) {
descriptor_->oneof_decl(i)->name(), true);
vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
- vars["inline"] = is_inline ? "inline " : "";
printer->Print(
vars,
- "$inline$"
- "$class_name$::$camel_oneof_name$Case $class_name$::"
+ "inline $class_name$::$camel_oneof_name$Case $class_name$::"
"$oneof_name$_case() const {\n"
" return $class_name$::$camel_oneof_name$Case("
"_oneof_case_[$oneof_index$]);\n"
@@ -1511,9 +1334,9 @@ GenerateInlineMethods(io::Printer* printer, bool is_inline) {
void MessageGenerator::
GenerateExtraDefaultFields(io::Printer* printer) {
- // Generate oneof default instance for reflection usage.
- if (descriptor_->oneof_decl_count() > 0) {
- printer->Print("public:\n");
+ // Generate oneof default instance and weak field instances for reflection
+ // usage.
+ if (descriptor_->oneof_decl_count() > 0 || num_weak_fields_ > 0) {
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
@@ -1525,84 +1348,356 @@ GenerateExtraDefaultFields(io::Printer* printer) {
field_generators_.get(field).GeneratePrivateMembers(printer);
}
}
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (field->options().weak()) {
+ printer->Print(
+ " const ::google::protobuf::Message* $name$_;\n", "name", FieldName(field));
+ }
+ }
+ }
+}
+
+bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset,
+ size_t aux_offset) {
+ if (!table_driven_) {
+ printer->Print("{ NULL, NULL, 0, -1, -1, -1, -1, NULL, false },\n");
+ return false;
+ }
+
+ std::map<string, string> vars;
+
+ vars["classname"] = ClassName(descriptor_);
+ vars["classtype"] = QualifiedClassName(descriptor_);
+ vars["offset"] = SimpleItoa(offset);
+ vars["aux_offset"] = SimpleItoa(aux_offset);
+
+ int max_field_number = 0;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (max_field_number < field->number()) {
+ max_field_number = field->number();
+ }
+ }
+
+ vars["max_field_number"] = SimpleItoa(max_field_number);
+
+ printer->Print("{\n");
+ printer->Indent();
+
+ printer->Print(vars,
+ "TableStruct::entries + $offset$,\n"
+ "TableStruct::aux + $aux_offset$,\n"
+ "$max_field_number$,\n");
+
+ if (!HasFieldPresence(descriptor_->file())) {
+ // If we don't have field presence, then _has_bits_ does not exist.
+ printer->Print(vars, "-1,\n");
+ } else {
+ printer->Print(vars,
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
+ " $classtype$, _has_bits_),\n");
}
+
+ if (descriptor_->oneof_decl_count() > 0) {
+ printer->Print(vars,
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
+ " $classtype$, _oneof_case_),\n");
+ } else {
+ printer->Print("-1, // no _oneof_case_\n");
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(vars,
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, "
+ "_extensions_),\n");
+ } else {
+ printer->Print("-1, // no _extensions_\n");
+ }
+
+ // TODO(ckennelly): Consolidate this with the calculation for
+ // AuxillaryParseTableField.
+ vars["ns"] = Namespace(descriptor_);
+
+ printer->Print(vars,
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
+ " $classtype$, _internal_metadata_),\n"
+ "&$ns$::_$classname$_default_instance_,\n");
+
+ if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+ printer->Print(vars, "true,\n");
+ } else {
+ printer->Print(vars, "false,\n");
+ }
+
+ printer->Outdent();
+ printer->Print("},\n");
+ return true;
}
void MessageGenerator::GenerateSchema(io::Printer* printer, int offset,
int has_offset) {
- if (IsMapEntryMessage(descriptor_)) return;
-
std::map<string, string> vars;
- vars["classname"] = classname_;
+ vars["classname"] = QualifiedClassName(descriptor_);
vars["offset"] = SimpleItoa(offset);
- vars["has_bits_offsets"] = HasFieldPresence(descriptor_->file())
- ? SimpleItoa(offset + has_offset)
- : "-1";
+ vars["has_bits_offsets"] =
+ HasFieldPresence(descriptor_->file()) || IsMapEntryMessage(descriptor_)
+ ? SimpleItoa(offset + has_offset)
+ : "-1";
printer->Print(vars,
"{ $offset$, $has_bits_offsets$, sizeof($classname$)},\n");
}
-void MessageGenerator::
-GenerateTypeRegistrations(io::Printer* printer) {
- // Register this message type with the message factory.
+namespace {
+
+// TODO(gerbens) remove this after the next sync with GitHub code base.
+// Then the opensource testing has gained the functionality to compile
+// the CalcFieldNum given the symbols defined in generated-message-util.
+#ifdef OPENSOURCE_PROTOBUF_CPP_BOOTSTRAP
+// We need a clean version of CalcFieldNum that doesn't use new functionality
+// in the runtime, because this functionality is not yet in the opensource
+// runtime
+
+uint32 CalculateType(uint32 type, uint32 type_class) {
+ return (type - 1) + type_class * 20;
+}
+
+uint32 CalcFieldNum(const FieldGenerator&, const FieldDescriptor* field,
+ const Options& options) {
+ bool is_a_map = IsMapEntryMessage(field->containing_type());
+ int type = field->type();
+ if (field->containing_oneof()) {
+ return CalculateType(type, 4);
+ }
+ if (field->is_packed()) {
+ return CalculateType(type, 3);
+ } else if (field->is_repeated()) {
+ return CalculateType(type, 2);
+ } else if (!HasFieldPresence(field->file()) &&
+ field->containing_oneof() == NULL && !is_a_map) {
+ return CalculateType(type, 1);
+ } else {
+ return CalculateType(type, 0);
+ }
+}
+
+#else
+// We need to calculate for each field what function the table driven code
+// should use to serialize it. This returns the index in a lookup table.
+uint32 CalcFieldNum(const FieldGenerator& generator,
+ const FieldDescriptor* field, const Options& options) {
+ bool is_a_map = IsMapEntryMessage(field->containing_type());
+ int type = field->type();
+ if (type == FieldDescriptor::TYPE_STRING ||
+ type == FieldDescriptor::TYPE_BYTES) {
+ if (generator.IsInlined()) {
+ type = internal::FieldMetadata::kInlinedType;
+ }
+ }
+ if (field->containing_oneof()) {
+ return internal::FieldMetadata::CalculateType(
+ type, internal::FieldMetadata::kOneOf);
+ }
+ if (field->is_packed()) {
+ return internal::FieldMetadata::CalculateType(
+ type, internal::FieldMetadata::kPacked);
+ } else if (field->is_repeated()) {
+ return internal::FieldMetadata::CalculateType(
+ type, internal::FieldMetadata::kRepeated);
+ } else if (!HasFieldPresence(field->file()) &&
+ field->containing_oneof() == NULL && !is_a_map) {
+ return internal::FieldMetadata::CalculateType(
+ type, internal::FieldMetadata::kNoPresence);
+ } else {
+ return internal::FieldMetadata::CalculateType(
+ type, internal::FieldMetadata::kPresence);
+ }
+}
+#endif
+
+int FindMessageIndexInFile(const Descriptor* descriptor) {
+ std::vector<const Descriptor*> flatten =
+ FlattenMessagesInFile(descriptor->file());
+ return std::find(flatten.begin(), flatten.end(), descriptor) -
+ flatten.begin();
+}
+
+} // namespace
+
+int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
+ if (!options_.table_driven_serialization) {
+ return 0;
+ }
+
+ string full_classname = QualifiedClassName(descriptor_);
+
+ std::vector<const FieldDescriptor*> sorted = SortFieldsByNumber(descriptor_);
if (IsMapEntryMessage(descriptor_)) {
- std::map<string, string> vars;
- CollectMapInfo(descriptor_, &vars);
- vars["classname"] = classname_;
- vars["file_namespace"] = FileLevelNamespace(descriptor_->file()->name());
+ for (int i = 0; i < 2; i++) {
+ const FieldDescriptor* field = sorted[i];
+ const FieldGenerator& generator = field_generators_.get(field);
- const FieldDescriptor* val = descriptor_->FindFieldByName("value");
- if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO2 &&
- val->type() == FieldDescriptor::TYPE_ENUM) {
- const EnumValueDescriptor* default_value = val->default_value_enum();
- vars["default_enum_value"] = Int32ToString(default_value->number());
- } else {
- vars["default_enum_value"] = "0";
+ uint32 tag = internal::WireFormatLite::MakeTag(
+ field->number(), WireFormat::WireTypeForFieldType(field->type()));
+
+ std::map<string, string> vars;
+ vars["classname"] = QualifiedClassName(descriptor_);
+ vars["field_name"] = FieldName(field);
+ vars["tag"] = SimpleItoa(tag);
+ vars["hasbit"] = SimpleItoa(i);
+ vars["type"] = SimpleItoa(CalcFieldNum(generator, field, options_));
+ vars["ptr"] = "NULL";
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ GOOGLE_CHECK(!IsMapEntryMessage(field->message_type()));
+ {
+ vars["ptr"] =
+ "::" + FileLevelNamespace(field->message_type()) +
+ "::TableStruct::serialization_table + " +
+ SimpleItoa(FindMessageIndexInFile(field->message_type()));
+ }
+ }
+ printer->Print(vars,
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+ "::google::protobuf::internal::MapEntryHelper<$classname$::"
+ "SuperType>, $field_name$_), $tag$,"
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+ "::google::protobuf::internal::MapEntryHelper<$classname$::"
+ "SuperType>, _has_bits_) * 8 + $hasbit$, $type$, "
+ "$ptr$},\n");
+ }
+ return 2;
+ }
+ printer->Print(
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
+ "_cached_size_), 0, 0, 0, NULL},\n",
+ "classname", full_classname);
+ std::vector<const Descriptor::ExtensionRange*> sorted_extensions;
+ for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
+ sorted_extensions.push_back(descriptor_->extension_range(i));
+ }
+ std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+ ExtensionRangeSorter());
+ for (int i = 0, extension_idx = 0; /* no range */; i++) {
+ for (; extension_idx < sorted_extensions.size() &&
+ (i == sorted.size() ||
+ sorted_extensions[extension_idx]->start < sorted[i]->number());
+ extension_idx++) {
+ const Descriptor::ExtensionRange* range =
+ sorted_extensions[extension_idx];
+ printer->Print(
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
+ "_extensions_), $start$, $end$, "
+ "::google::protobuf::internal::FieldMetadata::kSpecial, "
+ "reinterpret_cast<const "
+ "void*>(::google::protobuf::internal::ExtensionSerializer)},\n",
+ "classname", full_classname, "start", SimpleItoa(range->start), "end",
+ SimpleItoa(range->end));
+ }
+ if (i == sorted.size()) break;
+ const FieldDescriptor* field = sorted[i];
+
+ uint32 tag = internal::WireFormatLite::MakeTag(
+ field->number(), WireFormat::WireTypeForFieldType(field->type()));
+ if (field->is_packed()) {
+ tag = internal::WireFormatLite::MakeTag(
+ field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
}
- vars["index_in_metadata"] = SimpleItoa(index_in_metadata_);
+ string classfieldname = FieldName(field);
+ if (field->containing_oneof()) {
+ classfieldname = field->containing_oneof()->name();
+ }
+ std::map<string, string> vars;
+ vars["classname"] = full_classname;
+ vars["field_name"] = classfieldname;
+ vars["tag"] = SimpleItoa(tag);
+ vars["ptr"] = "NULL";
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (IsMapEntryMessage(field->message_type())) {
+ vars["idx"] = SimpleItoa(FindMessageIndexInFile(field->message_type()));
+ vars["fieldclassname"] = QualifiedClassName(field->message_type());
+ printer->Print(vars,
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, $field_name$_), $tag$, $idx$, "
+ "::google::protobuf::internal::FieldMetadata::kSpecial, "
+ "reinterpret_cast<const void*>(static_cast< "
+ "::google::protobuf::internal::SpecialSerializer>("
+ "::google::protobuf::internal::MapFieldSerializer< "
+ "::google::protobuf::internal::MapEntryToMapField<"
+ "$fieldclassname$>::MapFieldType, "
+ "TableStruct::serialization_table>))},\n");
+ continue;
+ } else {
+ vars["ptr"] =
+ "::" + FileLevelNamespace(field->message_type()) +
+ "::TableStruct::serialization_table + " +
+ SimpleItoa(FindMessageIndexInFile(field->message_type()));
+ }
+ }
- printer->Print(
- vars,
- "const ::google::protobuf::Descriptor* $classname$_descriptor = "
- "$file_namespace$::file_level_metadata[$index_in_metadata$].descriptor;"
- "\n"
- "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n"
- " $classname$_descriptor,\n"
- " ::google::protobuf::internal::MapEntry<\n"
- " $key$,\n"
- " $val$,\n"
- " $key_wire_type$,\n"
- " $val_wire_type$,\n"
- " $default_enum_value$>::CreateDefaultInstance(\n"
- " $classname$_descriptor));\n");
+ const FieldGenerator& generator = field_generators_.get(field);
+ vars["type"] = SimpleItoa(CalcFieldNum(generator, field, options_));
+
+
+ if (field->options().weak()) {
+ // TODO(gerbens) merge weak fields into ranges
+ printer->Print(vars,
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, _weak_field_map_), $tag$, $tag$, "
+ "::google::protobuf::internal::FieldMetadata::kSpecial, "
+ "reinterpret_cast<const "
+ "void*>(::google::protobuf::internal::WeakFieldSerializer)},\n");
+ } else if (field->containing_oneof()) {
+ vars["oneofoffset"] =
+ SimpleItoa(sizeof(uint32) * field->containing_oneof()->index());
+ printer->Print(vars,
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, $field_name$_), $tag$, "
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, _oneof_case_) + $oneofoffset$, "
+ "$type$, $ptr$},\n");
+ } else if (HasFieldPresence(descriptor_->file()) &&
+ has_bit_indices_[field->index()] != -1) {
+ vars["hasbitsoffset"] = SimpleItoa(has_bit_indices_[field->index()]);
+ printer->Print(vars,
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, $field_name$_), $tag$, "
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, _has_bits_) * 8 + $hasbitsoffset$, $type$, "
+ "$ptr$},\n");
+ } else {
+ printer->Print(vars,
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, $field_name$_), $tag$, ~0u, $type$, "
+ "$ptr$},\n");
+ }
}
+ int num_field_metadata = 1 + sorted.size() + sorted_extensions.size();
+ num_field_metadata++;
+ string serializer = UseUnknownFieldSet(descriptor_->file(), options_)
+ ? "::google::protobuf::internal::UnknownFieldSetSerializer"
+ : "::google::protobuf::internal::UnknownFieldSerializerLite";
+ printer->Print(
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
+ "_internal_metadata_), 0, ~0u, "
+ "::google::protobuf::internal::FieldMetadata::kSpecial, reinterpret_cast<const "
+ "void*>($serializer$)},\n",
+ "classname", full_classname, "serializer", serializer);
+ return num_field_metadata;
}
-void MessageGenerator::
-GenerateDefaultInstanceAllocator(io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) return;
-
- // Construct the default instances of all fields, as they will be used
- // when creating the default instance of the entire message.
+void MessageGenerator::GenerateFieldDefaultInstances(io::Printer* printer) {
+ // Construct the default instances for all fields that need one.
for (int i = 0; i < descriptor_->field_count(); i++) {
field_generators_.get(descriptor_->field(i))
.GenerateDefaultInstanceAllocator(printer);
}
-
- // Construct the default instance. We can't call InitAsDefaultInstance() yet
- // because we need to make sure all default instances that this one might
- // depend on are constructed first.
- printer->Print("_$classname$_default_instance_.DefaultConstruct();\n",
- "classname", classname_);
}
void MessageGenerator::
GenerateDefaultInstanceInitializer(io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) return;
-
// The default instance needs all of its embedded message pointers
// cross-linked to other default instances. We can't do this initialization
// in the constructor because some other default instances may not have been
@@ -1617,17 +1712,19 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) {
(field->containing_oneof() == NULL ||
HasDescriptorMethods(descriptor_->file(), options_))) {
string name;
- if (field->containing_oneof()) {
+ if (field->containing_oneof() || field->options().weak()) {
name = "_" + classname_ + "_default_instance_.";
} else {
- name = "_" + classname_ + "_default_instance_.get_mutable()->";
+ name =
+ "_" + classname_ + "_default_instance_._instance.get_mutable()->";
}
name += FieldName(field);
printer->Print(
- "$name$_ = const_cast< $type$*>(\n"
+ "$ns$::$name$_ = const_cast< $type$*>(\n"
" $type$::internal_default_instance());\n",
// Vars.
- "name", name, "type", FieldMessageTypeName(field));
+ "name", name, "type", FieldMessageTypeName(field), "ns",
+ Namespace(descriptor_));
} else if (field->containing_oneof() &&
HasDescriptorMethods(descriptor_->file(), options_)) {
field_generators_.get(descriptor_->field(i))
@@ -1637,27 +1734,42 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) {
}
void MessageGenerator::
-GenerateShutdownCode(io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) return;
-
- printer->Print("_$classname$_default_instance_.Shutdown();\n", "classname",
- classname_);
-
- if (HasDescriptorMethods(descriptor_->file(), options_)) {
- printer->Print("delete file_level_metadata[$index$].reflection;\n", "index",
- SimpleItoa(index_in_metadata_));
- }
-
- // Handle default instances of fields.
- for (int i = 0; i < descriptor_->field_count(); i++) {
- field_generators_.get(descriptor_->field(i))
- .GenerateShutdownCode(printer);
+GenerateClassMethods(io::Printer* printer) {
+ if (IsMapEntryMessage(descriptor_)) {
+ printer->Print(
+ "$classname$::$classname$() {}\n"
+ "$classname$::$classname$(::google::protobuf::Arena* arena) : "
+ "SuperType(arena) {}\n"
+ "void $classname$::MergeFrom(const $classname$& other) {\n"
+ " MergeFromInternal(other);\n"
+ "}\n",
+ "classname", classname_);
+ if (HasDescriptorMethods(descriptor_->file(), options_)) {
+ printer->Print(
+ "::google::protobuf::Metadata $classname$::GetMetadata() const {\n"
+ " ::$file_namespace$::protobuf_AssignDescriptorsOnce();\n"
+ " return ::$file_namespace$::file_level_metadata[$index$];\n"
+ "}\n"
+ "void $classname$::MergeFrom(\n"
+ " const ::google::protobuf::Message& other) {\n"
+ " ::google::protobuf::Message::MergeFrom(other);\n"
+ "}\n"
+ "\n",
+ "file_namespace", FileLevelNamespace(descriptor_),
+ "classname", classname_, "index",
+ SimpleItoa(index_in_file_messages_));
+ }
+ return;
}
-}
-void MessageGenerator::
-GenerateClassMethods(io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) return;
+ // TODO(gerbens) Remove this function. With a little bit of cleanup and
+ // refactoring this is superfluous.
+ printer->Print("void $classname$::InitAsDefaultInstance() {\n", "classname",
+ classname_);
+ printer->Indent();
+ GenerateDefaultInstanceInitializer(printer);
+ printer->Outdent();
+ printer->Print("}\n");
if (IsAnyMessage(descriptor_)) {
printer->Print(
@@ -1673,14 +1785,28 @@ GenerateClassMethods(io::Printer* printer) {
"bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n"
" return _any_metadata_.UnpackTo(message);\n"
"}\n"
+ "bool $classname$::ParseAnyTypeUrl(const string& type_url,\n"
+ " string* full_type_name) {\n"
+ " return ::google::protobuf::internal::ParseAnyTypeUrl(type_url,\n"
+ " full_type_name);\n"
+ "}\n"
"\n",
"classname", classname_);
}
// Generate non-inline field definitions.
for (int i = 0; i < descriptor_->field_count(); i++) {
- field_generators_.get(descriptor_->field(i))
+ const FieldDescriptor* field = descriptor_->field(i);
+ field_generators_.get(field)
.GenerateNonInlineAccessorDefinitions(printer);
+ if (IsCrossFileMaybeMap(field)) {
+ std::map<string, string> vars;
+ SetCommonFieldVariables(field, &vars, options_);
+ if (field->containing_oneof()) {
+ SetCommonOneofFieldVariables(field, &vars);
+ }
+ GenerateFieldClear(field, vars, false, printer);
+ }
}
// Generate field number constants.
@@ -1735,15 +1861,26 @@ GenerateClassMethods(io::Printer* printer) {
GenerateSwap(printer);
printer->Print("\n");
+ if (options_.table_driven_serialization) {
+ printer->Print(
+ "const void* $classname$::InternalGetTable() const {\n"
+ " return ::$file_namespace$::TableStruct::serialization_table + "
+ "$index$;\n"
+ "}\n"
+ "\n",
+ "classname", classname_, "index", SimpleItoa(index_in_file_messages_),
+ "file_namespace", FileLevelNamespace(descriptor_));
+ }
if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print(
"::google::protobuf::Metadata $classname$::GetMetadata() const {\n"
" $file_namespace$::protobuf_AssignDescriptorsOnce();\n"
- " return $file_namespace$::file_level_metadata[$index$];\n"
+ " return ::"
+ "$file_namespace$::file_level_metadata[kIndexInFileMessages];\n"
"}\n"
"\n",
- "classname", classname_, "index", SimpleItoa(index_in_metadata_),
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+ "classname", classname_, "file_namespace",
+ FileLevelNamespace(descriptor_));
} else {
printer->Print(
"::std::string $classname$::GetTypeName() const {\n"
@@ -1756,16 +1893,197 @@ GenerateClassMethods(io::Printer* printer) {
}
+size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) {
+ if (!table_driven_) {
+ return 0;
+ }
+
+ // Field "0" is special: We use it in our switch statement of processing
+ // types to handle the successful end tag case.
+ printer->Print("{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},\n");
+ int last_field_number = 1;
+
+ std::vector<const FieldDescriptor*> ordered_fields =
+ SortFieldsByNumber(descriptor_);
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = ordered_fields[i];
+ GOOGLE_CHECK_GE(field->number(), last_field_number);
+
+ for (; last_field_number < field->number(); last_field_number++) {
+ printer->Print(
+ "{ 0, 0, ::google::protobuf::internal::kInvalidMask,\n"
+ " ::google::protobuf::internal::kInvalidMask, 0, 0 },\n");
+ }
+ last_field_number++;
+
+ unsigned char normal_wiretype, packed_wiretype, processing_type;
+ normal_wiretype = WireFormat::WireTypeForFieldType(field->type());
+
+ if (field->is_packable()) {
+ packed_wiretype = WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
+ } else {
+ packed_wiretype = internal::kNotPackedMask;
+ }
+
+ processing_type = static_cast<unsigned>(field->type());
+ const FieldGenerator& generator = field_generators_.get(field);
+ if (field->type() == FieldDescriptor::TYPE_STRING) {
+ switch (EffectiveStringCType(field)) {
+ case FieldOptions::STRING:
+ default: {
+ if (generator.IsInlined()) {
+ processing_type = internal::TYPE_STRING_INLINED;
+ break;
+ }
+ break;
+ }
+ }
+ } else if (field->type() == FieldDescriptor::TYPE_BYTES) {
+ switch (EffectiveStringCType(field)) {
+ case FieldOptions::STRING:
+ default:
+ if (generator.IsInlined()) {
+ processing_type = internal::TYPE_BYTES_INLINED;
+ break;
+ }
+ break;
+ }
+ }
+
+ processing_type |= static_cast<unsigned>(
+ field->is_repeated() ? internal::kRepeatedMask : 0);
+ processing_type |= static_cast<unsigned>(
+ field->containing_oneof() ? internal::kOneofMask : 0);
+
+ if (field->is_map()) {
+ processing_type = internal::TYPE_MAP;
+ }
+
+ const unsigned char tag_size =
+ WireFormat::TagSize(field->number(), field->type());
+
+ std::map<string, string> vars;
+ vars["classname"] = QualifiedClassName(descriptor_);
+ if (field->containing_oneof() != NULL) {
+ vars["name"] = field->containing_oneof()->name();
+ vars["presence"] = SimpleItoa(field->containing_oneof()->index());
+ } else {
+ vars["name"] = FieldName(field);
+ vars["presence"] = SimpleItoa(has_bit_indices_[field->index()]);
+ }
+ vars["nwtype"] = SimpleItoa(normal_wiretype);
+ vars["pwtype"] = SimpleItoa(packed_wiretype);
+ vars["ptype"] = SimpleItoa(processing_type);
+ vars["tag_size"] = SimpleItoa(tag_size);
+
+ printer->Print(vars,
+ "{\n"
+ " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
+ " $classname$, $name$_),\n"
+ " static_cast<::google::protobuf::uint32>($presence$),\n"
+ " $nwtype$, $pwtype$, $ptype$, $tag_size$\n"
+ "},\n");
+ }
+
+ return last_field_number;
+}
+
+size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) {
+ if (!table_driven_) {
+ return 0;
+ }
+
+ std::vector<const FieldDescriptor*> ordered_fields =
+ SortFieldsByNumber(descriptor_);
+
+ printer->Print("::google::protobuf::internal::AuxillaryParseTableField(),\n");
+ int last_field_number = 1;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = ordered_fields[i];
+
+ GOOGLE_CHECK_GE(field->number(), last_field_number);
+ for (; last_field_number < field->number(); last_field_number++) {
+ printer->Print("::google::protobuf::internal::AuxillaryParseTableField(),\n");
+ }
+
+ std::map<string, string> vars;
+ SetCommonFieldVariables(field, &vars, options_);
+
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_ENUM:
+ vars["type"] = ClassName(field->enum_type(), true);
+ printer->Print(
+ vars,
+ "{::google::protobuf::internal::AuxillaryParseTableField::enum_aux{"
+ "$type$_IsValid}},\n");
+ last_field_number++;
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE: {
+ if (field->is_map()) {
+ vars["classname"] = QualifiedClassName(field->message_type());
+ printer->Print(vars,
+ "{::google::protobuf::internal::AuxillaryParseTableField::map_"
+ "aux{&::google::protobuf::internal::ParseMap<$classname$>}},\n");
+ last_field_number++;
+ break;
+ } else {
+ vars["classname"] = ClassName(field->message_type(), false);
+ }
+ vars["ns"] = Namespace(field->message_type());
+ vars["type"] = FieldMessageTypeName(field);
+ vars["file_namespace"] =
+ FileLevelNamespace(field->message_type());
+
+ printer->Print(
+ vars,
+ "{::google::protobuf::internal::AuxillaryParseTableField::message_aux{\n"
+ " &$ns$::_$classname$_default_instance_}},\n");
+ last_field_number++;
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_STRING:
+ switch (EffectiveStringCType(field)) {
+ case FieldOptions::STRING:
+ vars["default"] =
+ field->default_value_string().empty()
+ ? "&::google::protobuf::internal::fixed_address_empty_string"
+ : "&" + Namespace(field) + " ::" + classname_ +
+ "::" + MakeDefaultName(field);
+ break;
+ case FieldOptions::CORD:
+ case FieldOptions::STRING_PIECE:
+ vars["default"] =
+ "\"" + CEscape(field->default_value_string()) + "\"";
+ break;
+ }
+ vars["full_name"] = field->full_name();
+ printer->Print(vars,
+ "{::google::protobuf::internal::AuxillaryParseTableField::string_aux{\n"
+ " $default$,\n"
+ " \"$full_name$\"\n"
+ "}},\n");
+ last_field_number++;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return last_field_number;
+}
+
std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) return std::make_pair(0, 0);
std::map<string, string> variables;
- variables["classname"] = classname_;
+ string full_classname = QualifiedClassName(descriptor_);
+ variables["classname"] = full_classname;
- if (HasFieldPresence(descriptor_->file())) {
+ if (HasFieldPresence(descriptor_->file()) || IsMapEntryMessage(descriptor_)) {
printer->Print(
variables,
- "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_),\n");
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
+ "_has_bits_),\n");
} else {
printer->Print("~0u, // no _has_bits_\n");
}
@@ -1775,48 +2093,62 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
if (descriptor_->extension_range_count() > 0) {
printer->Print(
variables,
- "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _extensions_),\n");
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
+ "_extensions_),\n");
} else {
printer->Print("~0u, // no _extensions_\n");
}
if (descriptor_->oneof_decl_count() > 0) {
printer->Print(variables,
- "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
- "_oneof_case_[0]),\n");
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+ "$classname$, _oneof_case_[0]),\n");
} else {
printer->Print("~0u, // no _oneof_case_\n");
}
-
- const int kNumGenericOffsets = 4; // the number of fixed offsets above
+ if (num_weak_fields_ > 0) {
+ printer->Print(variables,
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$,"
+ " _weak_field_map_),\n");
+ } else {
+ printer->Print("~0u, // no _weak_field_map_\n");
+ }
+ const int kNumGenericOffsets = 5; // the number of fixed offsets above
const size_t offsets = kNumGenericOffsets +
descriptor_->field_count() +
descriptor_->oneof_decl_count();
size_t entries = offsets;
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
- if (field->containing_oneof()) {
- printer->Print(
- "PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET("
- "(&_$classname$_default_instance_), $name$_),\n",
- "classname", classname_, "name", FieldName(field));
+ if (field->containing_oneof() || field->options().weak()) {
+ printer->Print("offsetof($classname$DefaultTypeInternal, $name$_)",
+ "classname", full_classname, "name", FieldName(field));
} else {
printer->Print(
- "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
- "$name$_),\n",
- "classname", classname_,
- "name", FieldName(field));
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_)",
+ "classname", full_classname, "name", FieldName(field));
}
+
+ uint32 tag = field_generators_.get(field).CalculateFieldTag();
+ if (tag != 0) {
+ printer->Print(" | $tag$", "tag", SimpleItoa(tag));
+ }
+
+ printer->Print(",\n");
}
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
printer->Print(
- "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_),\n",
- "classname", classname_,
- "name", oneof->name());
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_),\n",
+ "classname", full_classname, "name", oneof->name());
}
- if (HasFieldPresence(descriptor_->file())) {
+ if (IsMapEntryMessage(descriptor_)) {
+ entries += 2;
+ printer->Print(
+ "0,\n"
+ "1,\n");
+ } else if (HasFieldPresence(descriptor_->file())) {
entries += has_bit_indices_.size();
for (int i = 0; i < has_bit_indices_.size(); i++) {
const string index = has_bit_indices_[i] >= 0 ?
@@ -1835,28 +2167,6 @@ GenerateSharedConstructorCode(io::Printer* printer) {
"classname", classname_);
printer->Indent();
- bool need_to_clear_cached_size = true;
- // We reproduce the logic used for laying out _cached_sized_ in the class
- // definition, as to initialize it in-order.
- if (HasFieldPresence(descriptor_->file()) &&
- (HasBitsSize() % 8) != 0) {
- printer->Print("_cached_size_ = 0;\n");
- need_to_clear_cached_size = false;
- }
-
- // TODO(gerbens) Clean this hack, and why do i need a reference to a pointer??
- for (int i = 0; i < descriptor_->nested_type_count(); i++) {
- if (HasDescriptorMethods(descriptor_->file(), options_) &&
- IsMapEntryMessage(descriptor_->nested_type(i))) {
- printer->Print(
- "const ::google::protobuf::Descriptor*& $type$_descriptor = "
- "$file_namespace$::file_level_metadata[$index$].descriptor;\n",
- "type", ClassName(descriptor_->nested_type(i), false), "index",
- SimpleItoa(nested_generators_[i]->index_in_metadata_),
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
- }
- }
-
std::vector<bool> processed(optimized_order_.size(), false);
GenerateConstructorBody(printer, processed, false);
@@ -1866,10 +2176,6 @@ GenerateSharedConstructorCode(io::Printer* printer) {
"oneof_name", descriptor_->oneof_decl(i)->name());
}
- if (need_to_clear_cached_size) {
- printer->Print("_cached_size_ = 0;\n");
- }
-
printer->Outdent();
printer->Print("}\n\n");
}
@@ -1881,15 +2187,9 @@ GenerateSharedDestructorCode(io::Printer* printer) {
"classname", classname_);
printer->Indent();
if (SupportsArenas(descriptor_)) {
- // Do nothing when the message is allocated in an arena.
printer->Print(
- "::google::protobuf::Arena* arena = GetArenaNoVirtual();\n"
- "if (arena != NULL) {\n"
- " return;\n"
- "}\n"
- "\n");
+ "GOOGLE_DCHECK(GetArenaNoVirtual() == NULL);\n");
}
-
// Write the destructors for each field except oneof members.
// optimized_order_ does not contain oneof fields.
for (int i = 0; i < optimized_order_.size(); i++) {
@@ -1906,6 +2206,9 @@ GenerateSharedDestructorCode(io::Printer* printer) {
"oneof_name", descriptor_->oneof_decl(i)->name());
}
+ if (num_weak_fields_) {
+ printer->Print("_weak_field_map_.ClearAll();\n");
+ }
printer->Outdent();
printer->Print(
"}\n"
@@ -1956,6 +2259,12 @@ GenerateArenaDestructorCode(io::Printer* printer) {
}
}
}
+ if (num_weak_fields_) {
+ // _this is the object being destructed (we are inside a static method
+ // here).
+ printer->Print("_this->_weak_field_map_.ClearAll();\n");
+ need_registration = true;
+ }
printer->Outdent();
printer->Print(
@@ -1971,7 +2280,7 @@ GenerateArenaDestructorCode(io::Printer* printer) {
"classname", classname_);
} else {
printer->Print(
- "void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n"
+ "void $classname$::RegisterArenaDtor(::google::protobuf::Arena*) {\n"
"}\n",
"classname", classname_);
}
@@ -2005,12 +2314,13 @@ void MessageGenerator::GenerateConstructorBody(io::Printer* printer,
if (copy_constructor) {
pod_template =
"::memcpy(&$first$_, &from.$first$_,\n"
- " reinterpret_cast<char*>(&$last$_) -\n"
- " reinterpret_cast<char*>(&$first$_) + sizeof($last$_));\n";
+ " static_cast<size_t>(reinterpret_cast<char*>(&$last$_) -\n"
+ " reinterpret_cast<char*>(&$first$_)) + sizeof($last$_));\n";
} else {
pod_template =
- "::memset(&$first$_, 0, reinterpret_cast<char*>(&$last$_) -\n"
- " reinterpret_cast<char*>(&$first$_) + sizeof($last$_));\n";
+ "::memset(&$first$_, 0, static_cast<size_t>(\n"
+ " reinterpret_cast<char*>(&$last$_) -\n"
+ " reinterpret_cast<char*>(&$first$_)) + sizeof($last$_));\n";
}
for (int i = 0; i < optimized_order_.size(); ++i) {
@@ -2049,12 +2359,7 @@ void MessageGenerator::GenerateConstructorBody(io::Printer* printer,
void MessageGenerator::
GenerateStructors(io::Printer* printer) {
string superclass;
- if (use_dependent_base_) {
- superclass =
- DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">";
- } else {
- superclass = SuperClassName(descriptor_, options_);
- }
+ superclass = SuperClassName(descriptor_, options_);
string initializer_with_arena = superclass + "()";
if (descriptor_->extension_range_count() > 0) {
@@ -2077,161 +2382,152 @@ GenerateStructors(io::Printer* printer) {
if (IsAnyMessage(descriptor_)) {
initializer_with_arena += ",\n _any_metadata_(&type_url_, &value_)";
}
+ if (num_weak_fields_ > 0) {
+ initializer_with_arena += ", _weak_field_map_(arena)";
+ }
- string initializer_null;
- initializer_null = ", _internal_metadata_(NULL)";
+ string initializer_null = superclass + "(), _internal_metadata_(NULL)";
if (IsAnyMessage(descriptor_)) {
initializer_null += ", _any_metadata_(&type_url_, &value_)";
}
+ if (num_weak_fields_ > 0) {
+ initializer_null += ", _weak_field_map_(nullptr)";
+ }
printer->Print(
"$classname$::$classname$()\n"
- " : $superclass$()$initializer$ {\n"
- " if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {\n"
- " $file_namespace$::InitDefaults();\n"
- " }\n"
+ " : $initializer$ {\n"
+ " ::google::protobuf::internal::InitSCC(\n"
+ " &$file_namespace$::scc_info_$scc_name$.base);\n"
" SharedCtor();\n"
" // @@protoc_insertion_point(constructor:$full_name$)\n"
"}\n",
- "classname", classname_, "superclass", superclass, "full_name",
- descriptor_->full_name(), "initializer", initializer_null,
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+ "classname", classname_, "full_name", descriptor_->full_name(),
+ "scc_name", scc_name_, "initializer", initializer_null, "file_namespace",
+ FileLevelNamespace(descriptor_));
if (SupportsArenas(descriptor_)) {
printer->Print(
"$classname$::$classname$(::google::protobuf::Arena* arena)\n"
" : $initializer$ {\n"
- // When arenas are used it's safe to assume we have finished
- // static init time (protos with arenas are unsafe during static init)
- "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n"
- " $file_namespace$::InitDefaults();\n"
- "#endif // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n"
+ " "
+ "::google::protobuf::internal::InitSCC(&$file_namespace$::scc_info_$scc_name$."
+ "base);\n"
" SharedCtor();\n"
" RegisterArenaDtor(arena);\n"
" // @@protoc_insertion_point(arena_constructor:$full_name$)\n"
"}\n",
"initializer", initializer_with_arena, "classname", classname_,
"superclass", superclass, "full_name", descriptor_->full_name(),
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+ "scc_name", scc_name_, "file_namespace",
+ FileLevelNamespace(descriptor_));
}
// Generate the copy constructor.
- printer->Print(
- "$classname$::$classname$(const $classname$& from)\n"
- " : $superclass$()",
- "classname", classname_,
- "superclass", superclass,
- "full_name", descriptor_->full_name());
- printer->Indent();
- printer->Indent();
- printer->Indent();
-
- printer->Print(
- ",\n_internal_metadata_(NULL)");
-
- if (HasFieldPresence(descriptor_->file())) {
- printer->Print(",\n_has_bits_(from._has_bits_)");
- }
-
- bool need_to_emit_cached_size = true;
- const string cached_size_decl = ",\n_cached_size_(0)";
- // We reproduce the logic used for laying out _cached_sized_ in the class
- // definition, as to initialize it in-order.
- if (HasFieldPresence(descriptor_->file()) &&
- (HasBitsSize() % 8) != 0) {
- printer->Print(cached_size_decl.c_str());
- need_to_emit_cached_size = false;
- }
+ if (UsingImplicitWeakFields(descriptor_->file(), options_)) {
+ // If we are in lite mode and using implicit weak fields, we generate a
+ // one-liner copy constructor that delegates to MergeFrom. This saves some
+ // code size and also cuts down on the complexity of implicit weak fields.
+ // We might eventually want to do this for all lite protos.
+ printer->Print(
+ "$classname$::$classname$(const $classname$& from)\n"
+ " : $classname$() {\n"
+ " MergeFrom(from);\n"
+ "}\n",
+ "classname", classname_);
+ } else {
+ printer->Print(
+ "$classname$::$classname$(const $classname$& from)\n"
+ " : $superclass$()",
+ "classname", classname_,
+ "superclass", superclass,
+ "full_name", descriptor_->full_name());
+ printer->Indent();
+ printer->Indent();
+ printer->Indent();
- std::vector<bool> processed(optimized_order_.size(), false);
- for (int i = 0; i < optimized_order_.size(); ++i) {
- const FieldDescriptor* field = optimized_order_[i];
+ printer->Print(
+ ",\n_internal_metadata_(NULL)");
- if (!(field->is_repeated() && !(field->is_map()))
- ) {
- continue;
+ if (HasFieldPresence(descriptor_->file())) {
+ printer->Print(",\n_has_bits_(from._has_bits_)");
}
- processed[i] = true;
- printer->Print(",\n$name$_(from.$name$_)",
- "name", FieldName(field));
- }
+ std::vector<bool> processed(optimized_order_.size(), false);
+ for (int i = 0; i < optimized_order_.size(); ++i) {
+ const FieldDescriptor* field = optimized_order_[i];
- if (need_to_emit_cached_size) {
- printer->Print(cached_size_decl.c_str());
- need_to_emit_cached_size = false;
- }
+ if (!(field->is_repeated() && !(field->is_map()))
+ ) {
+ continue;
+ }
- if (IsAnyMessage(descriptor_)) {
- printer->Print(",\n_any_metadata_(&type_url_, &value_)");
- }
+ processed[i] = true;
+ printer->Print(",\n$name$_(from.$name$_)",
+ "name", FieldName(field));
+ }
- printer->Outdent();
- printer->Outdent();
- printer->Print(" {\n");
+ if (IsAnyMessage(descriptor_)) {
+ printer->Print(",\n_any_metadata_(&type_url_, &value_)");
+ }
+ if (num_weak_fields_ > 0) {
+ printer->Print(",\n_weak_field_map_(from._weak_field_map_)");
+ }
- printer->Print(
- "_internal_metadata_.MergeFrom(from._internal_metadata_);\n");
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(" {\n");
- if (descriptor_->extension_range_count() > 0) {
- printer->Print("_extensions_.MergeFrom(from._extensions_);\n");
- }
+ printer->Print(
+ "_internal_metadata_.MergeFrom(from._internal_metadata_);\n");
- // TODO(gerbens) Clean this hack, and why do i need a reference to a pointer??
- for (int i = 0; i < descriptor_->nested_type_count(); i++) {
- if (HasDescriptorMethods(descriptor_->file(), options_) &&
- IsMapEntryMessage(descriptor_->nested_type(i))) {
- printer->Print(
- "const ::google::protobuf::Descriptor*& $type$_descriptor = "
- "$file_namespace$::file_level_metadata[$index$].descriptor;\n",
- "type", ClassName(descriptor_->nested_type(i), false), "index",
- SimpleItoa(nested_generators_[i]->index_in_metadata_),
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print("_extensions_.MergeFrom(from._extensions_);\n");
}
- }
- GenerateConstructorBody(printer, processed, true);
+ GenerateConstructorBody(printer, processed, true);
- // Copy oneof fields. Oneof field requires oneof case check.
- for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
- printer->Print(
- "clear_has_$oneofname$();\n"
- "switch (from.$oneofname$_case()) {\n",
- "oneofname", descriptor_->oneof_decl(i)->name());
- printer->Indent();
- for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
- const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ // Copy oneof fields. Oneof field requires oneof case check.
+ for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
printer->Print(
- "case k$field_name$: {\n",
- "field_name", UnderscoresToCamelCase(field->name(), true));
+ "clear_has_$oneofname$();\n"
+ "switch (from.$oneofname$_case()) {\n",
+ "oneofname", descriptor_->oneof_decl(i)->name());
printer->Indent();
- field_generators_.get(field).GenerateMergingCode(printer);
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+ printer->Print(
+ "case k$field_name$: {\n",
+ "field_name", UnderscoresToCamelCase(field->name(), true));
+ printer->Indent();
+ field_generators_.get(field).GenerateMergingCode(printer);
+ printer->Print(
+ "break;\n");
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+ }
printer->Print(
- "break;\n");
+ "case $cap_oneof_name$_NOT_SET: {\n"
+ " break;\n"
+ "}\n",
+ "oneof_index",
+ SimpleItoa(descriptor_->oneof_decl(i)->index()),
+ "cap_oneof_name",
+ ToUpper(descriptor_->oneof_decl(i)->name()));
printer->Outdent();
printer->Print(
"}\n");
}
- printer->Print(
- "case $cap_oneof_name$_NOT_SET: {\n"
- " break;\n"
- "}\n",
- "oneof_index",
- SimpleItoa(descriptor_->oneof_decl(i)->index()),
- "cap_oneof_name",
- ToUpper(descriptor_->oneof_decl(i)->name()));
+
printer->Outdent();
printer->Print(
- "}\n");
+ " // @@protoc_insertion_point(copy_constructor:$full_name$)\n"
+ "}\n"
+ "\n",
+ "full_name", descriptor_->full_name());
}
- printer->Outdent();
- printer->Print(
- " // @@protoc_insertion_point(copy_constructor:$full_name$)\n"
- "}\n"
- "\n",
- "full_name", descriptor_->full_name());
-
// Generate the shared constructor code.
GenerateSharedConstructorCode(printer);
@@ -2255,52 +2551,46 @@ GenerateStructors(io::Printer* printer) {
// Generate SetCachedSize.
printer->Print(
- "void $classname$::SetCachedSize(int size) const {\n"
- " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
- " _cached_size_ = size;\n"
- " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
- "}\n",
- "classname", classname_);
+ "void $classname$::SetCachedSize(int size) const {\n"
+ " _cached_size_.Set(size);\n"
+ "}\n",
+ "classname", classname_);
// Only generate this member if it's not disabled.
if (HasDescriptorMethods(descriptor_->file(), options_) &&
!descriptor_->options().no_standard_descriptor_accessor()) {
printer->Print(
"const ::google::protobuf::Descriptor* $classname$::descriptor() {\n"
- " $file_namespace$::protobuf_AssignDescriptorsOnce();\n"
- " return $file_namespace$::file_level_metadata[$index$].descriptor;\n"
+ " ::$file_namespace$::protobuf_AssignDescriptorsOnce();\n"
+ " return ::"
+ "$file_namespace$::file_level_metadata[kIndexInFileMessages]."
+ "descriptor;\n"
"}\n"
"\n",
- "index", SimpleItoa(index_in_metadata_), "classname", classname_,
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+ "classname", classname_, "file_namespace",
+ FileLevelNamespace(descriptor_));
}
printer->Print(
"const $classname$& $classname$::default_instance() {\n"
- " $file_namespace$::InitDefaults();\n"
+ " "
+ "::google::protobuf::internal::InitSCC(&$file_namespace$::scc_info_$scc_name$.base)"
+ ";\n"
" return *internal_default_instance();\n"
"}\n\n",
- "classname", classname_, "file_namespace",
- FileLevelNamespace(descriptor_->file()->name()));
+ "classname", classname_, "scc_name", scc_name_, "file_namespace",
+ FileLevelNamespace(descriptor_));
+}
- if (SupportsArenas(descriptor_)) {
- printer->Print(
- "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n"
- " return ::google::protobuf::Arena::CreateMessage<$classname$>(arena);\n"
- "}\n",
- "classname", classname_);
- } else {
- printer->Print(
- "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n"
- " $classname$* n = new $classname$;\n"
- " if (arena != NULL) {\n"
- " arena->Own(n);\n"
- " }\n"
- " return n;\n"
+void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) {
+ printer->Print(
+ "template<> "
+ "GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE "
+ "$classname$* Arena::CreateMaybeMessage< $classname$ >(Arena* arena) {\n"
+ " return Arena::$create_func$Internal< $classname$ >(arena);\n"
"}\n",
- "classname", classname_);
- }
-
+ "classname", QualifiedClassName(descriptor_),
+ "create_func", MessageCreateFunction(descriptor_));
}
// Return the number of bits set in n, a non-negative integer.
@@ -2313,188 +2603,214 @@ static int popcnt(uint32 n) {
return result;
}
+bool MessageGenerator::MaybeGenerateOptionalFieldCondition(
+ io::Printer* printer, const FieldDescriptor* field,
+ int expected_has_bits_index) {
+ int has_bit_index = has_bit_indices_[field->index()];
+ if (!field->options().weak() &&
+ expected_has_bits_index == has_bit_index / 32) {
+ const string mask =
+ StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8));
+ printer->Print(
+ "if (cached_has_bits & 0x$mask$u) {\n",
+ "mask", mask);
+ return true;
+ }
+ return false;
+}
+
void MessageGenerator::
GenerateClear(io::Printer* printer) {
+ // Performance tuning parameters
+ const int kMaxUnconditionalPrimitiveBytesClear = 4;
+
printer->Print(
"void $classname$::Clear() {\n"
"// @@protoc_insertion_point(message_clear_start:$full_name$)\n",
"classname", classname_, "full_name", descriptor_->full_name());
printer->Indent();
+ printer->Print(
+ // TODO(jwb): It would be better to avoid emitting this if it is not used,
+ // rather than emitting a workaround for the resulting warning.
+ "::google::protobuf::uint32 cached_has_bits = 0;\n"
+ "// Prevent compiler warnings about cached_has_bits being unused\n"
+ "(void) cached_has_bits;\n\n");
+
+ int cached_has_bit_index = -1;
+
// Step 1: Extensions
if (descriptor_->extension_range_count() > 0) {
printer->Print("_extensions_.Clear();\n");
}
- int last_i = -1;
- for (int i = 0; i < optimized_order_.size(); ) {
- // Detect infinite loops.
- GOOGLE_CHECK_NE(i, last_i);
- last_i = i;
-
- // Step 2: Repeated fields don't use _has_bits_; emit code to clear them
- // here.
- for (; i < optimized_order_.size(); i++) {
- const FieldDescriptor* field = optimized_order_[i];
- const FieldGenerator& generator = field_generators_.get(field);
-
- if (!field->is_repeated()) {
- break;
- }
+ int unconditional_budget = kMaxUnconditionalPrimitiveBytesClear;
+ for (int i = 0; i < optimized_order_.size(); i++) {
+ const FieldDescriptor* field = optimized_order_[i];
- if (use_dependent_base_ && IsFieldDependent(field)) {
- printer->Print("clear_$name$();\n", "name", FieldName(field));
- } else {
- generator.GenerateMessageClearingCode(printer);
- }
+ if (!CanInitializeByZeroing(field)) {
+ continue;
}
- // Step 3: Greedily seek runs of fields that can be cleared by
- // memset-to-0.
- int last_chunk = -1;
- int last_chunk_start = -1;
- int last_chunk_end = -1;
- uint32 last_chunk_mask = 0;
+ unconditional_budget -= EstimateAlignmentSize(field);
+ }
- int memset_run_start = -1;
- int memset_run_end = -1;
- for (; i < optimized_order_.size(); i++) {
- const FieldDescriptor* field = optimized_order_[i];
+ std::vector<std::vector<const FieldDescriptor*> > chunks_frag = CollectFields(
+ optimized_order_,
+ MatchRepeatedAndHasByteAndZeroInits(
+ &has_bit_indices_, HasFieldPresence(descriptor_->file())));
- if (!CanInitializeByZeroing(field)) {
- break;
+ // Merge next non-zero initializable chunk if it has the same has_byte index
+ // and not meeting unconditional clear condition.
+ std::vector<std::vector<const FieldDescriptor*> > chunks;
+ if (!HasFieldPresence(descriptor_->file())) {
+ // Don't bother with merging without has_bit field.
+ chunks = chunks_frag;
+ } else {
+ // Note that only the next chunk is considered for merging.
+ for (int i = 0; i < chunks_frag.size(); i++) {
+ chunks.push_back(chunks_frag[i]);
+ const FieldDescriptor* field = chunks_frag[i].front();
+ const FieldDescriptor* next_field =
+ (i + 1) < chunks_frag.size() ? chunks_frag[i + 1].front() : nullptr;
+ if (CanInitializeByZeroing(field) &&
+ (chunks_frag[i].size() == 1 || unconditional_budget < 0) &&
+ next_field != nullptr &&
+ has_bit_indices_[field->index()] / 8 ==
+ has_bit_indices_[next_field->index()] / 8) {
+ GOOGLE_CHECK(!CanInitializeByZeroing(next_field));
+ // Insert next chunk to the current one and skip next chunk.
+ chunks.back().insert(chunks.back().end(), chunks_frag[i + 1].begin(),
+ chunks_frag[i + 1].end());
+ i++;
}
+ }
+ }
- // "index" defines where in the _has_bits_ the field appears.
- // "i" is our loop counter within optimized_order_.
- int index = HasFieldPresence(descriptor_->file()) ?
- has_bit_indices_[field->index()] : 0;
- int chunk = index / 8;
+ for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) {
+ std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index];
+ GOOGLE_CHECK(!chunk.empty());
- if (last_chunk == -1) {
- last_chunk = chunk;
- last_chunk_start = i;
- } else if (chunk != last_chunk) {
- // Emit the fields for this chunk so far.
- break;
- }
+ // Step 2: Repeated fields don't use _has_bits_; emit code to clear them
+ // here.
+ if (chunk.front()->is_repeated()) {
+ for (int i = 0; i < chunk.size(); i++) {
+ const FieldDescriptor* field = chunk[i];
+ const FieldGenerator& generator = field_generators_.get(field);
- if (memset_run_start == -1) {
- memset_run_start = i;
+ generator.GenerateMessageClearingCode(printer);
}
-
- memset_run_end = i;
- last_chunk_end = i;
- last_chunk_mask |= static_cast<uint32>(1) << (index % 32);
+ continue;
}
- // Step 4: Non-repeated, non-zero initializable fields.
- for (; i < optimized_order_.size(); i++) {
- const FieldDescriptor* field = optimized_order_[i];
- if (field->is_repeated() || CanInitializeByZeroing(field)) {
- break;
- }
-
- // "index" defines where in the _has_bits_ the field appears.
- // "i" is our loop counter within optimized_order_.
- int index = HasFieldPresence(descriptor_->file()) ?
- has_bit_indices_[field->index()] : 0;
- int chunk = index / 8;
+ // Step 3: Non-repeated fields that can be cleared by memset-to-0, then
+ // non-repeated, non-zero initializable fields.
+ int last_chunk = HasFieldPresence(descriptor_->file())
+ ? has_bit_indices_[chunk.front()->index()] / 8
+ : 0;
+ int last_chunk_start = 0;
+ int memset_run_start = -1;
+ int memset_run_end = -1;
- if (last_chunk == -1) {
- last_chunk = chunk;
- last_chunk_start = i;
- } else if (chunk != last_chunk) {
- // Emit the fields for this chunk so far.
- break;
+ for (int i = 0; i < chunk.size(); i++) {
+ const FieldDescriptor* field = chunk[i];
+ if (CanInitializeByZeroing(field)) {
+ if (memset_run_start == -1) {
+ memset_run_start = i;
+ }
+ memset_run_end = i;
}
-
- last_chunk_end = i;
- last_chunk_mask |= static_cast<uint32>(1) << (index % 32);
}
- if (last_chunk != -1) {
- GOOGLE_DCHECK_NE(-1, last_chunk_start);
- GOOGLE_DCHECK_NE(-1, last_chunk_end);
- GOOGLE_DCHECK_NE(0, last_chunk_mask);
+ const bool have_outer_if =
+ HasFieldPresence(descriptor_->file()) && chunk.size() > 1 &&
+ (memset_run_end != chunk.size() - 1 || unconditional_budget < 0);
+ if (have_outer_if) {
+ uint32 last_chunk_mask = GenChunkMask(chunk, has_bit_indices_);
const int count = popcnt(last_chunk_mask);
- const bool have_outer_if = HasFieldPresence(descriptor_->file()) &&
- (last_chunk_start != last_chunk_end);
- if (have_outer_if) {
- // Check (up to) 8 has_bits at a time if we have more than one field in
- // this chunk. Due to field layout ordering, we may check
- // _has_bits_[last_chunk * 8 / 32] multiple times.
- GOOGLE_DCHECK_LE(2, count);
- GOOGLE_DCHECK_GE(8, count);
+ // Check (up to) 8 has_bits at a time if we have more than one field in
+ // this chunk. Due to field layout ordering, we may check
+ // _has_bits_[last_chunk * 8 / 32] multiple times.
+ GOOGLE_DCHECK_LE(2, count);
+ GOOGLE_DCHECK_GE(8, count);
- printer->Print(
- "if (_has_bits_[$index$ / 32] & $mask$u) {\n",
- "index", SimpleItoa(last_chunk * 8),
- "mask", SimpleItoa(last_chunk_mask));
- printer->Indent();
+ if (cached_has_bit_index != last_chunk / 4) {
+ cached_has_bit_index = last_chunk / 4;
+ printer->Print("cached_has_bits = _has_bits_[$idx$];\n", "idx",
+ SimpleItoa(cached_has_bit_index));
}
+ printer->Print("if (cached_has_bits & $mask$u) {\n", "mask",
+ SimpleItoa(last_chunk_mask));
+ printer->Indent();
+ }
- if (memset_run_start != -1) {
- if (memset_run_start == memset_run_end) {
- // For clarity, do not memset a single field.
- const FieldGenerator& generator =
- field_generators_.get(optimized_order_[memset_run_start]);
- generator.GenerateMessageClearingCode(printer);
- } else {
- const string first_field_name =
- FieldName(optimized_order_[memset_run_start]);
- const string last_field_name =
- FieldName(optimized_order_[memset_run_end]);
-
- printer->Print(
- "::memset(&$first$_, 0, reinterpret_cast<char*>(&$last$_) -\n"
- " reinterpret_cast<char*>(&$first$_) + sizeof($last$_));\n",
- "first", first_field_name,
- "last", last_field_name);
- }
+ if (memset_run_start != -1) {
+ if (memset_run_start == memset_run_end) {
+ // For clarity, do not memset a single field.
+ const FieldGenerator& generator =
+ field_generators_.get(chunk[memset_run_start]);
+ generator.GenerateMessageClearingCode(printer);
+ } else {
+ const string first_field_name = FieldName(chunk[memset_run_start]);
+ const string last_field_name = FieldName(chunk[memset_run_end]);
- // Advance last_chunk_start to skip over the fields we zeroed/memset.
- last_chunk_start = memset_run_end + 1;
+ printer->Print(
+ "::memset(&$first$_, 0, static_cast<size_t>(\n"
+ " reinterpret_cast<char*>(&$last$_) -\n"
+ " reinterpret_cast<char*>(&$first$_)) + sizeof($last$_));\n",
+ "first", first_field_name, "last", last_field_name);
}
- // Go back and emit clears for each of the fields we processed.
- for (int j = last_chunk_start; j <= last_chunk_end; j++) {
- const FieldDescriptor* field = optimized_order_[j];
- const string fieldname = FieldName(field);
- const FieldGenerator& generator = field_generators_.get(field);
+ // Advance last_chunk_start to skip over the fields we zeroed/memset.
+ last_chunk_start = memset_run_end + 1;
+ }
+
+ // Go back and emit clears for each of the fields we processed.
+ for (int j = last_chunk_start; j < chunk.size(); j++) {
+ const FieldDescriptor* field = chunk[j];
+ const string fieldname = FieldName(field);
+ const FieldGenerator& generator = field_generators_.get(field);
- // It's faster to just overwrite primitive types, but we should only
- // clear strings and messages if they were set.
- //
- // TODO(kenton): Let the CppFieldGenerator decide this somehow.
- bool should_check_bit =
+ // It's faster to just overwrite primitive types, but we should only
+ // clear strings and messages if they were set.
+ //
+ // TODO(kenton): Let the CppFieldGenerator decide this somehow.
+ bool should_check_bit =
field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
field->cpp_type() == FieldDescriptor::CPPTYPE_STRING;
- bool have_enclosing_if = false;
- if (should_check_bit &&
- // If no field presence, then always clear strings/messages as well.
- HasFieldPresence(descriptor_->file())) {
- printer->Print("if (has_$name$()) {\n", "name", fieldname);
- printer->Indent();
- have_enclosing_if = true;
+ bool have_enclosing_if = false;
+ if (should_check_bit &&
+ // If no field presence, then always clear strings/messages as well.
+ HasFieldPresence(descriptor_->file())) {
+ if (!field->options().weak() &&
+ cached_has_bit_index != (has_bit_indices_[field->index()] / 32)) {
+ cached_has_bit_index = (has_bit_indices_[field->index()] / 32);
+ printer->Print("cached_has_bits = _has_bits_[$new_index$];\n",
+ "new_index", SimpleItoa(cached_has_bit_index));
}
-
- generator.GenerateMessageClearingCode(printer);
-
- if (have_enclosing_if) {
- printer->Outdent();
- printer->Print("}\n");
+ if (!MaybeGenerateOptionalFieldCondition(printer, field,
+ cached_has_bit_index)) {
+ printer->Print("if (has_$name$()) {\n", "name", fieldname);
}
+ printer->Indent();
+ have_enclosing_if = true;
}
- if (have_outer_if) {
+ generator.GenerateMessageClearingCode(printer);
+
+ if (have_enclosing_if) {
printer->Outdent();
printer->Print("}\n");
}
}
+
+ if (have_outer_if) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
}
// Step 4: Unions.
@@ -2504,14 +2820,16 @@ GenerateClear(io::Printer* printer) {
"oneof_name", descriptor_->oneof_decl(i)->name());
}
+ if (num_weak_fields_) {
+ printer->Print("_weak_field_map_.ClearAll();\n");
+ }
+
if (HasFieldPresence(descriptor_->file())) {
// Step 5: Everything else.
printer->Print("_has_bits_.Clear();\n");
}
- if (PreserveUnknownFields(descriptor_)) {
- printer->Print("_internal_metadata_.Clear();\n");
- }
+ printer->Print("_internal_metadata_.Clear();\n");
printer->Outdent();
printer->Print("}\n");
@@ -2615,6 +2933,7 @@ GenerateSwap(io::Printer* printer) {
printer->Print("void $classname$::InternalSwap($classname$* other) {\n",
"classname", classname_);
printer->Indent();
+ printer->Print("using std::swap;\n");
if (HasGeneratedMethods(descriptor_->file(), options_)) {
for (int i = 0; i < optimized_order_.size(); i++) {
@@ -2626,27 +2945,28 @@ GenerateSwap(io::Printer* printer) {
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
printer->Print(
- "std::swap($oneof_name$_, other->$oneof_name$_);\n"
- "std::swap(_oneof_case_[$i$], other->_oneof_case_[$i$]);\n",
+ "swap($oneof_name$_, other->$oneof_name$_);\n"
+ "swap(_oneof_case_[$i$], other->_oneof_case_[$i$]);\n",
"oneof_name", descriptor_->oneof_decl(i)->name(),
"i", SimpleItoa(i));
}
if (HasFieldPresence(descriptor_->file())) {
for (int i = 0; i < HasBitsSize() / 4; ++i) {
- printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n",
+ printer->Print("swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n",
"i", SimpleItoa(i));
}
}
- if (PreserveUnknownFields(descriptor_)) {
- printer->Print("_internal_metadata_.Swap(&other->_internal_metadata_);\n");
- }
+ printer->Print("_internal_metadata_.Swap(&other->_internal_metadata_);\n");
- printer->Print("std::swap(_cached_size_, other->_cached_size_);\n");
if (descriptor_->extension_range_count() > 0) {
printer->Print("_extensions_.Swap(&other->_extensions_);\n");
}
+ if (num_weak_fields_) {
+ printer->Print(
+ "_weak_field_map_.UnsafeArenaSwap(&other->_weak_field_map_);\n");
+ }
} else {
printer->Print("GetReflection()->Swap(this, other);");
}
@@ -2714,7 +3034,14 @@ GenerateMergeFrom(io::Printer* printer) {
}
printer->Print(
- "_internal_metadata_.MergeFrom(from._internal_metadata_);\n");
+ "_internal_metadata_.MergeFrom(from._internal_metadata_);\n"
+ "::google::protobuf::uint32 cached_has_bits = 0;\n"
+ "(void) cached_has_bits;\n\n");
+
+ // cached_has_bit_index maintains that:
+ // cached_has_bits = from._has_bits_[cached_has_bit_index]
+ // for cached_has_bit_index >= 0
+ int cached_has_bit_index = -1;
int last_i = -1;
for (int i = 0; i < optimized_order_.size(); ) {
@@ -2734,7 +3061,7 @@ GenerateMergeFrom(io::Printer* printer) {
generator.GenerateMergingCode(printer);
}
- // Merge Optional and Required fields (after a _has_bit check).
+ // Merge Optional and Required fields (after a _has_bit_ check).
int last_chunk = -1;
int last_chunk_start = -1;
int last_chunk_end = -1;
@@ -2779,23 +3106,43 @@ GenerateMergeFrom(io::Printer* printer) {
GOOGLE_DCHECK_LE(2, count);
GOOGLE_DCHECK_GE(8, count);
+ if (cached_has_bit_index != last_chunk / 4) {
+ int new_index = last_chunk / 4;
+ printer->Print("cached_has_bits = from._has_bits_[$new_index$];\n",
+ "new_index", SimpleItoa(new_index));
+ cached_has_bit_index = new_index;
+ }
+
printer->Print(
- "if (from._has_bits_[$index$ / 32] & $mask$u) {\n",
- "index", SimpleItoa(last_chunk * 8),
+ "if (cached_has_bits & $mask$u) {\n",
"mask", SimpleItoa(last_chunk_mask));
printer->Indent();
}
// Go back and emit clears for each of the fields we processed.
+ bool deferred_has_bit_changes = false;
for (int j = last_chunk_start; j <= last_chunk_end; j++) {
const FieldDescriptor* field = optimized_order_[j];
const FieldGenerator& generator = field_generators_.get(field);
bool have_enclosing_if = false;
if (HasFieldPresence(descriptor_->file())) {
- printer->Print(
- "if (from.has_$name$()) {\n",
- "name", FieldName(field));
+ // Attempt to use the state of cached_has_bits, if possible.
+ int has_bit_index = has_bit_indices_[field->index()];
+ if (!field->options().weak() &&
+ cached_has_bit_index == has_bit_index / 32) {
+ const string mask = StrCat(
+ strings::Hex(1u << (has_bit_index % 32),
+ strings::ZERO_PAD_8));
+
+ printer->Print(
+ "if (cached_has_bits & 0x$mask$u) {\n", "mask", mask);
+ } else {
+ printer->Print(
+ "if (from.has_$name$()) {\n",
+ "name", FieldName(field));
+ }
+
printer->Indent();
have_enclosing_if = true;
} else {
@@ -2805,7 +3152,17 @@ GenerateMergeFrom(io::Printer* printer) {
printer, "from.", field);
}
- generator.GenerateMergingCode(printer);
+ if (have_outer_if && IsPOD(field)) {
+ // GenerateCopyConstructorCode for enum and primitive scalar fields
+ // does not do _has_bits_ modifications. We defer _has_bits_
+ // manipulation until the end of the outer if.
+ //
+ // This can reduce the number of loads/stores by up to 7 per 8 fields.
+ deferred_has_bit_changes = true;
+ generator.GenerateCopyConstructorCode(printer);
+ } else {
+ generator.GenerateMergingCode(printer);
+ }
if (have_enclosing_if) {
printer->Outdent();
@@ -2814,6 +3171,14 @@ GenerateMergeFrom(io::Printer* printer) {
}
if (have_outer_if) {
+ if (deferred_has_bit_changes) {
+ // Flush the has bits for the primitives we deferred.
+ GOOGLE_CHECK_LE(0, cached_has_bit_index);
+ printer->Print(
+ "_has_bits_[$index$] |= cached_has_bits;\n",
+ "index", SimpleItoa(cached_has_bit_index));
+ }
+
printer->Outdent();
printer->Print("}\n");
}
@@ -2849,6 +3214,9 @@ GenerateMergeFrom(io::Printer* printer) {
printer->Print(
"}\n");
}
+ if (num_weak_fields_) {
+ printer->Print("_weak_field_map_.MergeFrom(from._weak_field_map_);\n");
+ }
printer->Outdent();
printer->Print("}\n");
@@ -2894,44 +3262,74 @@ GenerateCopyFrom(io::Printer* printer) {
void MessageGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) {
+ std::map<string, string> vars;
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
if (descriptor_->options().message_set_wire_format()) {
// Special-case MessageSet.
- printer->Print(
+ vars["classname"] = classname_;
+ printer->Print(vars,
"bool $classname$::MergePartialFromCodedStream(\n"
- " ::google::protobuf::io::CodedInputStream* input) {\n",
- "classname", classname_);
-
- printer->Print(
- " return _extensions_.ParseMessageSet(input, "
- "internal_default_instance(),\n"
- " mutable_unknown_fields());\n",
- // Vars.
- "classname", classname_);
-
- printer->Print(
+ " ::google::protobuf::io::CodedInputStream* input) {\n"
+ " return _extensions_.ParseMessageSet(input,\n"
+ " internal_default_instance(), $mutable_unknown_fields$);\n"
"}\n");
return;
}
+ std::vector<const FieldDescriptor*> ordered_fields =
+ SortFieldsByNumber(descriptor_);
printer->Print(
"bool $classname$::MergePartialFromCodedStream(\n"
- " ::google::protobuf::io::CodedInputStream* input) {\n"
- "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure\n"
- " ::google::protobuf::uint32 tag;\n",
+ " ::google::protobuf::io::CodedInputStream* input) {\n",
"classname", classname_);
- if (PreserveUnknownFields(descriptor_) &&
- !UseUnknownFieldSet(descriptor_->file(), options_)) {
- // Use LazyStringOutputString to avoid initializing unknown fields string
- // unless it is actually needed. For the same reason, disable eager refresh
- // on the CodedOutputStream.
- printer->Print(
- " ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n"
- " ::google::protobuf::NewPermanentCallback(&_internal_metadata_,\n"
- " &::google::protobuf::internal::InternalMetadataWithArenaLite::mutable_unknown_fields));\n"
- " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
- " &unknown_fields_string, false);\n",
- "classname", classname_);
+ if (table_driven_) {
+ printer->Indent();
+
+ const string lite = UseUnknownFieldSet(descriptor_->file(), options_) ?
+ "" : "Lite";
+
+ printer->Print(
+ "return ::google::protobuf::internal::MergePartialFromCodedStream$lite$(\n"
+ " this,\n"
+ " ::$file_namespace$::TableStruct::schema[\n"
+ " $classname$::kIndexInFileMessages],\n"
+ " input);\n",
+ "classname", classname_, "file_namespace",
+ FileLevelNamespace(descriptor_), "lite", lite);
+
+ printer->Outdent();
+
+ printer->Print("}\n");
+ return;
+ }
+
+ if (SupportsArenas(descriptor_)) {
+ for (int i = 0; i < ordered_fields.size(); i++) {
+ const FieldDescriptor* field = ordered_fields[i];
+ const FieldGenerator& field_generator = field_generators_.get(field);
+ if (field_generator.MergeFromCodedStreamNeedsArena()) {
+ printer->Print(
+ " ::google::protobuf::Arena* arena = GetArenaNoVirtual();\n");
+ break;
+ }
+ }
+ }
+
+ printer->Print(
+ "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto "
+ "failure\n"
+ " ::google::protobuf::uint32 tag;\n");
+
+ if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
+ printer->Print(
+ " ::google::protobuf::internal::LiteUnknownFieldSetter unknown_fields_setter(\n"
+ " &_internal_metadata_);\n"
+ " ::google::protobuf::io::StringOutputStream unknown_fields_output(\n"
+ " unknown_fields_setter.buffer());\n"
+ " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
+ " &unknown_fields_output, false);\n",
+ "classname", classname_);
}
printer->Print(
@@ -2942,10 +3340,12 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Print("for (;;) {\n");
printer->Indent();
- std::vector<const FieldDescriptor*> ordered_fields =
- SortFieldsByNumber(descriptor_);
- uint32 maxtag = descriptor_->field_count() == 0 ? 0 :
- WireFormat::MakeTag(ordered_fields[descriptor_->field_count() - 1]);
+ // To calculate the maximum tag to expect, we look at the highest-numbered
+ // field. We need to be prepared to handle more than one wire type if that
+ // field is a packable repeated field, so to simplify things we assume the
+ // highest possible wire type of 5.
+ uint32 maxtag =
+ ordered_fields.empty() ? 0 : ordered_fields.back()->number() * 8 + 5;
const int kCutoff0 = 127; // fits in 1-byte varint
const int kCutoff1 = (127 << 7) + 127; // fits in 2-byte varint
@@ -2963,6 +3363,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
break;
}
}
+
+ for (int i = 0; i < parent->extension_count(); i++) {
+ const FieldDescriptor* field = parent->extension(i);
+ if (field->type() == FieldDescriptor::TYPE_GROUP &&
+ field->message_type() == descriptor_) {
+ capture_last_tag = true;
+ break;
+ }
+ }
}
for (int i = 0; i < descriptor_->file()->extension_count(); i++) {
@@ -2974,14 +3383,13 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
}
}
- printer->Print("::std::pair< ::google::protobuf::uint32, bool> p = "
- "input->ReadTagWithCutoff$lasttag$($max$u);\n"
+ printer->Print("::std::pair<::google::protobuf::uint32, bool> p = "
+ "input->ReadTagWithCutoffNoLastTag($max$u);\n"
"tag = p.first;\n"
"if (!p.second) goto handle_unusual;\n",
"max", SimpleItoa(maxtag <= kCutoff0 ? kCutoff0 :
(maxtag <= kCutoff1 ? kCutoff1 :
- maxtag)),
- "lasttag", !capture_last_tag ? "NoLastTag" : "");
+ maxtag)));
if (descriptor_->field_count() > 0) {
// We don't even want to print the switch() if we have no fields because
@@ -3004,20 +3412,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Indent();
- // Find repeated messages and groups now, to simplify what follows.
- hash_set<int> fields_with_parse_loop;
for (int i = 0; i < ordered_fields.size(); i++) {
const FieldDescriptor* field = ordered_fields[i];
- if (field->is_repeated() &&
- (field->type() == FieldDescriptor::TYPE_MESSAGE ||
- field->type() == FieldDescriptor::TYPE_GROUP)) {
- fields_with_parse_loop.insert(i);
- }
- }
-
- for (int i = 0; i < ordered_fields.size(); i++) {
- const FieldDescriptor* field = ordered_fields[i];
- const bool loops = fields_with_parse_loop.count(i) > 0;
PrintFieldComment(printer, field);
@@ -3028,13 +3424,11 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
const FieldGenerator& field_generator = field_generators_.get(field);
// Emit code to parse the common, expected case.
- printer->Print("if (static_cast< ::google::protobuf::uint8>(tag) ==\n"
- " static_cast< ::google::protobuf::uint8>($commontag$u)) {\n",
- "commontag", SimpleItoa(WireFormat::MakeTag(field)));
-
- if (loops) {
- printer->Print(" DO_(input->IncrementRecursionDepth());\n");
- }
+ printer->Print(
+ "if (static_cast< ::google::protobuf::uint8>(tag) ==\n"
+ " static_cast< ::google::protobuf::uint8>($truncated$u /* $full$ & 0xFF */)) {\n",
+ "truncated", SimpleItoa(WireFormat::MakeTag(field) & 0xFF),
+ "full", SimpleItoa(WireFormat::MakeTag(field)));
printer->Indent();
if (field->is_packed()) {
@@ -3048,22 +3442,30 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
if (field->is_packed()) {
internal::WireFormatLite::WireType wiretype =
WireFormat::WireTypeForFieldType(field->type());
- printer->Print("} else if (static_cast< ::google::protobuf::uint8>(tag) ==\n"
- " static_cast< ::google::protobuf::uint8>($uncommontag$u)) {\n",
- "uncommontag", SimpleItoa(
- internal::WireFormatLite::MakeTag(
- field->number(), wiretype)));
+ const uint32 tag = internal::WireFormatLite::MakeTag(
+ field->number(), wiretype);
+ printer->Print(
+ "} else if (\n"
+ " static_cast< ::google::protobuf::uint8>(tag) ==\n"
+ " static_cast< ::google::protobuf::uint8>($truncated$u /* $full$ & 0xFF */)) {\n",
+ "truncated", SimpleItoa(tag & 0xFF),
+ "full", SimpleItoa(tag));
+
printer->Indent();
field_generator.GenerateMergeFromCodedStream(printer);
printer->Outdent();
} else if (field->is_packable() && !field->is_packed()) {
internal::WireFormatLite::WireType wiretype =
internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
- printer->Print("} else if (static_cast< ::google::protobuf::uint8>(tag) ==\n"
- " static_cast< ::google::protobuf::uint8>($uncommontag$u)) {\n",
- "uncommontag", SimpleItoa(
- internal::WireFormatLite::MakeTag(
- field->number(), wiretype)));
+ const uint32 tag = internal::WireFormatLite::MakeTag(
+ field->number(), wiretype);
+
+ printer->Print(
+ "} else if (\n"
+ " static_cast< ::google::protobuf::uint8>(tag) ==\n"
+ " static_cast< ::google::protobuf::uint8>($truncated$u /* $full$ & 0xFF */)) {\n",
+ "truncated", SimpleItoa(tag & 0xFF),
+ "full", SimpleItoa(tag));
printer->Indent();
field_generator.GenerateMergeFromCodedStreamWithPacking(printer);
printer->Outdent();
@@ -3074,19 +3476,12 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
" goto handle_unusual;\n"
"}\n");
- // For repeated messages/groups, we need to decrement recursion depth.
- if (loops) {
- printer->Print(
- "input->UnsafeDecrementRecursionDepth();\n");
- }
-
printer->Print(
"break;\n");
printer->Outdent();
printer->Print("}\n\n");
}
-
printer->Print("default: {\n");
printer->Indent();
}
@@ -3095,12 +3490,20 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Print("handle_unusual:\n");
printer->Indent();
// If tag is 0 or an end-group tag then this must be the end of the message.
- printer->Print(
- "if (tag == 0 ||\n"
- " ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n"
- " ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n"
- " goto success;\n"
- "}\n");
+ if (capture_last_tag) {
+ printer->Print(
+ "if (tag == 0 ||\n"
+ " ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n"
+ " ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n"
+ " input->SetLastTag(tag);\n"
+ " goto success;\n"
+ "}\n");
+ } else {
+ printer->Print(
+ "if (tag == 0) {\n"
+ " goto success;\n"
+ "}\n");
+ }
// Handle extension ranges.
if (descriptor_->extension_range_count() > 0) {
@@ -3128,23 +3531,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
}
}
printer->Print(") {\n");
- if (PreserveUnknownFields(descriptor_)) {
- if (UseUnknownFieldSet(descriptor_->file(), options_)) {
- printer->Print(
- " DO_(_extensions_.ParseField(tag, input, "
- "internal_default_instance(),\n"
- " mutable_unknown_fields()));\n");
- } else {
- printer->Print(
- " DO_(_extensions_.ParseField(tag, input, "
- "internal_default_instance(),\n"
- " &unknown_fields_stream));\n");
- }
+ if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+ printer->Print(vars,
+ " DO_(_extensions_.ParseField(tag, input,\n"
+ " internal_default_instance(),\n"
+ " $mutable_unknown_fields$));\n");
} else {
printer->Print(
- // With static initializers.
- " DO_(_extensions_.ParseField(tag, input, "
- "internal_default_instance());\n");
+ " DO_(_extensions_.ParseField(tag, input,\n"
+ " internal_default_instance(),\n"
+ " &unknown_fields_stream));\n");
}
printer->Print(
" continue;\n"
@@ -3152,19 +3548,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
}
// We really don't recognize this tag. Skip it.
- if (PreserveUnknownFields(descriptor_)) {
- if (UseUnknownFieldSet(descriptor_->file(), options_)) {
- printer->Print(
+ if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+ printer->Print(vars,
"DO_(::google::protobuf::internal::WireFormat::SkipField(\n"
- " input, tag, mutable_unknown_fields()));\n");
- } else {
- printer->Print(
- "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n"
- " input, tag, &unknown_fields_stream));\n");
- }
+ " input, tag, $mutable_unknown_fields$));\n");
} else {
printer->Print(
- "DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));\n");
+ "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n"
+ " input, tag, &unknown_fields_stream));\n");
}
if (descriptor_->field_count() > 0) {
@@ -3194,7 +3585,7 @@ void MessageGenerator::GenerateSerializeOneofFields(
bool to_array) {
GOOGLE_CHECK(!fields.empty());
if (fields.size() == 1) {
- GenerateSerializeOneField(printer, fields[0], to_array);
+ GenerateSerializeOneField(printer, fields[0], to_array, -1);
return;
}
// We have multiple mutually exclusive choices. Emit a switch statement.
@@ -3227,14 +3618,31 @@ void MessageGenerator::GenerateSerializeOneofFields(
}
void MessageGenerator::GenerateSerializeOneField(
- io::Printer* printer, const FieldDescriptor* field, bool to_array) {
- PrintFieldComment(printer, field);
+ io::Printer* printer, const FieldDescriptor* field, bool to_array,
+ int cached_has_bits_index) {
+ if (!field->options().weak()) {
+ // For weakfields, PrintFieldComment is called during iteration.
+ PrintFieldComment(printer, field);
+ }
bool have_enclosing_if = false;
- if (!field->is_repeated() && HasFieldPresence(descriptor_->file())) {
- printer->Print(
- "if (has_$name$()) {\n",
- "name", FieldName(field));
+ if (field->options().weak()) {
+ } else if (!field->is_repeated() && HasFieldPresence(descriptor_->file())) {
+ // Attempt to use the state of cached_has_bits, if possible.
+ int has_bit_index = has_bit_indices_[field->index()];
+ if (cached_has_bits_index == has_bit_index / 32) {
+ const string mask = StrCat(
+ strings::Hex(1u << (has_bit_index % 32),
+ strings::ZERO_PAD_8));
+
+ printer->Print(
+ "if (cached_has_bits & 0x$mask$u) {\n", "mask", mask);
+ } else {
+ printer->Print(
+ "if (has_$name$()) {\n",
+ "name", FieldName(field));
+ }
+
printer->Indent();
have_enclosing_if = true;
} else if (!HasFieldPresence(descriptor_->file())) {
@@ -3284,13 +3692,16 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) {
" _extensions_.SerializeMessageSetWithCachedSizes(output);\n",
"classname", classname_);
GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
- printer->Print(
+ std::map<string, string> vars;
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
+ printer->Print(vars,
" ::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n"
- " unknown_fields(), output);\n");
+ " $unknown_fields$, output);\n");
printer->Print(
"}\n");
return;
}
+ if (options_.table_driven_serialization) return;
printer->Print(
"void $classname$::SerializeWithCachedSizes(\n"
@@ -3325,10 +3736,12 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) {
" deterministic, target);\n",
"classname", classname_);
GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
- printer->Print(
+ std::map<string, string> vars;
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
+ printer->Print(vars,
" target = ::google::protobuf::internal::WireFormat::\n"
" SerializeUnknownMessageSetItemsToArray(\n"
- " unknown_fields(), target);\n");
+ " $unknown_fields$, target);\n");
printer->Print(
" return target;\n"
"}\n");
@@ -3341,7 +3754,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) {
"classname", classname_);
printer->Indent();
- printer->Print("(void)deterministic; // Unused\n");
+ printer->Print("(void)deterministic; // Unused\n");
printer->Print(
"// @@protoc_insertion_point(serialize_to_array_start:$full_name$)\n",
"full_name", descriptor_->full_name());
@@ -3372,7 +3785,8 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
: mg_(mg),
printer_(printer),
to_array_(to_array),
- eager_(!HasFieldPresence(mg->descriptor_->file())) {}
+ eager_(!HasFieldPresence(mg->descriptor_->file())),
+ cached_has_bit_index_(-1) {}
~LazySerializerEmitter() { Flush(); }
@@ -3383,7 +3797,27 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
Flush();
}
if (field->containing_oneof() == NULL) {
- mg_->GenerateSerializeOneField(printer_, field, to_array_);
+ // TODO(ckennelly): Defer non-oneof fields similarly to oneof fields.
+
+ if (!field->options().weak() && !field->is_repeated() && !eager_) {
+ // We speculatively load the entire _has_bits_[index] contents, even
+ // if it is for only one field. Deferring non-oneof emitting would
+ // allow us to determine whether this is going to be useful.
+ int has_bit_index = mg_->has_bit_indices_[field->index()];
+ if (cached_has_bit_index_ != has_bit_index / 32) {
+ // Reload.
+ int new_index = has_bit_index / 32;
+
+ printer_->Print(
+ "cached_has_bits = _has_bits_[$new_index$];\n",
+ "new_index", SimpleItoa(new_index));
+
+ cached_has_bit_index_ = new_index;
+ }
+ }
+
+ mg_->GenerateSerializeOneField(
+ printer_, field, to_array_, cached_has_bit_index_);
} else {
v_.push_back(field);
}
@@ -3409,6 +3843,11 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
const bool to_array_;
const bool eager_;
std::vector<const FieldDescriptor*> v_;
+
+ // cached_has_bit_index_ maintains that:
+ // cached_has_bits = from._has_bits_[cached_has_bit_index_]
+ // for cached_has_bit_index_ >= 0
+ int cached_has_bit_index_;
};
std::vector<const FieldDescriptor*> ordered_fields =
@@ -3420,54 +3859,76 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
}
std::sort(sorted_extensions.begin(), sorted_extensions.end(),
ExtensionRangeSorter());
+ if (num_weak_fields_) {
+ printer->Print(
+ "::google::protobuf::internal::WeakFieldMap::FieldWriter field_writer("
+ "_weak_field_map_);\n");
+ }
+
+ printer->Print(
+ "::google::protobuf::uint32 cached_has_bits = 0;\n"
+ "(void) cached_has_bits;\n\n");
// Merge the fields and the extension ranges, both sorted by field number.
{
LazySerializerEmitter e(this, printer, to_array);
+ const FieldDescriptor* last_weak_field = nullptr;
int i, j;
for (i = 0, j = 0;
i < ordered_fields.size() || j < sorted_extensions.size();) {
- if (i == descriptor_->field_count()) {
- e.Flush();
- GenerateSerializeOneExtensionRange(printer,
- sorted_extensions[j++],
- to_array);
- } else if (j == sorted_extensions.size()) {
- e.Emit(ordered_fields[i++]);
- } else if (ordered_fields[i]->number() < sorted_extensions[j]->start) {
- e.Emit(ordered_fields[i++]);
- } else {
+ if ((j == sorted_extensions.size()) ||
+ (i < descriptor_->field_count() &&
+ ordered_fields[i]->number() < sorted_extensions[j]->start)) {
+ const FieldDescriptor* field = ordered_fields[i++];
+ if (field->options().weak()) {
+ last_weak_field = field;
+ PrintFieldComment(printer, field);
+ } else {
+ if (last_weak_field != nullptr) {
+ e.Emit(last_weak_field);
+ last_weak_field = nullptr;
+ }
+ e.Emit(field);
+ }
+ } else {
+ if (last_weak_field != nullptr) {
+ e.Emit(last_weak_field);
+ last_weak_field = nullptr;
+ }
e.Flush();
GenerateSerializeOneExtensionRange(printer,
sorted_extensions[j++],
to_array);
}
}
+ if (last_weak_field != nullptr) {
+ e.Emit(last_weak_field);
+ }
}
- if (PreserveUnknownFields(descriptor_)) {
- if (UseUnknownFieldSet(descriptor_->file(), options_)) {
- printer->Print("if (_internal_metadata_.have_unknown_fields()) {\n");
- printer->Indent();
- if (to_array) {
- printer->Print(
- "target = "
- "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
- " unknown_fields(), target);\n");
- } else {
- printer->Print(
- "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
- " unknown_fields(), output);\n");
- }
- printer->Outdent();
-
- printer->Print(
- "}\n");
+ std::map<string, string> vars;
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
+ if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+ printer->Print(vars,
+ "if ($have_unknown_fields$) {\n");
+ printer->Indent();
+ if (to_array) {
+ printer->Print(vars,
+ "target = "
+ "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
+ " $unknown_fields$, target);\n");
} else {
- printer->Print(
- "output->WriteRaw(unknown_fields().data(),\n"
- " static_cast<int>(unknown_fields().size()));\n");
+ printer->Print(vars,
+ "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
+ " $unknown_fields$, output);\n");
}
+ printer->Outdent();
+
+ printer->Print("}\n");
+ } else {
+ printer->Print(vars,
+ "output->WriteRaw($unknown_fields$.data(),\n"
+ " static_cast<int>($unknown_fields$.size()));\n");
}
}
@@ -3502,8 +3963,9 @@ static string ConditionalToCheckBitmasks(const std::vector<uint32>& masks) {
}
GOOGLE_CHECK(!parts.empty());
// If we have multiple parts, each expected to be 0, then bitwise-or them.
- string result = parts.size() == 1 ? parts[0] :
- StrCat("(", Join(parts, "\n | "), ")");
+ string result = parts.size() == 1
+ ? parts[0]
+ : StrCat("(", Join(parts, "\n | "), ")");
return result + " == 0";
}
@@ -3511,24 +3973,24 @@ void MessageGenerator::
GenerateByteSize(io::Printer* printer) {
if (descriptor_->options().message_set_wire_format()) {
// Special-case MessageSet.
+ GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
+ std::map<string, string> vars;
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
+ vars["classname"] = classname_;
+ vars["full_name"] = descriptor_->full_name();
printer->Print(
+ vars,
"size_t $classname$::ByteSizeLong() const {\n"
"// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n"
- " size_t total_size = _extensions_.MessageSetByteSize();\n",
- "classname", classname_, "full_name", descriptor_->full_name());
- GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
- printer->Print(
- "if (_internal_metadata_.have_unknown_fields()) {\n"
- " total_size += ::google::protobuf::internal::WireFormat::\n"
- " ComputeUnknownMessageSetItemsSize(unknown_fields());\n"
- "}\n");
- printer->Print(
- " int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n"
- " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
- " _cached_size_ = cached_size;\n"
- " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
- " return total_size;\n"
- "}\n");
+ " size_t total_size = _extensions_.MessageSetByteSize();\n"
+ " if ($have_unknown_fields$) {\n"
+ " total_size += ::google::protobuf::internal::WireFormat::\n"
+ " ComputeUnknownMessageSetItemsSize($unknown_fields$);\n"
+ " }\n"
+ " int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n"
+ " SetCachedSize(cached_size);\n"
+ " return total_size;\n"
+ "}\n");
return;
}
@@ -3576,19 +4038,19 @@ GenerateByteSize(io::Printer* printer) {
"\n");
}
- if (PreserveUnknownFields(descriptor_)) {
- if (UseUnknownFieldSet(descriptor_->file(), options_)) {
- printer->Print(
- "if (_internal_metadata_.have_unknown_fields()) {\n"
- " total_size +=\n"
- " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
- " unknown_fields());\n"
- "}\n");
- } else {
- printer->Print(
- "total_size += unknown_fields().size();\n"
- "\n");
- }
+ std::map<string, string> vars;
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
+ if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+ printer->Print(vars,
+ "if ($have_unknown_fields$) {\n"
+ " total_size +=\n"
+ " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
+ " $unknown_fields$);\n"
+ "}\n");
+ } else {
+ printer->Print(vars,
+ "total_size += $unknown_fields$.size();\n"
+ "\n");
}
// Handle required fields (if any). We expect all of them to be
@@ -3629,28 +4091,30 @@ GenerateByteSize(io::Printer* printer) {
}
}
- int last_i = -1;
- for (int i = 0; i < optimized_order_.size(); ) {
- // Detect infinite loops.
- GOOGLE_CHECK_NE(i, last_i);
- last_i = i;
+ std::vector<std::vector<const FieldDescriptor*> > chunks = CollectFields(
+ optimized_order_,
+ MatchRepeatedAndHasByteAndRequired(
+ &has_bit_indices_, HasFieldPresence(descriptor_->file())));
- // Skip required fields.
- for (; i < optimized_order_.size() &&
- optimized_order_[i]->is_required(); i++) {
- }
+ // Remove chunks with required fields.
+ chunks.erase(std::remove_if(chunks.begin(), chunks.end(), IsRequired),
+ chunks.end());
+
+ for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) {
+ const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index];
+ GOOGLE_CHECK(!chunk.empty());
// Handle repeated fields.
- for (; i < optimized_order_.size(); i++) {
- const FieldDescriptor* field = optimized_order_[i];
- if (!field->is_repeated()) {
- break;
- }
+ if (chunk.front()->is_repeated()) {
+ for (int i = 0; i < chunk.size(); i++) {
+ const FieldDescriptor* field = chunk[i];
- PrintFieldComment(printer, field);
- const FieldGenerator& generator = field_generators_.get(field);
- generator.GenerateByteSize(printer);
- printer->Print("\n");
+ PrintFieldComment(printer, field);
+ const FieldGenerator& generator = field_generators_.get(field);
+ generator.GenerateByteSize(printer);
+ printer->Print("\n");
+ }
+ continue;
}
// Handle optional (non-repeated/oneof) fields.
@@ -3662,92 +4126,62 @@ GenerateByteSize(io::Printer* printer) {
// descriptor_->field(8), descriptor_->field(9), ...
// descriptor_->field(15),
// etc.
- int last_chunk = -1;
- int last_chunk_start = -1;
- int last_chunk_end = -1;
- uint32 last_chunk_mask = 0;
- for (; i < optimized_order_.size(); i++) {
- const FieldDescriptor* field = optimized_order_[i];
- if (field->is_repeated() || field->is_required()) {
- break;
- }
+ int last_chunk = HasFieldPresence(descriptor_->file())
+ ? has_bit_indices_[chunk.front()->index()] / 8
+ : 0;
+ GOOGLE_DCHECK_NE(-1, last_chunk);
- // "index" defines where in the _has_bits_ the field appears.
- // "i" is our loop counter within optimized_order_.
- int index = HasFieldPresence(descriptor_->file()) ?
- has_bit_indices_[field->index()] : 0;
- int chunk = index / 8;
+ const bool have_outer_if =
+ HasFieldPresence(descriptor_->file()) && chunk.size() > 1;
- if (last_chunk == -1) {
- last_chunk = chunk;
- last_chunk_start = i;
- } else if (chunk != last_chunk) {
- // Emit the fields for this chunk so far.
- break;
- }
+ if (have_outer_if) {
+ uint32 last_chunk_mask = GenChunkMask(chunk, has_bit_indices_);
+ const int count = popcnt(last_chunk_mask);
- last_chunk_end = i;
- last_chunk_mask |= static_cast<uint32>(1) << (index % 32);
- }
+ // Check (up to) 8 has_bits at a time if we have more than one field in
+ // this chunk. Due to field layout ordering, we may check
+ // _has_bits_[last_chunk * 8 / 32] multiple times.
+ GOOGLE_DCHECK_LE(2, count);
+ GOOGLE_DCHECK_GE(8, count);
- if (last_chunk != -1) {
- GOOGLE_DCHECK_NE(-1, last_chunk_start);
- GOOGLE_DCHECK_NE(-1, last_chunk_end);
- GOOGLE_DCHECK_NE(0, last_chunk_mask);
+ printer->Print("if (_has_bits_[$index$ / 32] & $mask$u) {\n", "index",
+ SimpleItoa(last_chunk * 8), "mask",
+ SimpleItoa(last_chunk_mask));
+ printer->Indent();
+ }
- const int count = popcnt(last_chunk_mask);
- const bool have_outer_if = HasFieldPresence(descriptor_->file()) &&
- (last_chunk_start != last_chunk_end);
+ // Go back and emit checks for each of the fields we processed.
+ for (int j = 0; j < chunk.size(); j++) {
+ const FieldDescriptor* field = chunk[j];
+ const FieldGenerator& generator = field_generators_.get(field);
- if (have_outer_if) {
- // Check (up to) 8 has_bits at a time if we have more than one field in
- // this chunk. Due to field layout ordering, we may check
- // _has_bits_[last_chunk * 8 / 32] multiple times.
- GOOGLE_DCHECK_LE(2, count);
- GOOGLE_DCHECK_GE(8, count);
+ PrintFieldComment(printer, field);
- printer->Print(
- "if (_has_bits_[$index$ / 32] & $mask$u) {\n",
- "index", SimpleItoa(last_chunk * 8),
- "mask", SimpleItoa(last_chunk_mask));
+ bool have_enclosing_if = false;
+ if (HasFieldPresence(descriptor_->file())) {
+ printer->Print("if (has_$name$()) {\n", "name", FieldName(field));
printer->Indent();
+ have_enclosing_if = true;
+ } else {
+ // Without field presence: field is serialized only if it has a
+ // non-default value.
+ have_enclosing_if =
+ EmitFieldNonDefaultCondition(printer, "this->", field);
}
- // Go back and emit checks for each of the fields we processed.
- for (int j = last_chunk_start; j <= last_chunk_end; j++) {
- const FieldDescriptor* field = optimized_order_[j];
- const FieldGenerator& generator = field_generators_.get(field);
-
- PrintFieldComment(printer, field);
-
- bool have_enclosing_if = false;
- if (HasFieldPresence(descriptor_->file())) {
- printer->Print(
- "if (has_$name$()) {\n",
- "name", FieldName(field));
- printer->Indent();
- have_enclosing_if = true;
- } else {
- // Without field presence: field is serialized only if it has a
- // non-default value.
- have_enclosing_if = EmitFieldNonDefaultCondition(
- printer, "this->", field);
- }
-
- generator.GenerateByteSize(printer);
+ generator.GenerateByteSize(printer);
- if (have_enclosing_if) {
- printer->Outdent();
- printer->Print(
+ if (have_enclosing_if) {
+ printer->Outdent();
+ printer->Print(
"}\n"
"\n");
- }
}
+ }
- if (have_outer_if) {
- printer->Outdent();
- printer->Print("}\n");
- }
+ if (have_outer_if) {
+ printer->Outdent();
+ printer->Print("}\n");
}
}
@@ -3783,17 +4217,23 @@ GenerateByteSize(io::Printer* printer) {
"}\n");
}
- // We update _cached_size_ even though this is a const method. In theory,
- // this is not thread-compatible, because concurrent writes have undefined
- // results. In practice, since any concurrent writes will be writing the
- // exact same value, it works on all common processors. In a future version
- // of C++, _cached_size_ should be made into an atomic<int>.
+ if (num_weak_fields_) {
+ // TagSize + MessageSize
+ printer->Print("total_size += _weak_field_map_.ByteSizeLong();\n");
+ }
+
+ // We update _cached_size_ even though this is a const method. Because
+ // const methods might be called concurrently this needs to be atomic
+ // operations or the program is undefined. In practice, since any concurrent
+ // writes will be writing the exact same value, normal writes will work on
+ // all common processors. We use a dedicated wrapper class to abstract away
+ // the underlying atomic. This makes it easier on platforms where even relaxed
+ // memory order might have perf impact to replace it with ordinary loads and
+ // stores.
printer->Print(
- "int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n"
- "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
- "_cached_size_ = cached_size;\n"
- "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
- "return total_size;\n");
+ "int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n"
+ "SetCachedSize(cached_size);\n"
+ "return total_size;\n");
printer->Outdent();
printer->Print("}\n");
@@ -3840,26 +4280,35 @@ GenerateIsInitialized(io::Printer* printer) {
// TODO(ckennelly): Push this down into a generator?
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
!ShouldIgnoreRequiredFieldCheck(field, options_) &&
- HasRequiredFields(field->message_type(), options_)) {
+ scc_analyzer_->HasRequiredFields(field->message_type())) {
if (field->is_repeated()) {
- printer->Print(
- "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))"
- " return false;\n",
- "name", FieldName(field));
+ if (IsImplicitWeakField(field, options_, scc_analyzer_)) {
+ printer->Print(
+ "if (!::google::protobuf::internal::AllAreInitializedWeak(this->$name$_))"
+ " return false;\n",
+ "name", FieldName(field));
+ } else {
+ printer->Print(
+ "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))"
+ " return false;\n",
+ "name", FieldName(field));
+ }
+ } else if (field->options().weak()) {
+ continue;
} else {
- GOOGLE_CHECK(field->options().weak() || !field->containing_oneof());
- // For weak fields, use the data member (::google::protobuf::Message*) instead
- // of the getter to avoid a link dependency on the weak message type
- // which is only forward declared.
+ GOOGLE_CHECK(!field->containing_oneof());
printer->Print(
"if (has_$name$()) {\n"
" if (!this->$name$_->IsInitialized()) return false;\n"
"}\n",
- "name", FieldName(field));
+ "name", FieldName(field));
}
}
}
-
+ if (num_weak_fields_) {
+ // For Weak fields.
+ printer->Print("if (!_weak_field_map_.IsInitialized()) return false;\n");
+ }
// Go through the oneof fields, emitting a switch if any might have required
// fields.
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
@@ -3871,7 +4320,7 @@ GenerateIsInitialized(io::Printer* printer) {
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
!ShouldIgnoreRequiredFieldCheck(field, options_) &&
- HasRequiredFields(field->message_type(), options_)) {
+ scc_analyzer_->HasRequiredFields(field->message_type())) {
has_required_fields = true;
break;
}
@@ -3894,17 +4343,10 @@ GenerateIsInitialized(io::Printer* printer) {
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
!ShouldIgnoreRequiredFieldCheck(field, options_) &&
- HasRequiredFields(field->message_type(), options_)) {
+ scc_analyzer_->HasRequiredFields(field->message_type())) {
GOOGLE_CHECK(!(field->options().weak() || !field->containing_oneof()));
if (field->options().weak()) {
- // For weak fields, use the data member (::google::protobuf::Message*) instead
- // of the getter to avoid a link dependency on the weak message type
- // which is only forward declared.
- printer->Print(
- "if (has_$name$()) {\n"
- " if (!this->$name$_->IsInitialized()) return false;\n"
- "}\n",
- "name", FieldName(field));
+ // Just skip.
} else {
printer->Print(
"if (has_$name$()) {\n"
@@ -3937,7 +4379,6 @@ GenerateIsInitialized(io::Printer* printer) {
"}\n");
}
-
} // namespace cpp
} // namespace compiler
} // namespace protobuf