Rename private reflection helpers HasBit to HasFieldSingular.

This change renames the helper functions to HasFieldSingular(), SetHasBit(),
ClearHasBit(), and SwapHasBit(), which should hopefully be less confusing.

First of all, the HasBit(), SetBit(), ClearBit(), and SwapBit() methods are all
private so they are easier to change than a public-facing API.

The function named HasBit is called for both proto2 and proto3 fields. For
proto2 fields, it returns true if and only if the hasbit is set -- i.e. if the
field is present. For proto3 fields, it returns true if and only if the field
is nonempty -- i.e. if the field is present.

See documentation here for what "field presence" means:
https://github.com/protocolbuffers/protobuf/blob/main/docs/field_presence.md

Note that in the proto3 case, what this function is doing has nothing to do
with bits!

The name HasFieldSingular is chosen to emphasize the fact that this function
has the same semantics has HasField, only that it's narrowly applied to
"singular" (i.e., non-repeating, non-oneof, non-weak) fields.

HasField itself is not a great name -- IsPresent is probably more appripriate
-- but it is a public API and therefore hard to change. This change at least
makes the two share a similar name.

(I considered `HasPresence` too but that also leaves room for ambiguity: "has
presence" might be interpreted to refer to whether a field is an explicit
presence field or an implicit presence field).

The other helper functions here do manipulate the hasbit directly. Because of
this, they should just make it obvious in the name.

PiperOrigin-RevId: 671966727
pull/18071/head
Tony Liao 3 months ago committed by Copybara-Service
parent 849f05f886
commit c964e143d9
  1. 64
      src/google/protobuf/generated_message_reflection.cc
  2. 16
      src/google/protobuf/message.h
  3. 2
      src/google/protobuf/reflection_visit_fields.h

@ -786,18 +786,18 @@ void SwapFieldHelper::SwapMessage(const Reflection* r, Message* lhs,
if (*lhs_sub != nullptr && *rhs_sub != nullptr) {
(*lhs_sub)->GetReflection()->Swap(*lhs_sub, *rhs_sub);
} else if (*lhs_sub == nullptr && r->HasBit(*rhs, field)) {
} else if (*lhs_sub == nullptr && r->HasFieldSingular(*rhs, field)) {
*lhs_sub = (*rhs_sub)->New(lhs_arena);
(*lhs_sub)->CopyFrom(**rhs_sub);
r->ClearField(rhs, field);
// Ensures has bit is unchanged after ClearField.
r->SetBit(rhs, field);
} else if (*rhs_sub == nullptr && r->HasBit(*lhs, field)) {
r->SetHasBit(rhs, field);
} else if (*rhs_sub == nullptr && r->HasFieldSingular(*lhs, field)) {
*rhs_sub = (*lhs_sub)->New(rhs_arena);
(*rhs_sub)->CopyFrom(**lhs_sub);
r->ClearField(lhs, field);
// Ensures has bit is unchanged after ClearField.
r->SetBit(lhs, field);
r->SetHasBit(lhs, field);
}
}
@ -1161,7 +1161,7 @@ void Reflection::SwapFieldsImpl(
// oneof already. This has to be done after SwapField, because SwapField
// may depend on the information in has bits.
if (!field->is_repeated()) {
SwapBit(message1, message2, field);
SwapHasBit(message1, message2, field);
if (field->options().ctype() == FieldOptions::STRING &&
IsInlined(field)) {
ABSL_DCHECK(!unsafe_shallow_swap ||
@ -1217,7 +1217,7 @@ bool Reflection::HasField(const Message& message,
if (schema_.InRealOneof(field)) {
return HasOneofField(message, field);
} else {
return HasBit(message, field);
return HasFieldSingular(message, field);
}
}
}
@ -1363,8 +1363,8 @@ void Reflection::ClearField(Message* message,
ClearOneofField(message, field);
return;
}
if (HasBit(*message, field)) {
ClearBit(message, field);
if (HasFieldSingular(*message, field)) {
ClearHasBit(message, field);
// We need to set the field back to its default value.
switch (field->cpp_type()) {
@ -1675,11 +1675,12 @@ void Reflection::ListFields(const Message& message,
append_to_output(field);
}
} else if (has_bits && has_bits_indices[i] != static_cast<uint32_t>(-1)) {
// Equivalent to: HasBit(message, field)
// Equivalent to: HasFieldSingular(message, field)
if (IsIndexInHasBitSet(has_bits, has_bits_indices[i])) {
append_to_output(field);
}
} else if (HasBit(message, field)) { // Fall back on proto3-style HasBit.
} else if (HasFieldSingular(message, field)) {
// Fall back on proto3-style HasBit.
append_to_output(field);
}
}
@ -2329,7 +2330,7 @@ Message* Reflection::MutableMessage(Message* message,
*result_holder = default_message->New(message->GetArena());
}
} else {
SetBit(message, field);
SetHasBit(message, field);
}
if (*result_holder == nullptr) {
@ -2363,9 +2364,9 @@ void Reflection::UnsafeArenaSetAllocatedMessage(
}
if (sub_message == nullptr) {
ClearBit(message, field);
ClearHasBit(message, field);
} else {
SetBit(message, field);
SetHasBit(message, field);
}
Message** sub_message_holder = MutableRaw<Message*>(message, field);
if (message->GetArena() == nullptr) {
@ -2424,7 +2425,7 @@ Message* Reflection::UnsafeArenaReleaseMessage(Message* message,
factory));
} else {
if (!(field->is_repeated() || schema_.InRealOneof(field))) {
ClearBit(message, field);
ClearHasBit(message, field);
}
if (schema_.InRealOneof(field)) {
if (HasOneofField(*message, field)) {
@ -2898,8 +2899,8 @@ void Reflection::SwapInlinedStringDonated(Message* lhs, Message* rhs,
}
// Simple accessors for manipulating has_bits_.
bool Reflection::HasBit(const Message& message,
const FieldDescriptor* field) const {
bool Reflection::HasFieldSingular(const Message& message,
const FieldDescriptor* field) const {
ABSL_DCHECK(!field->options().weak());
if (schema_.HasBitIndex(field) != static_cast<uint32_t>(-1)) {
return IsIndexInHasBitSet(GetHasBits(message), schema_.HasBitIndex(field));
@ -2962,12 +2963,13 @@ bool Reflection::HasBit(const Message& message,
// handled above; avoid warning
break;
}
ABSL_LOG(FATAL) << "Reached impossible case in HasBit().";
ABSL_LOG(FATAL) << "Reached impossible case in HasFieldSingular().";
return false;
}
}
void Reflection::SetBit(Message* message, const FieldDescriptor* field) const {
void Reflection::SetHasBit(Message* message,
const FieldDescriptor* field) const {
ABSL_DCHECK(!field->options().weak());
const uint32_t index = schema_.HasBitIndex(field);
if (index == static_cast<uint32_t>(-1)) return;
@ -2975,8 +2977,8 @@ void Reflection::SetBit(Message* message, const FieldDescriptor* field) const {
(static_cast<uint32_t>(1) << (index % 32));
}
void Reflection::ClearBit(Message* message,
const FieldDescriptor* field) const {
void Reflection::ClearHasBit(Message* message,
const FieldDescriptor* field) const {
ABSL_DCHECK(!field->options().weak());
const uint32_t index = schema_.HasBitIndex(field);
if (index == static_cast<uint32_t>(-1)) return;
@ -2984,22 +2986,22 @@ void Reflection::ClearBit(Message* message,
~(static_cast<uint32_t>(1) << (index % 32));
}
void Reflection::SwapBit(Message* message1, Message* message2,
const FieldDescriptor* field) const {
void Reflection::SwapHasBit(Message* message1, Message* message2,
const FieldDescriptor* field) const {
ABSL_DCHECK(!field->options().weak());
if (!schema_.HasHasbits()) {
return;
}
bool temp_has_bit = HasBit(*message1, field);
if (HasBit(*message2, field)) {
SetBit(message1, field);
bool temp_is_present = HasFieldSingular(*message1, field);
if (HasFieldSingular(*message2, field)) {
SetHasBit(message1, field);
} else {
ClearBit(message1, field);
ClearHasBit(message1, field);
}
if (temp_has_bit) {
SetBit(message2, field);
if (temp_is_present) {
SetHasBit(message2, field);
} else {
ClearBit(message2, field);
ClearHasBit(message2, field);
}
}
@ -3127,14 +3129,14 @@ void Reflection::SetField(Message* message, const FieldDescriptor* field,
ClearOneof(message, field->containing_oneof());
}
*MutableRaw<Type>(message, field) = value;
real_oneof ? SetOneofCase(message, field) : SetBit(message, field);
real_oneof ? SetOneofCase(message, field) : SetHasBit(message, field);
}
template <typename Type>
Type* Reflection::MutableField(Message* message,
const FieldDescriptor* field) const {
schema_.InRealOneof(field) ? SetOneofCase(message, field)
: SetBit(message, field);
: SetHasBit(message, field);
return MutableRaw<Type>(message, field);
}

@ -1234,11 +1234,17 @@ class PROTOBUF_EXPORT Reflection final {
return schema_.IsFieldInlined(field);
}
bool HasBit(const Message& message, const FieldDescriptor* field) const;
void SetBit(Message* message, const FieldDescriptor* field) const;
inline void ClearBit(Message* message, const FieldDescriptor* field) const;
inline void SwapBit(Message* message1, Message* message2,
const FieldDescriptor* field) const;
// Returns true if the field is considered to be present.
// Requires the input to be 'singular' i.e. non-extension, non-oneof, non-weak
// field.
// For explicit presence fields, a field is present iff the hasbit is set.
// For implicit presence fields, a field is present iff it is nonzero.
bool HasFieldSingular(const Message& message,
const FieldDescriptor* field) const;
void SetHasBit(Message* message, const FieldDescriptor* field) const;
inline void ClearHasBit(Message* message, const FieldDescriptor* field) const;
inline void SwapHasBit(Message* message1, Message* message2,
const FieldDescriptor* field) const;
inline const uint32_t* GetInlinedStringDonatedArray(
const Message& message) const;

@ -249,7 +249,7 @@ void ReflectionVisit::VisitFields(MessageT& message, CallbackFn&& func,
if ((has_bits[index / 32] & (1u << (index % 32))) == 0) continue;
} else {
// Skip if it has default values.
if (!reflection->HasBit(message, field)) continue;
if (!reflection->HasFieldSingular(message, field)) continue;
}
switch (field->type()) {
#define PROTOBUF_HANDLE_CASE(TYPE, NAME) \

Loading…
Cancel
Save