diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc index 647f804d2043e..e52c1838508dc 100644 --- a/src/google/protobuf/compiler/cpp/message.cc +++ b/src/google/protobuf/compiler/cpp/message.cc @@ -208,21 +208,11 @@ bool EmitFieldNonDefaultCondition(io::Printer* p, const std::string& prefix, )cc"); } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT) { p->Emit(R"cc( - static_assert(sizeof(::uint32_t) == sizeof(float), - "Code assumes ::uint32_t and float are the same size."); - float tmp_$name$ = $prefix$_internal_$name$(); - ::uint32_t raw_$name$; - memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$)); - if (raw_$name$ != 0) { + if (!IsDefaultImplicitPresence($prefix$_internal_$name$())) { )cc"); } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { p->Emit(R"cc( - static_assert(sizeof(::uint64_t) == sizeof(double), - "Code assumes ::uint64_t and double are the same size."); - double tmp_$name$ = $prefix$_internal_$name$(); - ::uint64_t raw_$name$; - memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$)); - if (raw_$name$ != 0) { + if (!IsDefaultImplicitPresence($prefix$_internal_$name$())) { )cc"); } else { p->Emit(R"cc( diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h index 1b85aa0c6517b..54199392b4ac0 100644 --- a/src/google/protobuf/message_lite.h +++ b/src/google/protobuf/message_lite.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -506,6 +507,22 @@ class PROTOBUF_EXPORT MessageLite { return internal::InternalVisibility{}; } + // Returns true if "value" is default (0), which implicitly checks presence. + static inline bool IsDefaultImplicitPresence(float value) { + static_assert(sizeof(uint32_t) == sizeof(float), + "Code assumes uint32_t and float are the same size."); + uint32_t raw; + memcpy(&raw, &value, sizeof(value)); + return raw == 0; + } + static inline bool IsDefaultImplicitPresence(double value) { + static_assert(sizeof(uint64_t) == sizeof(double), + "Code assumes uint64_t and double are the same size."); + uint64_t raw; + memcpy(&raw, &value, sizeof(value)); + return raw == 0; + } + template PROTOBUF_ALWAYS_INLINE static T* DefaultConstruct(Arena* arena) { return static_cast(Arena::DefaultConstruct(arena));