|
@@ -69,6 +69,8 @@ using internal::WireFormatLite;
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
+static constexpr int kNoHasbit = -1;
|
|
|
+
|
|
|
// Create an expression that evaluates to
|
|
|
// "for all i, (_has_bits_[i] & masks[i]) == masks[i]"
|
|
|
// masks is allowed to be shorter than _has_bits_, but at least one element of
|
|
@@ -239,7 +241,8 @@ bool HasHasMethod(const FieldDescriptor* field) {
|
|
|
}
|
|
|
// For message types without true field presence, only fields with a message
|
|
|
// type have a has_$name$() method.
|
|
|
- return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE;
|
|
|
+ return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
|
|
|
+ field->has_optional_keyword();
|
|
|
}
|
|
|
|
|
|
// Collects map entry message type information.
|
|
@@ -329,10 +332,16 @@ bool TableDrivenParsingEnabled(const Descriptor* descriptor,
|
|
|
// 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;
|
|
|
+ bool has_hasbit = false;
|
|
|
+ for (int i = 0; i < descriptor->field_count(); i++) {
|
|
|
+ if (HasHasbit(descriptor->field(i))) {
|
|
|
+ has_hasbit = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ if (!has_hasbit) return false;
|
|
|
+
|
|
|
const double table_sparseness = 0.5;
|
|
|
int max_field_number = 0;
|
|
|
for (auto field : FieldRange(descriptor)) {
|
|
@@ -488,7 +497,7 @@ void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index,
|
|
|
const std::string& from,
|
|
|
io::Printer* printer) {
|
|
|
Formatter format(printer, variables_);
|
|
|
- if (!access_info_map_ || has_bit_indices_.empty()) {
|
|
|
+ if (!access_info_map_) {
|
|
|
return;
|
|
|
} else if (chunk < limit_chunk_) {
|
|
|
// We are already inside a run of cold chunks.
|
|
@@ -595,17 +604,18 @@ MessageGenerator::MessageGenerator(
|
|
|
|
|
|
message_layout_helper_->OptimizeLayout(&optimized_order_, options_);
|
|
|
|
|
|
- if (HasFieldPresence(descriptor_->file())) {
|
|
|
- // We use -1 as a sentinel.
|
|
|
- has_bit_indices_.resize(descriptor_->field_count(), -1);
|
|
|
- for (auto field : optimized_order_) {
|
|
|
- // Skip fields that do not have has bits.
|
|
|
- if (field->is_repeated()) {
|
|
|
- continue;
|
|
|
+ // This message has hasbits iff one or more fields need one.
|
|
|
+ for (auto field : optimized_order_) {
|
|
|
+ if (HasHasbit(field)) {
|
|
|
+ if (has_bit_indices_.empty()) {
|
|
|
+ has_bit_indices_.resize(descriptor_->field_count(), kNoHasbit);
|
|
|
}
|
|
|
-
|
|
|
has_bit_indices_[field->index()] = max_has_bit_index_++;
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (!has_bit_indices_.empty()) {
|
|
|
field_generators_.SetHasBitIndices(has_bit_indices_);
|
|
|
}
|
|
|
|
|
@@ -635,17 +645,18 @@ size_t MessageGenerator::HasBitsSize() const {
|
|
|
}
|
|
|
|
|
|
int MessageGenerator::HasBitIndex(const FieldDescriptor* field) const {
|
|
|
- return has_bit_indices_.empty() ? -1 : has_bit_indices_[field->index()];
|
|
|
+ return has_bit_indices_.empty() ? kNoHasbit
|
|
|
+ : has_bit_indices_[field->index()];
|
|
|
}
|
|
|
|
|
|
int MessageGenerator::HasByteIndex(const FieldDescriptor* field) const {
|
|
|
int hasbit = HasBitIndex(field);
|
|
|
- return hasbit == -1 ? -1 : hasbit / 8;
|
|
|
+ return hasbit == kNoHasbit ? kNoHasbit : hasbit / 8;
|
|
|
}
|
|
|
|
|
|
int MessageGenerator::HasWordIndex(const FieldDescriptor* field) const {
|
|
|
int hasbit = HasBitIndex(field);
|
|
|
- return hasbit == -1 ? -1 : hasbit / 32;
|
|
|
+ return hasbit == kNoHasbit ? kNoHasbit : hasbit / 32;
|
|
|
}
|
|
|
|
|
|
void MessageGenerator::AddGenerators(
|
|
@@ -784,11 +795,9 @@ void MessageGenerator::GenerateSingularFieldHasBits(
|
|
|
"}\n");
|
|
|
return;
|
|
|
}
|
|
|
- if (HasFieldPresence(descriptor_->file())) {
|
|
|
- // N.B.: without field presence, we do not use has-bits or generate
|
|
|
- // has_$name$() methods.
|
|
|
- int has_bit_index = has_bit_indices_[field->index()];
|
|
|
- GOOGLE_CHECK_GE(has_bit_index, 0);
|
|
|
+ if (HasHasbit(field)) {
|
|
|
+ int has_bit_index = HasBitIndex(field);
|
|
|
+ GOOGLE_CHECK_NE(has_bit_index, kNoHasbit);
|
|
|
|
|
|
format.Set("has_array_index", has_bit_index / 32);
|
|
|
format.Set("has_mask",
|
|
@@ -813,27 +822,25 @@ void MessageGenerator::GenerateSingularFieldHasBits(
|
|
|
"$annotate_accessor$"
|
|
|
" return _internal_has_$name$();\n"
|
|
|
"}\n");
|
|
|
- } else {
|
|
|
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
|
|
// Message fields have a has_$name$() method.
|
|
|
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
|
|
- if (IsLazy(field, options_)) {
|
|
|
- format(
|
|
|
- "inline bool $classname$::_internal_has_$name$() const {\n"
|
|
|
- " return !$name$_.IsCleared();\n"
|
|
|
- "}\n");
|
|
|
- } else {
|
|
|
- format(
|
|
|
- "inline bool $classname$::_internal_has_$name$() const {\n"
|
|
|
- " return this != internal_default_instance() "
|
|
|
- "&& $name$_ != nullptr;\n"
|
|
|
- "}\n");
|
|
|
- }
|
|
|
+ if (IsLazy(field, options_)) {
|
|
|
+ format(
|
|
|
+ "inline bool $classname$::_internal_has_$name$() const {\n"
|
|
|
+ " return !$name$_.IsCleared();\n"
|
|
|
+ "}\n");
|
|
|
+ } else {
|
|
|
format(
|
|
|
- "inline bool $classname$::has_$name$() const {\n"
|
|
|
- "$annotate_accessor$"
|
|
|
- " return _internal_has_$name$();\n"
|
|
|
+ "inline bool $classname$::_internal_has_$name$() const {\n"
|
|
|
+ " return this != internal_default_instance() "
|
|
|
+ "&& $name$_ != nullptr;\n"
|
|
|
"}\n");
|
|
|
}
|
|
|
+ format(
|
|
|
+ "inline bool $classname$::has_$name$() const {\n"
|
|
|
+ "$annotate_accessor$"
|
|
|
+ " return _internal_has_$name$();\n"
|
|
|
+ "}\n");
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -926,16 +933,12 @@ void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field,
|
|
|
format("}\n");
|
|
|
} else {
|
|
|
field_generators_.get(field).GenerateClearingCode(format.printer());
|
|
|
- if (HasFieldPresence(descriptor_->file())) {
|
|
|
- if (!field->is_repeated() && !field->options().weak()) {
|
|
|
- int has_bit_index = has_bit_indices_[field->index()];
|
|
|
- GOOGLE_CHECK_GE(has_bit_index, 0);
|
|
|
-
|
|
|
- format.Set("has_array_index", has_bit_index / 32);
|
|
|
- format.Set("has_mask",
|
|
|
- strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8));
|
|
|
- format("_has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n");
|
|
|
- }
|
|
|
+ if (HasHasbit(field)) {
|
|
|
+ int has_bit_index = HasBitIndex(field);
|
|
|
+ format.Set("has_array_index", has_bit_index / 32);
|
|
|
+ format.Set("has_mask",
|
|
|
+ strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8));
|
|
|
+ format("_has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n");
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1540,7 +1543,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
|
|
|
"typedef void DestructorSkippable_;\n");
|
|
|
}
|
|
|
|
|
|
- if (HasFieldPresence(descriptor_->file())) {
|
|
|
+ if (!has_bit_indices_.empty()) {
|
|
|
// _has_bits_ is frequently accessed, so to reduce code size and improve
|
|
|
// speed, it should be close to the start of the object. Placing
|
|
|
// _cached_size_ together with _has_bits_ improves cache locality despite
|
|
@@ -1686,8 +1689,8 @@ bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset,
|
|
|
"$3$,\n",
|
|
|
offset, aux_offset, max_field_number);
|
|
|
|
|
|
- if (!HasFieldPresence(descriptor_->file())) {
|
|
|
- // If we don't have field presence, then _has_bits_ does not exist.
|
|
|
+ if (has_bit_indices_.empty()) {
|
|
|
+ // If no fields have hasbits, then _has_bits_ does not exist.
|
|
|
format("-1,\n");
|
|
|
} else {
|
|
|
format("PROTOBUF_FIELD_OFFSET($classtype$, _has_bits_),\n");
|
|
@@ -1725,10 +1728,9 @@ bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset,
|
|
|
void MessageGenerator::GenerateSchema(io::Printer* printer, int offset,
|
|
|
int has_offset) {
|
|
|
Formatter format(printer, variables_);
|
|
|
- has_offset =
|
|
|
- HasFieldPresence(descriptor_->file()) || IsMapEntryMessage(descriptor_)
|
|
|
- ? offset + has_offset
|
|
|
- : -1;
|
|
|
+ has_offset = !has_bit_indices_.empty() || IsMapEntryMessage(descriptor_)
|
|
|
+ ? offset + has_offset
|
|
|
+ : -1;
|
|
|
|
|
|
format("{ $1$, $2$, sizeof($classtype$)},\n", offset, has_offset);
|
|
|
}
|
|
@@ -1763,13 +1765,12 @@ uint32 CalcFieldNum(const FieldGenerator& generator,
|
|
|
} 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) {
|
|
|
+ } else if (HasHasbit(field) || field->containing_oneof() || is_a_map) {
|
|
|
return internal::FieldMetadata::CalculateType(
|
|
|
- type, internal::FieldMetadata::kNoPresence);
|
|
|
+ type, internal::FieldMetadata::kPresence);
|
|
|
} else {
|
|
|
return internal::FieldMetadata::CalculateType(
|
|
|
- type, internal::FieldMetadata::kPresence);
|
|
|
+ type, internal::FieldMetadata::kNoPresence);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1897,8 +1898,7 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
|
|
|
"::internal::LazyFieldSerializer";
|
|
|
if (field->containing_oneof()) {
|
|
|
ptr += "OneOf";
|
|
|
- } else if (!HasFieldPresence(descriptor_->file()) ||
|
|
|
- has_bit_indices_[field->index()] == -1) {
|
|
|
+ } else if (!HasHasbit(field)) {
|
|
|
ptr += "NoPresence";
|
|
|
}
|
|
|
ptr += ")";
|
|
@@ -1921,8 +1921,7 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
|
|
|
" PROTOBUF_FIELD_OFFSET($classtype$, _oneof_case_) + "
|
|
|
"$oneofoffset$, $2$, $3$},\n",
|
|
|
tag, type, ptr);
|
|
|
- } else if (HasFieldPresence(descriptor_->file()) &&
|
|
|
- has_bit_indices_[field->index()] != -1) {
|
|
|
+ } else if (HasHasbit(field)) {
|
|
|
format.Set("hasbitsoffset", has_bit_indices_[field->index()]);
|
|
|
format(
|
|
|
"{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), "
|
|
@@ -2073,7 +2072,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
|
|
|
"class $classname$::_Internal {\n"
|
|
|
" public:\n");
|
|
|
format.Indent();
|
|
|
- if (HasFieldPresence(descriptor_->file()) && HasBitsSize() != 0) {
|
|
|
+ if (!has_bit_indices_.empty()) {
|
|
|
format(
|
|
|
"using HasBits = decltype(std::declval<$classname$>()._has_bits_);\n");
|
|
|
}
|
|
@@ -2082,10 +2081,8 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
|
|
|
if (!IsFieldUsed(field, options_)) {
|
|
|
continue;
|
|
|
}
|
|
|
- if (HasFieldPresence(descriptor_->file()) && !field->is_repeated() &&
|
|
|
- !field->options().weak() && !field->containing_oneof()) {
|
|
|
- int has_bit_index = has_bit_indices_[field->index()];
|
|
|
- GOOGLE_CHECK_GE(has_bit_index, 0);
|
|
|
+ if (HasHasbit(field)) {
|
|
|
+ int has_bit_index = HasBitIndex(field);
|
|
|
format(
|
|
|
"static void set_has_$1$(HasBits* has_bits) {\n"
|
|
|
" (*has_bits)[$2$] |= $3$u;\n"
|
|
@@ -2093,7 +2090,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
|
|
|
FieldName(field), has_bit_index / 32, (1u << (has_bit_index % 32)));
|
|
|
}
|
|
|
}
|
|
|
- if (num_required_fields_ > 0 && HasFieldPresence(descriptor_->file())) {
|
|
|
+ if (num_required_fields_ > 0) {
|
|
|
const std::vector<uint32> masks_for_has_bits = RequiredFieldsBitMask();
|
|
|
format(
|
|
|
"static bool MissingRequiredFields(const HasBits& has_bits) "
|
|
@@ -2392,7 +2389,7 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
|
|
|
io::Printer* printer) {
|
|
|
Formatter format(printer, variables_);
|
|
|
|
|
|
- if (HasFieldPresence(descriptor_->file()) || IsMapEntryMessage(descriptor_)) {
|
|
|
+ if (!has_bit_indices_.empty() || IsMapEntryMessage(descriptor_)) {
|
|
|
format("PROTOBUF_FIELD_OFFSET($classtype$, _has_bits_),\n");
|
|
|
} else {
|
|
|
format("~0u, // no _has_bits_\n");
|
|
@@ -2451,7 +2448,7 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
|
|
|
format(
|
|
|
"0,\n"
|
|
|
"1,\n");
|
|
|
- } else if (HasFieldPresence(descriptor_->file())) {
|
|
|
+ } else if (!has_bit_indices_.empty()) {
|
|
|
entries += has_bit_indices_.size() - num_stripped;
|
|
|
for (int i = 0; i < has_bit_indices_.size(); i++) {
|
|
|
if (!IsFieldUsed(descriptor_->field(i), options_)) {
|
|
@@ -2723,10 +2720,8 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) {
|
|
|
format.Indent();
|
|
|
format.Indent();
|
|
|
|
|
|
- if (HasFieldPresence(descriptor_->file())) {
|
|
|
- if (!IsProto2MessageSet(descriptor_, options_)) {
|
|
|
- format(",\n_has_bits_(from._has_bits_)");
|
|
|
- }
|
|
|
+ if (!has_bit_indices_.empty()) {
|
|
|
+ format(",\n_has_bits_(from._has_bits_)");
|
|
|
}
|
|
|
|
|
|
std::vector<bool> processed(optimized_order_.size(), false);
|
|
@@ -2916,7 +2911,7 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
|
|
|
// We can omit the if() for chunk size 1, or if our fields do not have
|
|
|
// hasbits. I don't understand the rationale for the last part of the
|
|
|
// condition, but it matches the old logic.
|
|
|
- const bool have_outer_if = HasBitIndex(chunk.front()) != -1 &&
|
|
|
+ const bool have_outer_if = HasBitIndex(chunk.front()) != kNoHasbit &&
|
|
|
chunk.size() > 1 &&
|
|
|
(memset_end != chunk.back() || merge_zero_init);
|
|
|
|
|
@@ -2962,7 +2957,7 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
|
|
|
//
|
|
|
// TODO(kenton): Let the CppFieldGenerator decide this somehow.
|
|
|
bool have_enclosing_if =
|
|
|
- HasBitIndex(field) != -1 &&
|
|
|
+ HasBitIndex(field) != kNoHasbit &&
|
|
|
(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
|
|
|
field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
|
|
|
|
|
@@ -2999,7 +2994,7 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
|
|
|
format("_weak_field_map_.ClearAll();\n");
|
|
|
}
|
|
|
|
|
|
- if (HasFieldPresence(descriptor_->file())) {
|
|
|
+ if (!has_bit_indices_.empty()) {
|
|
|
// Step 5: Everything else.
|
|
|
format("_has_bits_.Clear();\n");
|
|
|
}
|
|
@@ -3075,7 +3070,7 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) {
|
|
|
"_internal_metadata_.Swap<$unknown_fields_type$>(&other->_internal_"
|
|
|
"metadata_);\n");
|
|
|
|
|
|
- if (HasFieldPresence(descriptor_->file())) {
|
|
|
+ if (!has_bit_indices_.empty()) {
|
|
|
for (int i = 0; i < HasBitsSize() / 4; ++i) {
|
|
|
format("swap(_has_bits_[$1$], other->_has_bits_[$1$]);\n", i);
|
|
|
}
|
|
@@ -3218,7 +3213,8 @@ void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) {
|
|
|
|
|
|
for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) {
|
|
|
const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index];
|
|
|
- bool have_outer_if = chunk.size() > 1 && HasByteIndex(chunk.front()) != -1;
|
|
|
+ bool have_outer_if =
|
|
|
+ chunk.size() > 1 && HasByteIndex(chunk.front()) != kNoHasbit;
|
|
|
cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "from.",
|
|
|
printer);
|
|
|
|
|
@@ -3466,9 +3462,9 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* printer,
|
|
|
|
|
|
bool have_enclosing_if = false;
|
|
|
if (field->options().weak()) {
|
|
|
- } else if (!field->is_repeated() && HasFieldPresence(descriptor_->file())) {
|
|
|
+ } else if (HasHasbit(field)) {
|
|
|
// Attempt to use the state of cached_has_bits, if possible.
|
|
|
- int has_bit_index = has_bit_indices_[field->index()];
|
|
|
+ int has_bit_index = HasBitIndex(field);
|
|
|
if (cached_has_bits_index == has_bit_index / 32) {
|
|
|
const std::string mask =
|
|
|
StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8));
|
|
@@ -3480,7 +3476,7 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* printer,
|
|
|
|
|
|
format.Indent();
|
|
|
have_enclosing_if = true;
|
|
|
- } else if (!HasFieldPresence(descriptor_->file())) {
|
|
|
+ } else if (field->is_optional() && !HasHasbit(field)) {
|
|
|
have_enclosing_if = EmitFieldNonDefaultCondition(printer, "this->", field);
|
|
|
}
|
|
|
|
|
@@ -3561,7 +3557,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody(
|
|
|
: mg_(mg),
|
|
|
format_(printer),
|
|
|
eager_(!HasFieldPresence(mg->descriptor_->file())),
|
|
|
- cached_has_bit_index_(-1) {}
|
|
|
+ cached_has_bit_index_(kNoHasbit) {}
|
|
|
|
|
|
~LazySerializerEmitter() { Flush(); }
|
|
|
|
|
@@ -3841,7 +3837,8 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) {
|
|
|
|
|
|
for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) {
|
|
|
const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index];
|
|
|
- const bool have_outer_if = chunk.size() > 1 && HasWordIndex(chunk[0]) != -1;
|
|
|
+ const bool have_outer_if =
|
|
|
+ chunk.size() > 1 && HasWordIndex(chunk[0]) != kNoHasbit;
|
|
|
cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", printer);
|
|
|
|
|
|
if (have_outer_if) {
|
|
@@ -3983,7 +3980,7 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
|
|
|
"}\n\n");
|
|
|
}
|
|
|
|
|
|
- if (num_required_fields_ > 0 && HasFieldPresence(descriptor_->file())) {
|
|
|
+ if (num_required_fields_ > 0) {
|
|
|
format(
|
|
|
"if (_Internal::MissingRequiredFields(_has_bits_))"
|
|
|
" return false;\n");
|