// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd // Author: kenton@google.com (Kenton Varda) // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. // // This header is logically internal, but is made public because it is used // from protocol-compiler-generated code, which may reside in other components. #ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__ #define GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__ #include #include #include #include #include "absl/base/call_once.h" #include "absl/log/absl_check.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/generated_enum_reflection.h" #include "google/protobuf/port.h" #include "google/protobuf/unknown_field_set.h" // Must be included last. #include "google/protobuf/port_def.inc" #ifdef SWIG #error "You cannot SWIG proto headers" #endif namespace google { namespace protobuf { class MapKey; class MapValueRef; class MessageLayoutInspector; class Message; struct Metadata; namespace io { class CodedOutputStream; } } // namespace protobuf } // namespace google namespace google { namespace protobuf { namespace internal { class DefaultEmptyOneof; // Defined in other files. class ExtensionSet; // extension_set.h class WeakFieldMap; // weak_field_map.h // Tag used on offsets for fields that don't have a real offset. // For example, weak message fields go into the WeakFieldMap and not in an // actual field. constexpr uint32_t kInvalidFieldOffsetTag = 0x40000000u; // Mask used on offsets for split fields. constexpr uint32_t kSplitFieldOffsetMask = 0x80000000u; constexpr uint32_t kLazyMask = 0x1u; constexpr uint32_t kInlinedMask = 0x1u; // This struct describes the internal layout of the message, hence this is // used to act on the message reflectively. // default_instance: The default instance of the message. This is only // used to obtain pointers to default instances of embedded // messages, which GetMessage() will return if the particular // sub-message has not been initialized yet. (Thus, all // embedded message fields *must* have non-null pointers // in the default instance.) // offsets: An array of ints giving the byte offsets. // For each oneof or weak field, the offset is relative to the // default_instance. These can be computed at compile time // using the // PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET() // macro. For each none oneof field, the offset is related to // the start of the message object. These can be computed at // compile time using the // PROTO2_GENERATED_MESSAGE_FIELD_OFFSET() macro. // Besides offsets for all fields, this array also contains // offsets for oneof unions. The offset of the i-th oneof union // is offsets[descriptor->field_count() + i]. // has_bit_indices: Mapping from field indexes to their index in the has // bit array. // has_bits_offset: Offset in the message of an array of uint32s of size // descriptor->field_count()/32, rounded up. This is a // bitfield where each bit indicates whether or not the // corresponding field of the message has been initialized. // The bit for field index i is obtained by the expression: // has_bits[i / 32] & (1 << (i % 32)) // unknown_fields_offset: Offset in the message of the UnknownFieldSet for // the message. // extensions_offset: Offset in the message of the ExtensionSet for the // message, or -1 if the message type has no extension // ranges. // oneof_case_offset: Offset in the message of an array of uint32s of // size descriptor->oneof_decl_count(). Each uint32_t // indicates what field is set for each oneof. // object_size: The size of a message object of this type, as measured // by sizeof(). // arena_offset: If a message doesn't have a unknown_field_set that stores // the arena, it must have a direct pointer to the arena. // weak_field_map_offset: If the message proto has weak fields, this is the // offset of _weak_field_map_ in the generated proto. Otherwise // -1. struct ReflectionSchema { public: // Size of a google::protobuf::Message object of this type. uint32_t GetObjectSize() const { return static_cast(object_size_); } bool InRealOneof(const FieldDescriptor* field) const { return field->real_containing_oneof(); } // Offset of a non-oneof field. Getting a field offset is slightly more // efficient when we know statically that it is not a oneof field. uint32_t GetFieldOffsetNonOneof(const FieldDescriptor* field) const { ABSL_DCHECK(!InRealOneof(field)); return OffsetValue(offsets_[field->index()], field->type()); } // Offset of any field. uint32_t GetFieldOffset(const FieldDescriptor* field) const { if (InRealOneof(field)) { size_t offset = static_cast(field->containing_type()->field_count()) + field->containing_oneof()->index(); return OffsetValue(offsets_[offset], field->type()); } else { return GetFieldOffsetNonOneof(field); } } bool IsFieldInlined(const FieldDescriptor* field) const { return Inlined(offsets_[field->index()], field->type()); } uint32_t GetOneofCaseOffset(const OneofDescriptor* oneof_descriptor) const { return static_cast(oneof_case_offset_) + static_cast( static_cast(oneof_descriptor->index()) * sizeof(uint32_t)); } bool HasHasbits() const { return has_bits_offset_ != -1; } // Bit index within the bit array of hasbits. Bit order is low-to-high. uint32_t HasBitIndex(const FieldDescriptor* field) const { if (has_bits_offset_ == -1) return static_cast(-1); ABSL_DCHECK(HasHasbits()); return has_bit_indices_[field->index()]; } // Byte offset of the hasbits array. uint32_t HasBitsOffset() const { ABSL_DCHECK(HasHasbits()); return static_cast(has_bits_offset_); } bool HasInlinedString() const { return inlined_string_donated_offset_ != -1; } // Bit index within the bit array of _inlined_string_donated_. Bit order is // low-to-high. uint32_t InlinedStringIndex(const FieldDescriptor* field) const { ABSL_DCHECK(HasInlinedString()); return inlined_string_indices_[field->index()]; } // Byte offset of the _inlined_string_donated_ array. uint32_t InlinedStringDonatedOffset() const { ABSL_DCHECK(HasInlinedString()); return static_cast(inlined_string_donated_offset_); } // The offset of the InternalMetadataWithArena member. // For Lite this will actually be an InternalMetadataWithArenaLite. // The schema doesn't contain enough information to distinguish between // these two cases. uint32_t GetMetadataOffset() const { return static_cast(metadata_offset_); } // Whether this message has an ExtensionSet. bool HasExtensionSet() const { return extensions_offset_ != -1; } // The offset of the ExtensionSet in this message. uint32_t GetExtensionSetOffset() const { ABSL_DCHECK(HasExtensionSet()); return static_cast(extensions_offset_); } // The off set of WeakFieldMap when the message contains weak fields. // The default is 0 for now. int GetWeakFieldMapOffset() const { return weak_field_map_offset_; } bool IsDefaultInstance(const Message& message) const { return &message == default_instance_; } // Returns a pointer to the default value for this field. The size and type // of the underlying data depends on the field's type. const void* GetFieldDefault(const FieldDescriptor* field) const { return reinterpret_cast(default_instance_) + OffsetValue(offsets_[field->index()], field->type()); } // Returns true if the field is implicitly backed by LazyField. bool IsEagerlyVerifiedLazyField(const FieldDescriptor* field) const { ABSL_DCHECK_EQ(field->type(), FieldDescriptor::TYPE_MESSAGE); (void)field; return false; } bool IsSplit() const { return split_offset_ != -1; } bool IsSplit(const FieldDescriptor* field) const { return split_offset_ != -1 && (offsets_[field->index()] & kSplitFieldOffsetMask) != 0; } // Byte offset of _split_. uint32_t SplitOffset() const { ABSL_DCHECK(IsSplit()); return static_cast(split_offset_); } uint32_t SizeofSplit() const { ABSL_DCHECK(IsSplit()); return static_cast(sizeof_split_); } bool HasWeakFields() const { return weak_field_map_offset_ > 0; } // These members are intended to be private, but we cannot actually make them // private because this prevents us from using aggregate initialization of // them, ie. // // ReflectionSchema schema = {a, b, c, d, e, ...}; // private: const Message* default_instance_; const uint32_t* offsets_; const uint32_t* has_bit_indices_; int has_bits_offset_; int metadata_offset_; int extensions_offset_; int oneof_case_offset_; int object_size_; int weak_field_map_offset_; const uint32_t* inlined_string_indices_; int inlined_string_donated_offset_; int split_offset_; int sizeof_split_; // We tag offset values to provide additional data about fields (such as // "unused" or "lazy" or "inlined"). static uint32_t OffsetValue(uint32_t v, FieldDescriptor::Type type) { if (type == FieldDescriptor::TYPE_MESSAGE || type == FieldDescriptor::TYPE_STRING || type == FieldDescriptor::TYPE_BYTES) { return v & (~kSplitFieldOffsetMask) & (~kInlinedMask) & (~kLazyMask); } return v & (~kSplitFieldOffsetMask); } static bool Inlined(uint32_t v, FieldDescriptor::Type type) { if (type == FieldDescriptor::TYPE_STRING || type == FieldDescriptor::TYPE_BYTES) { return (v & kInlinedMask) != 0u; } else { // Non string/byte fields are not inlined. return false; } } }; // Structs that the code generator emits directly to describe a message. // These should never used directly except to build a ReflectionSchema // object. // // EXPERIMENTAL: these are changing rapidly, and may completely disappear // or merge with ReflectionSchema. struct MigrationSchema { int32_t offsets_index; int32_t has_bit_indices_index; int32_t inlined_string_indices_index; int object_size; }; // This struct tries to reduce unnecessary padding. // The num_xxx might not be close to their respective pointer, but this saves // padding. struct PROTOBUF_EXPORT DescriptorTable { mutable bool is_initialized; bool is_eager; int size; // of serialized descriptor const char* descriptor; const char* filename; absl::once_flag* once; const DescriptorTable* const* deps; int num_deps; int num_messages; const MigrationSchema* schemas; const Message* const* default_instances; const uint32_t* offsets; // update the following descriptor arrays. const EnumDescriptor** file_level_enum_descriptors; const ServiceDescriptor** file_level_service_descriptors; }; // AssignDescriptors() pulls the compiled FileDescriptor from the DescriptorPool // and uses it to populate all of the global variables which store pointers to // the descriptor objects. It also constructs the reflection objects. It is // called the first time anyone calls descriptor() or GetReflection() on one of // the types defined in the file. AssignDescriptors() is thread-safe. void PROTOBUF_EXPORT AssignDescriptors(const DescriptorTable* table); // As above, but the caller did the call_once call already. void PROTOBUF_EXPORT AssignDescriptorsOnceInnerCall(const DescriptorTable* table); // These cannot be in lite so we put them in the reflection. PROTOBUF_EXPORT void UnknownFieldSetSerializer(const uint8_t* base, uint32_t offset, uint32_t tag, uint32_t has_offset, io::CodedOutputStream* output); PROTOBUF_EXPORT void InitializeFileDescriptorDefaultInstances(); PROTOBUF_EXPORT void AddDescriptors(const DescriptorTable* table); struct PROTOBUF_EXPORT AddDescriptorsRunner { explicit AddDescriptorsRunner(const DescriptorTable* table); }; // Retrieves the existing prototype out of a descriptor table. // If it doesn't exist: // - If force_build is true, asks the generated message factory for one. // - Otherwise, return null const Message* GetPrototypeForWeakDescriptor(const DescriptorTable* table, int index, bool force_build); struct DenseEnumCacheInfo { std::atomic cache; int min_val; int max_val; const EnumDescriptor* (*descriptor_fn)(); }; PROTOBUF_EXPORT const std::string& NameOfDenseEnumSlow(int v, DenseEnumCacheInfo*); // Similar to the routine NameOfEnum, this routine returns the name of an enum. // Unlike that routine, it allocates, on-demand, a block of pointers to the // std::string objects allocated by reflection to store the enum names. This // way, as long as the enum values are fairly dense, looking them up can be // very fast. This assumes all the enums fall in the range [min_val .. max_val]. template const std::string& NameOfDenseEnum(int v) { static_assert(max_val - min_val >= 0, "Too many enums between min and max."); static DenseEnumCacheInfo deci = {/* atomic ptr */ {}, min_val, max_val, descriptor_fn}; const std::string** cache = deci.cache.load(std::memory_order_acquire ); if (PROTOBUF_PREDICT_TRUE(cache != nullptr)) { if (PROTOBUF_PREDICT_TRUE(v >= min_val && v <= max_val)) { return *cache[v - min_val]; } } return NameOfDenseEnumSlow(v, &deci); } // Returns whether this type of field is stored in the split struct as a raw // pointer. PROTOBUF_EXPORT bool SplitFieldHasExtraIndirection( const FieldDescriptor* field); } // namespace internal } // namespace protobuf } // namespace google #include "google/protobuf/port_undef.inc" #endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__