N.B.:
- This change is not intended to affect any well-defined protobuf behaviour in
an observable way.
- The wire parsing codepath is not affected.
- This change only affects the C++ protobuf implementation (other languages are
not affected).
- sizeof proto3 message objects may increase in 32-bit increments to
accommodate hasbits.
- When profiled on some of Google's largest binaries, we have seen a code size
increase of ~0.1%, which we consider to be a reasonable increase.
There are quite a few terminologies in the title:
- **singular**: a field that is not repeated, not oneof, not extension, not lazy,
just a field with a simple primitive type (number or boolean), or
string/bytes.
- **proto3**: describes behaviour consistent to the "proto3" syntax.
This is equivalent to `edition = "2023"` with
`option features.field_presence = IMPLICIT;`.
- **implicit presence**: describes behaviour consistent with "non-optional"
fields in proto3. This is described in more detail in
https://protobuf.dev/programming-guides/field_presence/#presence-in-proto3-apis
This change enables C++ proto3 objects to generate hasbits for regular proto3
(i.e. non-`optional`) fields. This code change might make certain codepaths
negligibly more efficient, but large improvement or regression is unlikely. A
larger performance improvement is expected from generating hasbits for repeated
fields -- this change will pave the way for future work there.
Hasbits in C++ will have slightly different semantics for implicit presence
fields. In the past, all hasbits are true field presence indicators. If the
hasbit is set, the field is guaranteed to be present; if the hasbit is unset,
the field is guaranteed to be missing.
This change introduces a new hasbit mode that I will call "hint hasbits",
denoted by a newly-introduced enum, `internal::cpp::HasbitMode::kHintHasbit`.
For implicit presence fields, it may be possible to mutate the field and have
it end up as a zero field, especially with `mutable_foo` APIs. To handle those
cases correctly, we unconditionally set the hasbit when `mutable_foo` is
called, then we must do an additional check for field emptiness before
serializing the field onto the wire.
PiperOrigin-RevId: 691945237