| // 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 <atomic> | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <string> | |
| #include "absl/base/call_once.h" | |
| #include "absl/base/optimization.h" | |
| #include "absl/log/absl_check.h" | |
| #include "google/protobuf/descriptor.h" | |
| #include "google/protobuf/generated_enum_reflection.h" | |
| #include "google/protobuf/has_bits.h" | |
| #include "google/protobuf/message_lite.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 io | |
| } // namespace protobuf | |
| } // namespace google | |
| namespace google { | |
| namespace protobuf { | |
| namespace internal { | |
| class DefaultEmptyOneof; | |
| struct MessageGlobalsBase; | |
| struct ClassData; | |
| // Defined in other files. | |
| class ExtensionSet; // extension_set.h | |
| // Tags used in field offsets to indicate extra information about the field. | |
| // This information can't be derived from the descriptor. | |
| // We reuse tags that can't go on the same field. | |
| inline constexpr uint32_t kSplitFieldOffsetTag = 0x80000000u; | |
| inline constexpr uint32_t kLazyOffsetTag = 0x40000000u; | |
| inline constexpr uint32_t kInlinedOffsetTag = 0x40000000u; | |
| inline constexpr uint32_t kMicroStringOffsetTag = 0x20000000u; | |
| inline constexpr uint32_t kAllOffsetTags = kSplitFieldOffsetTag | | |
| kLazyOffsetTag | kInlinedOffsetTag | | |
| kMicroStringOffsetTag; | |
| // 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; | |
| int object_size; | |
| }; | |
| // 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. | |
| class ReflectionSchema { | |
| public: | |
| ReflectionSchema(const Message* default_instance, const uint32_t* offsets, | |
| const uint32_t* has_bit_indices, int has_bits_offset, | |
| int extensions_offset, int oneof_case_offset, | |
| int object_size, int split_offset, int sizeof_split); | |
| // Helper function to transform migration schema into reflection schema. | |
| static ReflectionSchema MigrationToReflectionSchema( | |
| const MessageGlobalsBase* const* message_globals, const uint32_t* offsets, | |
| MigrationSchema migration_schema); | |
| const Message* default_instance() const { return default_instance_; } | |
| // Size of a google::protobuf::Message object of this type. | |
| uint32_t GetObjectSize() const { return static_cast<uint32_t>(object_size_); } | |
| bool InRealOneof(const FieldDescriptor* field) const { | |
| return field->real_containing_oneof() != nullptr; | |
| } | |
| // Offset of any field. | |
| uint32_t GetFieldOffset(const FieldDescriptor* field) const { | |
| return OffsetValue(offsets_[field->index()]); | |
| } | |
| bool IsFieldInlined(const FieldDescriptor* field) const { | |
| return Inlined(offsets_[field->index()], field->type()); | |
| } | |
| bool IsFieldMicroString(const FieldDescriptor* field) const { | |
| return IsMicroString(offsets_[field->index()], field->type()); | |
| } | |
| uint32_t GetOneofCaseOffset(const OneofDescriptor* oneof_descriptor) const { | |
| return static_cast<uint32_t>(oneof_case_offset_) + | |
| static_cast<uint32_t>( | |
| static_cast<size_t>(oneof_descriptor->index()) * | |
| sizeof(uint32_t)); | |
| } | |
| // Returns true iff the field object has usable hasbit offset. | |
| // Note that this is not necessarily correlated with *field presence* : | |
| // Fields with implicit presence (i.e. ones that don't expose has_foo API) | |
| // can still have hasbits in their underlying implementation. | |
| bool HasHasbits() const { return has_bits_offset_ != -1; } | |
| // Bit index within the bit array of hasbits. Bit order is low-to-high. | |
| // `field_index` must be equal to field->index(). | |
| uint32_t HasBitIndex(const FieldDescriptor* field, int field_index) const { | |
| ABSL_DCHECK_EQ(field->index(), field_index); | |
| ABSL_DCHECK(!field->is_extension()); | |
| if (has_bits_offset_ == -1) return static_cast<uint32_t>(kNoHasbit); | |
| ABSL_DCHECK(HasHasbits()); | |
| return has_bit_indices_[field_index]; | |
| } | |
| // Bit index within the bit array of hasbits. Bit order is low-to-high. | |
| uint32_t HasBitIndex(const FieldDescriptor* field) const { | |
| return HasBitIndex(field, field->index()); | |
| } | |
| // Byte offset of the hasbits array. | |
| uint32_t HasBitsOffset() const { | |
| ABSL_DCHECK(HasHasbits()); | |
| return static_cast<uint32_t>(has_bits_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<uint32_t>(extensions_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<const uint8_t*>(default_instance_) + | |
| OffsetValue(offsets_[field->index()]); | |
| } | |
| // 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()] & kSplitFieldOffsetTag) != 0; | |
| } | |
| // Byte offset of _split_. | |
| uint32_t SplitOffset() const { | |
| ABSL_DCHECK(IsSplit()); | |
| return static_cast<uint32_t>(split_offset_); | |
| } | |
| uint32_t SizeofSplit() const { | |
| ABSL_DCHECK(IsSplit()); | |
| return static_cast<uint32_t>(sizeof_split_); | |
| } | |
| private: | |
| ReflectionSchema() = default; | |
| // We tag offset values to provide additional data about fields (such as | |
| // "unused" or "lazy" or "inlined"). | |
| static uint32_t OffsetValue(uint32_t v) { return v & ~kAllOffsetTags; } | |
| static bool Inlined(uint32_t v, FieldDescriptor::Type type) { | |
| if (type == FieldDescriptor::TYPE_STRING || | |
| type == FieldDescriptor::TYPE_BYTES) { | |
| return (v & kInlinedOffsetTag) != 0u; | |
| } else { | |
| // Non string/byte fields are not inlined. | |
| return false; | |
| } | |
| } | |
| static bool IsMicroString(uint32_t v, FieldDescriptor::Type type) { | |
| ABSL_DCHECK(type == FieldDescriptor::TYPE_STRING || | |
| type == FieldDescriptor::TYPE_BYTES) | |
| << type; | |
| return (v & kMicroStringOffsetTag) != 0u; | |
| } | |
| const Message* default_instance_; | |
| const uint32_t* offsets_; | |
| const uint32_t* has_bit_indices_; | |
| int has_bits_offset_; | |
| int extensions_offset_; | |
| int oneof_case_offset_; | |
| int object_size_; | |
| int split_offset_; | |
| int sizeof_split_; | |
| }; | |
| // 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 MessageGlobalsBase* const* message_globals; | |
| 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 ClassData 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 ClassData* GetClassDataForWeakDescriptor(const DescriptorTable* table, | |
| int index, bool force_build); | |
| struct DenseEnumCacheInfo { | |
| absl::once_flag loaded; | |
| std::atomic<const std::string**> 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 EnumDescriptor* (*descriptor_fn)(), int min_val, int max_val> | |
| const std::string& NameOfDenseEnum(int v) { | |
| static_assert(max_val - min_val >= 0, "Too many enums between min and max."); | |
| static DenseEnumCacheInfo deci = {/* once_flag */ {}, /* atomic ptr */ {}, | |
| min_val, max_val, descriptor_fn}; | |
| if (ABSL_PREDICT_TRUE(v >= min_val && v <= max_val)) { | |
| const std::string** cache = deci.cache.load(std::memory_order_acquire); | |
| if (ABSL_PREDICT_TRUE(cache != nullptr)) { | |
| 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__ |