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