1313
1414#include < algorithm>
1515#include < atomic>
16+ #include < cstddef>
1617#include < cstdint>
1718#include < cstring>
1819#include < new> // IWYU pragma: keep for operator delete
@@ -1761,13 +1762,23 @@ bool CreateUnknownEnumValues(const FieldDescriptor* field) {
17611762} // namespace internal
17621763using internal::CreateUnknownEnumValues;
17631764
1764- void Reflection::ListFields (const Message& message,
1765- std::vector<const FieldDescriptor*>* output) const {
1766- output->clear ();
1767-
1768- // Optimization: The default instance never has any fields set.
1769- if (schema_.IsDefaultInstance (message)) return ;
17701765
1766+ // Common functionality shared by IsEmpty and ListFields for iterating over
1767+ // all set fields.
1768+ //
1769+ // If kForIsEmpty=true, returns 0 if the message is empty, and 1 otherwise.
1770+ //
1771+ // If kForIsEmpty=false, populates output with all filled fields. Return value
1772+ // is the last field set, or 0 if the message is empty.
1773+ template <bool kForIsEmpty , typename MaybeFieldDescriptorVec>
1774+ inline int32_t Reflection::IsEmptyOrCollectSetFields (
1775+ const Message& message,
1776+ // Cached locally rather than a member variable for performance.
1777+ const Descriptor& descriptor,
1778+ [[maybe_unused]] MaybeFieldDescriptorVec output) const {
1779+ // Output should be null only if we are not computing the full output list.
1780+ static_assert (kForIsEmpty ==
1781+ std::is_same_v<MaybeFieldDescriptorVec, std::nullptr_t >);
17711782 // Optimization: Avoid calling GetHasBits() and HasOneofField() many times
17721783 // within the field loop. We allow this violation of ReflectionSchema
17731784 // encapsulation because this function takes a noticeable about of CPU
@@ -1776,17 +1787,33 @@ void Reflection::ListFields(const Message& message,
17761787 const uint32_t * const has_bits =
17771788 schema_.HasHasbits () ? GetHasBits (message) : nullptr ;
17781789 const uint32_t * const has_bits_indices = schema_.has_bit_indices_ ;
1779- const Descriptor* const descriptor = descriptor_;
1780- output->reserve (descriptor->field_count ());
1790+ if constexpr (!kForIsEmpty ) {
1791+ output->reserve (descriptor.field_count ());
1792+ }
17811793 // Fields in messages are usually added with the increasing tags.
17821794 uint32_t last = 0 ; // UINT32_MAX if out-of-order
1783- auto append_to_output = [&last, &output](const FieldDescriptor* field) {
1784- CheckInOrder (field, &last);
1785- output->push_back (field);
1786- };
1795+ // Stifle unused variable compilation error when kForIsEmpty is true.
1796+ [[maybe_unused]] const auto append_to_output =
1797+ [&last, output](const FieldDescriptor& field) {
1798+ if constexpr (!kForIsEmpty ) {
1799+ CheckInOrder (&field, &last);
1800+ output->push_back (&field);
1801+ }
1802+ };
1803+ // Core functionality difference depending on the value of kForIsEmpty. If we
1804+ // encounter a set field, either return 1, or push it back into the vector.
1805+ #define PROTO_REFLECTION_APPEND_OR_RETURN () \
1806+ do { \
1807+ if constexpr (kForIsEmpty ) { \
1808+ return 1 ; \
1809+ } else { \
1810+ append_to_output (field); \
1811+ } \
1812+ } while (false )
1813+
17871814 int i = -1 ;
17881815 for (const FieldDescriptor& field :
1789- absl::MakeSpan (descriptor-> fields_ , last_non_weak_field_index_ + 1 )) {
1816+ absl::MakeSpan (descriptor. fields_ , last_non_weak_field_index_ + 1 )) {
17901817 ++i;
17911818 const OneofDescriptor* containing_oneof = field.containing_oneof ();
17921819 // If the hasbits for repeated fields experiment is disabled, we can
@@ -1795,7 +1822,7 @@ void Reflection::ListFields(const Message& message,
17951822 if (!internal::EnableExperimentalHintHasBitsForRepeatedFields () &&
17961823 field.is_repeated ()) {
17971824 if (FieldSize (message, &field) > 0 ) {
1798- append_to_output (&field );
1825+ PROTO_REFLECTION_APPEND_OR_RETURN ( );
17991826 }
18001827 } else if (schema_.InRealOneof (&field)) {
18011828 const uint32_t * const oneof_case_array =
@@ -1804,20 +1831,33 @@ void Reflection::ListFields(const Message& message,
18041831 // Equivalent to: HasOneofField(message, field)
18051832 if (static_cast <int64_t >(oneof_case_array[containing_oneof->index ()]) ==
18061833 field.number ()) {
1807- append_to_output (&field );
1834+ PROTO_REFLECTION_APPEND_OR_RETURN ( );
18081835 }
18091836 } else if (has_bits &&
18101837 has_bits_indices[i] != static_cast <uint32_t >(kNoHasbit )) {
18111838 // Equivalent to: HasFieldSingular(message, field)
18121839 if (IsFieldPresentGivenHasbits (message, &field, has_bits,
18131840 has_bits_indices[i])) {
1814- append_to_output (&field );
1841+ PROTO_REFLECTION_APPEND_OR_RETURN ( );
18151842 }
18161843 } else if (HasFieldWithHasbits (message, &field)) {
1817- // Fall back on proto3-style HasBit.
1818- append_to_output (&field);
1844+ PROTO_REFLECTION_APPEND_OR_RETURN ();
18191845 }
18201846 }
1847+ #undef PROTO_REFLECTION_APPEND_OR_RETURN
1848+ // Last will be 0 if no fields were encountered. Otherwise it contains the
1849+ // last encountered field.
1850+ return last;
1851+ }
1852+
1853+ void Reflection::ListFields (const Message& message,
1854+ std::vector<const FieldDescriptor*>* output) const {
1855+ output->clear ();
1856+ // Optimization: The default instance never has any fields set.
1857+ if (schema_.IsDefaultInstance (message)) return ;
1858+ const Descriptor* const descriptor = descriptor_;
1859+ uint32_t last = IsEmptyOrCollectSetFields</* kForIsEmpty=*/ false >(
1860+ message, *descriptor, output);
18211861
18221862 // Descriptors of ExtensionSet are appended in their increasing tag
18231863 // order and they are usually bigger than the field tags so if all fields are
@@ -1845,6 +1885,29 @@ void Reflection::ListFields(const Message& message,
18451885 }
18461886}
18471887
1888+ bool Reflection::IsEmptyIgnoringUnknownFieldsImpl (
1889+ const Message& message) const {
1890+ if (IsEmptyOrCollectSetFields</* kForIsEmpty=*/ true >(message, *descriptor_,
1891+ nullptr ) != 0 ) {
1892+ return false ;
1893+ }
1894+ return
1895+ !(schema_.HasExtensionSet () && !GetExtensionSet (message).IsEmpty ());
1896+ }
1897+
1898+ bool Reflection::IsEmptyIgnoringUnknownFields (const Message& message) const {
1899+ // Optimization: The default instance never has any fields set.
1900+ if (schema_.IsDefaultInstance (message)) return true ;
1901+ return IsEmptyIgnoringUnknownFieldsImpl (message);
1902+ }
1903+
1904+ bool Reflection::IsEmpty (const Message& message) const {
1905+ // Optimization: The default instance never has any fields set.
1906+ if (schema_.IsDefaultInstance (message)) return true ;
1907+ return IsEmptyIgnoringUnknownFieldsImpl (message) &&
1908+ GetUnknownFields (message).empty ();
1909+ }
1910+
18481911// -------------------------------------------------------------------
18491912
18501913#undef DEFINE_PRIMITIVE_ACCESSORS
0 commit comments