| // 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. | |
| #include "google/protobuf/generated_message_reflection.h" | |
| #include <algorithm> | |
| #include <atomic> | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <cstring> | |
| #include <new> // IWYU pragma: keep for operator delete | |
| #include <queue> | |
| #include <string> | |
| #include <type_traits> | |
| #include <utility> | |
| #include <variant> | |
| #include <vector> | |
| #include "absl/algorithm/container.h" | |
| #include "absl/base/attributes.h" | |
| #include "absl/base/call_once.h" | |
| #include "absl/base/casts.h" | |
| #include "absl/base/const_init.h" | |
| #include "absl/container/flat_hash_set.h" | |
| #include "absl/log/absl_check.h" | |
| #include "absl/log/absl_log.h" | |
| #include "absl/strings/str_format.h" | |
| #include "absl/strings/string_view.h" | |
| #include "absl/synchronization/mutex.h" | |
| #include "absl/types/span.h" | |
| #include "google/protobuf/arena.h" | |
| #include "google/protobuf/cpp_features.pb.h" | |
| #include "google/protobuf/descriptor.h" | |
| #include "google/protobuf/descriptor.pb.h" | |
| #include "google/protobuf/descriptor_lite.h" | |
| #include "google/protobuf/extension_set.h" | |
| #include "google/protobuf/generated_enum_util.h" | |
| #include "google/protobuf/generated_message_tctable_decl.h" | |
| #include "google/protobuf/generated_message_tctable_gen.h" | |
| #include "google/protobuf/generated_message_tctable_impl.h" | |
| #include "google/protobuf/generated_message_util.h" | |
| #include "google/protobuf/has_bits.h" | |
| #include "google/protobuf/inlined_string_field.h" | |
| #include "google/protobuf/map_field.h" | |
| #include "google/protobuf/message.h" | |
| #include "google/protobuf/message_lite.h" | |
| #include "google/protobuf/micro_string.h" | |
| #include "google/protobuf/port.h" | |
| #include "google/protobuf/raw_ptr.h" | |
| #include "google/protobuf/reflection_visit_fields.h" | |
| #include "google/protobuf/repeated_field.h" | |
| #include "google/protobuf/repeated_ptr_field.h" | |
| #include "google/protobuf/unknown_field_set.h" | |
| // clang-format off | |
| #include "google/protobuf/port_def.inc" | |
| // clang-format on | |
| #define GOOGLE_PROTOBUF_HAS_ONEOF | |
| using google::protobuf::internal::ArenaStringPtr; | |
| using google::protobuf::internal::DescriptorTable; | |
| using google::protobuf::internal::ExtensionSet; | |
| using google::protobuf::internal::GenericTypeHandler; | |
| using google::protobuf::internal::InlinedStringField; | |
| using google::protobuf::internal::InternalMetadata; | |
| using google::protobuf::internal::kNoHasbit; | |
| using google::protobuf::internal::LazyField; | |
| using google::protobuf::internal::MapFieldBase; | |
| using google::protobuf::internal::MicroString; | |
| using google::protobuf::internal::MigrationSchema; | |
| using google::protobuf::internal::OnShutdownDelete; | |
| using google::protobuf::internal::ReflectionSchema; | |
| using google::protobuf::internal::RepeatedPtrFieldBase; | |
| using google::protobuf::internal::StringSpaceUsedExcludingSelfLong; | |
| using google::protobuf::internal::cpp::IsLazilyInitializedFile; | |
| namespace google { | |
| namespace protobuf { | |
| namespace { | |
| bool IsMapFieldInApi(const FieldDescriptor* field) { return field->is_map(); } | |
| bool IsMapEntry(const FieldDescriptor* field) { | |
| return (field->containing_type() != nullptr && | |
| field->containing_type()->options().map_entry()); | |
| } | |
| Message* MaybeForceCopy(Arena* arena, Message* msg) { | |
| if (arena != nullptr || msg == nullptr) return msg; | |
| Message* copy = msg->New(); | |
| copy->MergeFrom(*msg); | |
| delete msg; | |
| return copy; | |
| } | |
| } // anonymous namespace | |
| namespace internal { | |
| void InitializeFileDescriptorDefaultInstances() { | |
| #if !defined(PROTOBUF_CONSTINIT_DEFAULT_INSTANCES) | |
| static std::true_type init = | |
| (InitializeFileDescriptorDefaultInstancesSlow(), std::true_type{}); | |
| (void)init; | |
| #endif // !defined(PROTOBUF_CONSTINIT_DEFAULT_INSTANCES) | |
| } | |
| void InitializeLazyExtensionSet() { | |
| } | |
| bool ParseNamedEnum(const EnumDescriptor* PROTOBUF_NONNULL descriptor, | |
| absl::string_view name, int* PROTOBUF_NONNULL value) { | |
| const EnumValueDescriptor* d = descriptor->FindValueByName(name); | |
| if (d == nullptr) return false; | |
| *value = d->number(); | |
| return true; | |
| } | |
| const std::string& NameOfEnum(const EnumDescriptor* PROTOBUF_NONNULL descriptor, | |
| int value) { | |
| const EnumValueDescriptor* d = descriptor->FindValueByNumber(value); | |
| return (d == nullptr ? GetEmptyString() : internal::NameOfEnumAsString(d)); | |
| } | |
| // Internal helper routine for NameOfDenseEnum in the header file. | |
| // Allocates and fills a simple array of string pointers, based on | |
| // reflection information about the names of the enums. This routine | |
| // allocates max_val + 1 entries, under the assumption that all the enums | |
| // fall in the range [min_val .. max_val]. | |
| const std::string** MakeDenseEnumCache(const EnumDescriptor* desc, int min_val, | |
| int max_val) { | |
| auto* str_ptrs = | |
| new const std::string*[static_cast<size_t>(max_val - min_val + 1)](); | |
| const int count = desc->value_count(); | |
| for (int i = 0; i < count; ++i) { | |
| const int num = desc->value(i)->number(); | |
| if (str_ptrs[num - min_val] == nullptr) { | |
| // Don't over-write an existing entry, because in case of duplication, the | |
| // first one wins. | |
| str_ptrs[num - min_val] = &internal::NameOfEnumAsString(desc->value(i)); | |
| } | |
| } | |
| // Change any unfilled entries to point to the empty string. | |
| for (int i = 0; i < max_val - min_val + 1; ++i) { | |
| if (str_ptrs[i] == nullptr) str_ptrs[i] = &GetEmptyStringAlreadyInited(); | |
| } | |
| return str_ptrs; | |
| } | |
| PROTOBUF_NOINLINE const std::string& NameOfDenseEnumSlow( | |
| int v, DenseEnumCacheInfo* deci) { | |
| if (v < deci->min_val || v > deci->max_val) | |
| return GetEmptyStringAlreadyInited(); | |
| const std::string** new_cache = | |
| MakeDenseEnumCache(deci->descriptor_fn(), deci->min_val, deci->max_val); | |
| const std::string** old_cache = nullptr; | |
| if (deci->cache.compare_exchange_strong(old_cache, new_cache, | |
| std::memory_order_release, | |
| std::memory_order_acquire)) { | |
| // We successfully stored our new cache, and the old value was nullptr. | |
| return *new_cache[v - deci->min_val]; | |
| } else { | |
| // In the time it took to create our enum cache, another thread also | |
| // created one, and put it into deci->cache. So delete ours, and | |
| // use theirs instead. | |
| delete[] new_cache; | |
| return *old_cache[v - deci->min_val]; | |
| } | |
| } | |
| bool IsMatchingCType(const FieldDescriptor* field, int ctype) { | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| return ctype == FieldOptions::CORD; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| return ctype == FieldOptions::STRING; | |
| } | |
| internal::Unreachable(); | |
| } | |
| } // namespace internal | |
| // =================================================================== | |
| // Helpers for reporting usage errors (e.g. trying to use GetInt32() on | |
| // a string field). | |
| namespace { | |
| using internal::GetConstPointerAtOffset; | |
| using internal::GetConstRefAtOffset; | |
| using internal::GetPointerAtOffset; | |
| void ReportReflectionUsageError(const Descriptor* descriptor, | |
| const FieldDescriptor* field, | |
| const char* method, const char* description) { | |
| ABSL_LOG(FATAL) << "Protocol Buffer reflection usage error:\n" | |
| " Method : google::protobuf::Reflection::" | |
| << method | |
| << "\n" | |
| " Message type: " | |
| << descriptor->full_name() | |
| << "\n" | |
| " Field : " | |
| << field->full_name() | |
| << "\n" | |
| " Problem : " | |
| << description; | |
| } | |
| #ifndef NDEBUG | |
| void ReportReflectionUsageMessageError(const Descriptor* expected, | |
| const Descriptor* actual, | |
| const FieldDescriptor* field, | |
| const char* method) { | |
| ABSL_LOG(FATAL) << absl::StrFormat( | |
| "Protocol Buffer reflection usage error:\n" | |
| " Method : google::protobuf::Reflection::%s\n" | |
| " Expected type: %s\n" | |
| " Actual type : %s\n" | |
| " Field : %s\n" | |
| " Problem : Message is not the right object for reflection", | |
| method, expected->full_name(), actual->full_name(), | |
| (field != nullptr ? field->full_name() : "n/a")); | |
| } | |
| #endif | |
| const char* cpptype_names_[FieldDescriptor::MAX_CPPTYPE + 1] = { | |
| "INVALID_CPPTYPE", "CPPTYPE_INT32", "CPPTYPE_INT64", "CPPTYPE_UINT32", | |
| "CPPTYPE_UINT64", "CPPTYPE_DOUBLE", "CPPTYPE_FLOAT", "CPPTYPE_BOOL", | |
| "CPPTYPE_ENUM", "CPPTYPE_STRING", "CPPTYPE_MESSAGE"}; | |
| static void ReportReflectionUsageTypeError( | |
| const Descriptor* descriptor, const FieldDescriptor* field, | |
| const char* method, FieldDescriptor::CppType expected_type) { | |
| ABSL_LOG(FATAL) | |
| << "Protocol Buffer reflection usage error:\n" | |
| " Method : google::protobuf::Reflection::" | |
| << method | |
| << "\n" | |
| " Message type: " | |
| << descriptor->full_name() | |
| << "\n" | |
| " Field : " | |
| << field->full_name() | |
| << "\n" | |
| " Problem : Field is not the right type for this message:\n" | |
| " Expected : " | |
| << cpptype_names_[expected_type] | |
| << "\n" | |
| " Field type: " | |
| << cpptype_names_[field->cpp_type()]; | |
| } | |
| static void ReportReflectionUsageEnumTypeError( | |
| const Descriptor* descriptor, const FieldDescriptor* field, | |
| const char* method, const EnumValueDescriptor* value) { | |
| ABSL_LOG(FATAL) << "Protocol Buffer reflection usage error:\n" | |
| " Method : google::protobuf::Reflection::" | |
| << method | |
| << "\n" | |
| " Message type: " | |
| << descriptor->full_name() | |
| << "\n" | |
| " Field : " | |
| << field->full_name() | |
| << "\n" | |
| " Problem : Enum value did not match field type:\n" | |
| " Expected : " | |
| << field->enum_type()->full_name() | |
| << "\n" | |
| " Actual : " | |
| << value->full_name(); | |
| } | |
| #define USAGE_CHECK(CONDITION, METHOD, ERROR_DESCRIPTION) \ | |
| if (!(CONDITION)) \ | |
| ReportReflectionUsageError(descriptor_, field, #METHOD, ERROR_DESCRIPTION) | |
| #define USAGE_CHECK_EQ(A, B, METHOD, ERROR_DESCRIPTION) \ | |
| USAGE_CHECK((A) == (B), METHOD, ERROR_DESCRIPTION) | |
| #define USAGE_CHECK_NE(A, B, METHOD, ERROR_DESCRIPTION) \ | |
| USAGE_CHECK((A) != (B), METHOD, ERROR_DESCRIPTION) | |
| #define USAGE_CHECK_TYPE(METHOD, CPPTYPE) \ | |
| if (field->cpp_type() != FieldDescriptor::CPPTYPE_##CPPTYPE) \ | |
| ReportReflectionUsageTypeError(descriptor_, field, #METHOD, \ | |
| FieldDescriptor::CPPTYPE_##CPPTYPE) | |
| #define USAGE_CHECK_ENUM_VALUE(METHOD) \ | |
| if (value->type() != field->enum_type()) \ | |
| ReportReflectionUsageEnumTypeError(descriptor_, field, #METHOD, value) | |
| #ifdef NDEBUG | |
| // Avoid a virtual method call in optimized builds. | |
| #define USAGE_CHECK_MESSAGE(METHOD, MESSAGE) | |
| #define STATIC_USAGE_CHECK_MESSAGE(METHOD, MESSAGE) | |
| #else | |
| #define USAGE_CHECK_MESSAGE(METHOD, MESSAGE) \ | |
| if (this != (MESSAGE)->GetReflection()) \ | |
| ReportReflectionUsageMessageError(descriptor_, (MESSAGE)->GetDescriptor(), \ | |
| field, #METHOD) | |
| #define STATIC_USAGE_CHECK_MESSAGE(METHOD, MESSAGE) \ | |
| if (this != (MESSAGE)->GetReflection()) \ | |
| ReportReflectionUsageMessageError(descriptor_, (MESSAGE)->GetDescriptor(), \ | |
| /*field=*/nullptr, #METHOD) | |
| #endif | |
| #define USAGE_CHECK_MESSAGE_TYPE(METHOD) \ | |
| USAGE_CHECK_EQ(field->containing_type(), descriptor_, METHOD, \ | |
| "Field does not match message type."); | |
| #define USAGE_CHECK_SINGULAR(METHOD) \ | |
| USAGE_CHECK_NE(field->is_repeated(), true, METHOD, \ | |
| "Field is repeated; the method requires a singular field.") | |
| #define USAGE_CHECK_REPEATED(METHOD) \ | |
| USAGE_CHECK_EQ(field->is_repeated(), true, METHOD, \ | |
| "Field is singular; the method requires a repeated field.") | |
| #define USAGE_CHECK_ALL(METHOD, LABEL, CPPTYPE) \ | |
| USAGE_CHECK_MESSAGE(METHOD, &message); \ | |
| USAGE_CHECK_MESSAGE_TYPE(METHOD); \ | |
| USAGE_CHECK_##LABEL(METHOD); \ | |
| USAGE_CHECK_TYPE(METHOD, CPPTYPE) | |
| #define USAGE_MUTABLE_CHECK_ALL(METHOD, LABEL, CPPTYPE) \ | |
| USAGE_CHECK_MESSAGE(METHOD, message); \ | |
| USAGE_CHECK_MESSAGE_TYPE(METHOD); \ | |
| USAGE_CHECK_##LABEL(METHOD); \ | |
| USAGE_CHECK_TYPE(METHOD, CPPTYPE) | |
| } // namespace | |
| // =================================================================== | |
| Reflection::Reflection(const Descriptor* descriptor, | |
| const internal::ReflectionSchema& schema, | |
| const DescriptorPool* pool, MessageFactory* factory) | |
| : last_non_weak_field_index_(-1), | |
| descriptor_(descriptor), | |
| message_factory_(factory), | |
| descriptor_pool_( | |
| (pool == nullptr) ? DescriptorPool::internal_generated_pool() : pool), | |
| schema_(schema) { | |
| last_non_weak_field_index_ = descriptor_->field_count() - 1; | |
| } | |
| Reflection::~Reflection() { | |
| // No need to use sized delete. This code path is uncommon and it would not be | |
| // worth saving or recalculating the size. | |
| ::operator delete(const_cast<internal::TcParseTableBase*>(tcparse_table_)); | |
| } | |
| const UnknownFieldSet& Reflection::GetUnknownFields( | |
| const Message& message) const { | |
| STATIC_USAGE_CHECK_MESSAGE(GetUnknownFields, &message); | |
| return GetInternalMetadata(message).unknown_fields<UnknownFieldSet>( | |
| UnknownFieldSet::default_instance); | |
| } | |
| UnknownFieldSet* Reflection::MutableUnknownFields(Message* message) const { | |
| STATIC_USAGE_CHECK_MESSAGE(MutableUnknownFields, message); | |
| return MutableInternalMetadata(message) | |
| ->mutable_unknown_fields<UnknownFieldSet>(); | |
| } | |
| bool Reflection::IsLazyExtension(const Message& message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK_MESSAGE(IsLazyExtension, &message); | |
| return field->is_extension() && | |
| GetExtensionSet(message).HasLazy(field->number()); | |
| } | |
| bool Reflection::IsLazilyVerifiedLazyField(const FieldDescriptor* field) const { | |
| return false; | |
| } | |
| bool Reflection::IsEagerlyVerifiedLazyField( | |
| const FieldDescriptor* field) const { | |
| return false; | |
| } | |
| internal::field_layout::TransformValidation Reflection::GetLazyStyle( | |
| const FieldDescriptor* field) const { | |
| if (IsEagerlyVerifiedLazyField(field)) { | |
| return internal::field_layout::kTvEager; | |
| } | |
| if (IsLazilyVerifiedLazyField(field)) { | |
| return internal::field_layout::kTvLazy; | |
| } | |
| return {}; | |
| } | |
| size_t Reflection::SpaceUsedLong(const Message& message) const { | |
| STATIC_USAGE_CHECK_MESSAGE(SpaceUsedLong, &message); | |
| // object_size_ already includes the in-memory representation of each field | |
| // in the message, so we only need to account for additional memory used by | |
| // the fields. | |
| size_t total_size = schema_.GetObjectSize(); | |
| total_size += GetUnknownFields(message).SpaceUsedExcludingSelfLong(); | |
| if (schema_.HasExtensionSet()) { | |
| total_size += GetExtensionSet(message).SpaceUsedExcludingSelfLong(); | |
| } | |
| for (int i = 0; i <= last_non_weak_field_index_; i++) { | |
| const FieldDescriptor* field = descriptor_->field(i); | |
| if (field->is_repeated()) { | |
| switch (field->cpp_type()) { | |
| #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ | |
| case FieldDescriptor::CPPTYPE_##UPPERCASE: \ | |
| total_size += GetRaw<RepeatedField<LOWERCASE> >(message, field) \ | |
| .SpaceUsedExcludingSelfLong(); \ | |
| break | |
| HANDLE_TYPE(INT32, int32_t); | |
| HANDLE_TYPE(INT64, int64_t); | |
| HANDLE_TYPE(UINT32, uint32_t); | |
| HANDLE_TYPE(UINT64, uint64_t); | |
| HANDLE_TYPE(DOUBLE, double); | |
| HANDLE_TYPE(FLOAT, float); | |
| HANDLE_TYPE(BOOL, bool); | |
| HANDLE_TYPE(ENUM, int); | |
| #undef HANDLE_TYPE | |
| case FieldDescriptor::CPPTYPE_STRING: | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| total_size += GetRaw<RepeatedField<absl::Cord>>(message, field) | |
| .SpaceUsedExcludingSelfLong(); | |
| break; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| total_size += | |
| GetRaw<RepeatedPtrField<std::string> >(message, field) | |
| .SpaceUsedExcludingSelfLong(); | |
| break; | |
| } | |
| break; | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| if (IsMapFieldInApi(field)) { | |
| total_size += GetRaw<internal::MapFieldBase>(message, field) | |
| .SpaceUsedExcludingSelfLong(); | |
| } else { | |
| // We don't know which subclass of RepeatedPtrFieldBase the type is, | |
| // so we use RepeatedPtrFieldBase directly. | |
| total_size += | |
| GetRaw<RepeatedPtrFieldBase>(message, field) | |
| .SpaceUsedExcludingSelfLong<GenericTypeHandler<Message> >(); | |
| } | |
| break; | |
| } | |
| } else { | |
| if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { | |
| continue; | |
| } | |
| switch (field->cpp_type()) { | |
| case FieldDescriptor::CPPTYPE_INT32: | |
| case FieldDescriptor::CPPTYPE_INT64: | |
| case FieldDescriptor::CPPTYPE_UINT32: | |
| case FieldDescriptor::CPPTYPE_UINT64: | |
| case FieldDescriptor::CPPTYPE_DOUBLE: | |
| case FieldDescriptor::CPPTYPE_FLOAT: | |
| case FieldDescriptor::CPPTYPE_BOOL: | |
| case FieldDescriptor::CPPTYPE_ENUM: | |
| // Field is inline, so we've already counted it. | |
| break; | |
| case FieldDescriptor::CPPTYPE_STRING: { | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| if (schema_.InRealOneof(field)) { | |
| total_size += GetField<absl::Cord*>(message, field) | |
| ->EstimatedMemoryUsage(); | |
| } else { | |
| // sizeof(absl::Cord) is included to self. | |
| total_size += GetField<absl::Cord>(message, field) | |
| .EstimatedMemoryUsage() - | |
| sizeof(absl::Cord); | |
| } | |
| break; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| if (IsInlined(field)) { | |
| total_size += GetField<InlinedStringField>(message, field) | |
| .SpaceUsedExcludingSelfLong(); | |
| } else if (IsMicroString(field)) { | |
| total_size += GetField<MicroString>(message, field) | |
| .SpaceUsedExcludingSelfLong(); | |
| } else { | |
| // Initially, the string points to the default value stored | |
| // in the prototype. Only count the string if it has been | |
| // changed from the default value. | |
| // Except oneof fields, those never point to a default instance, | |
| // and there is no default instance to point to. | |
| const auto& str = GetField<ArenaStringPtr>(message, field); | |
| if (!str.IsDefault() || schema_.InRealOneof(field)) { | |
| // string fields are represented by just a pointer, so also | |
| // include sizeof(string) as well. | |
| total_size += sizeof(std::string) + | |
| StringSpaceUsedExcludingSelfLong(str.Get()); | |
| } | |
| } | |
| break; | |
| } | |
| break; | |
| } | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| if (schema_.IsDefaultInstance(message)) { | |
| // For singular fields, the prototype just stores a pointer to the | |
| // external type's prototype, so there is no extra memory usage. | |
| } else { | |
| const Message* sub_message = GetRaw<const Message*>(message, field); | |
| if (sub_message != nullptr) { | |
| total_size += sub_message->SpaceUsedLong(); | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| if (internal::DebugHardenFuzzMessageSpaceUsedLong()) { | |
| // Use both `this` and `dummy` to generate the seed so that the scale factor | |
| // is both per-object and non-predictable, but consistent across multiple | |
| // calls in the same binary. | |
| static bool dummy; | |
| uintptr_t seed = | |
| reinterpret_cast<uintptr_t>(&dummy) ^ reinterpret_cast<uintptr_t>(this); | |
| // Fuzz the size by +/- 50%. | |
| double scale = (static_cast<double>(seed % 10000) / 10000) + 0.5; | |
| return total_size * scale; | |
| } else { | |
| return total_size; | |
| } | |
| } | |
| template <bool unsafe_shallow_swap, typename FromType, typename ToType> | |
| void Reflection::InternalMoveOneofField(const FieldDescriptor* field, | |
| FromType* from, ToType* to) const { | |
| switch (field->cpp_type()) { | |
| case FieldDescriptor::CPPTYPE_INT32: | |
| to->SetInt32(from->GetInt32()); | |
| break; | |
| case FieldDescriptor::CPPTYPE_INT64: | |
| to->SetInt64(from->GetInt64()); | |
| break; | |
| case FieldDescriptor::CPPTYPE_UINT32: | |
| to->SetUint32(from->GetUint32()); | |
| break; | |
| case FieldDescriptor::CPPTYPE_UINT64: | |
| to->SetUint64(from->GetUint64()); | |
| break; | |
| case FieldDescriptor::CPPTYPE_FLOAT: | |
| to->SetFloat(from->GetFloat()); | |
| break; | |
| case FieldDescriptor::CPPTYPE_DOUBLE: | |
| to->SetDouble(from->GetDouble()); | |
| break; | |
| case FieldDescriptor::CPPTYPE_BOOL: | |
| to->SetBool(from->GetBool()); | |
| break; | |
| case FieldDescriptor::CPPTYPE_ENUM: | |
| to->SetEnum(from->GetEnum()); | |
| break; | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| if (!unsafe_shallow_swap) { | |
| to->SetMessage(from->GetMessage()); | |
| } else { | |
| to->UnsafeSetMessage(from->UnsafeGetMessage()); | |
| } | |
| break; | |
| case FieldDescriptor::CPPTYPE_STRING: | |
| if (!unsafe_shallow_swap) { | |
| to->SetString(from->GetString()); | |
| break; | |
| } | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| to->SetCord(from->GetCord()); | |
| break; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| if (IsMicroString(field)) { | |
| to->SetMicroString(from->GetMicroString()); | |
| } else { | |
| to->SetArenaStringPtr(from->GetArenaStringPtr()); | |
| } | |
| break; | |
| } | |
| break; | |
| default: | |
| ABSL_LOG(FATAL) << "unimplemented type: " << field->cpp_type(); | |
| } | |
| if (unsafe_shallow_swap) { | |
| // Not clearing oneof case after move may cause unwanted "ClearOneof" | |
| // where the residual message or string value is deleted and causes | |
| // use-after-free (only for unsafe swap). | |
| from->ClearOneofCase(); | |
| } | |
| } | |
| namespace internal { | |
| class SwapFieldHelper { | |
| public: | |
| template <bool unsafe_shallow_swap> | |
| static void SwapRepeatedStringField(const Reflection* r, Message* lhs, | |
| Message* rhs, | |
| const FieldDescriptor* field); | |
| template <bool unsafe_shallow_swap> | |
| static void SwapInlinedStrings(const Reflection* r, Message* lhs, | |
| Message* rhs, const FieldDescriptor* field); | |
| template <bool unsafe_shallow_swap> | |
| static void SwapNonInlinedStrings(const Reflection* r, Message* lhs, | |
| Message* rhs, const FieldDescriptor* field); | |
| template <bool unsafe_shallow_swap> | |
| static void SwapStringField(const Reflection* r, Message* lhs, Message* rhs, | |
| const FieldDescriptor* field); | |
| static void SwapArenaStringPtr(ArenaStringPtr* lhs, Arena* lhs_arena, | |
| ArenaStringPtr* rhs, Arena* rhs_arena); | |
| template <bool unsafe_shallow_swap> | |
| static void SwapRepeatedMessageField(const Reflection* r, Message* lhs, | |
| Message* rhs, | |
| const FieldDescriptor* field); | |
| template <bool unsafe_shallow_swap> | |
| static void SwapMessageField(const Reflection* r, Message* lhs, Message* rhs, | |
| const FieldDescriptor* field); | |
| static void SwapMessage(const Reflection* r, Message* lhs, Arena* lhs_arena, | |
| Message* rhs, Arena* rhs_arena, | |
| const FieldDescriptor* field); | |
| static void SwapNonMessageNonStringField(const Reflection* r, Message* lhs, | |
| Message* rhs, | |
| const FieldDescriptor* field); | |
| }; | |
| template <bool unsafe_shallow_swap> | |
| void SwapFieldHelper::SwapRepeatedStringField(const Reflection* r, Message* lhs, | |
| Message* rhs, | |
| const FieldDescriptor* field) { | |
| Arena* lhs_arena = lhs->GetArena(); | |
| Arena* rhs_arena = rhs->GetArena(); | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: { | |
| auto* lhs_cord = r->MutableRaw<RepeatedField<absl::Cord>>(lhs, field); | |
| auto* rhs_cord = r->MutableRaw<RepeatedField<absl::Cord>>(rhs, field); | |
| if (unsafe_shallow_swap) { | |
| lhs_cord->InternalSwap(rhs_cord); | |
| } else { | |
| lhs_cord->Swap(rhs_cord); | |
| } | |
| break; | |
| } | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: { | |
| auto* lhs_string = r->MutableRaw<RepeatedPtrFieldBase>(lhs, field); | |
| auto* rhs_string = r->MutableRaw<RepeatedPtrFieldBase>(rhs, field); | |
| if (unsafe_shallow_swap) { | |
| lhs_string->InternalSwap(rhs_string); | |
| } else { | |
| lhs_string->Swap<GenericTypeHandler<std::string>>(lhs_arena, rhs_string, | |
| rhs_arena); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| template <bool unsafe_shallow_swap> | |
| void SwapFieldHelper::SwapInlinedStrings(const Reflection* r, Message* lhs, | |
| Message* rhs, | |
| const FieldDescriptor* field) { | |
| // Inlined string field. | |
| Arena* lhs_arena = lhs->GetArena(); | |
| Arena* rhs_arena = rhs->GetArena(); | |
| auto* lhs_string = r->MutableRaw<InlinedStringField>(lhs, field); | |
| auto* rhs_string = r->MutableRaw<InlinedStringField>(rhs, field); | |
| if (unsafe_shallow_swap) { | |
| ABSL_DCHECK_EQ(lhs_arena, rhs_arena); | |
| InlinedStringField::InternalSwap(lhs_string, rhs_string, lhs_arena); | |
| } else { | |
| const std::string temp = lhs_string->Get(); | |
| lhs_string->Set(rhs_string->Get(), lhs_arena); | |
| rhs_string->Set(temp, rhs_arena); | |
| } | |
| } | |
| template <bool unsafe_shallow_swap> | |
| void SwapFieldHelper::SwapNonInlinedStrings(const Reflection* r, Message* lhs, | |
| Message* rhs, | |
| const FieldDescriptor* field) { | |
| ArenaStringPtr* lhs_string = r->MutableRaw<ArenaStringPtr>(lhs, field); | |
| ArenaStringPtr* rhs_string = r->MutableRaw<ArenaStringPtr>(rhs, field); | |
| if (unsafe_shallow_swap) { | |
| ArenaStringPtr::UnsafeShallowSwap(lhs_string, rhs_string); | |
| } else { | |
| SwapFieldHelper::SwapArenaStringPtr(lhs_string, lhs->GetArena(), // | |
| rhs_string, rhs->GetArena()); | |
| } | |
| } | |
| template <bool unsafe_shallow_swap> | |
| void SwapFieldHelper::SwapStringField(const Reflection* r, Message* lhs, | |
| Message* rhs, | |
| const FieldDescriptor* field) { | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| // Always shallow swap for Cord. | |
| std::swap(*r->MutableRaw<absl::Cord>(lhs, field), | |
| *r->MutableRaw<absl::Cord>(rhs, field)); | |
| break; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: { | |
| if (r->IsInlined(field)) { | |
| SwapFieldHelper::SwapInlinedStrings<unsafe_shallow_swap>(r, lhs, rhs, | |
| field); | |
| } else if (r->IsMicroString(field)) { | |
| auto* lhs_string = r->MutableRaw<MicroString>(lhs, field); | |
| auto* rhs_string = r->MutableRaw<MicroString>(rhs, field); | |
| auto* lhs_arena = lhs->GetArena(); | |
| auto* rhs_arena = rhs->GetArena(); | |
| if (unsafe_shallow_swap || lhs_arena == rhs_arena) { | |
| lhs_string->InternalSwap(rhs_string); | |
| } else { | |
| MicroString tmp; | |
| tmp.Set(*lhs_string, rhs_arena); | |
| lhs_string->Set(*rhs_string, lhs_arena); | |
| if (rhs_arena == nullptr) rhs_string->Destroy(); | |
| *rhs_string = tmp; | |
| } | |
| } else { | |
| SwapFieldHelper::SwapNonInlinedStrings<unsafe_shallow_swap>(r, lhs, rhs, | |
| field); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| void SwapFieldHelper::SwapArenaStringPtr(ArenaStringPtr* lhs, Arena* lhs_arena, | |
| ArenaStringPtr* rhs, | |
| Arena* rhs_arena) { | |
| if (lhs_arena == rhs_arena) { | |
| ArenaStringPtr::InternalSwap(lhs, rhs, lhs_arena); | |
| } else if (lhs->IsDefault() && rhs->IsDefault()) { | |
| // Nothing to do. | |
| } else if (lhs->IsDefault()) { | |
| lhs->Set(rhs->Get(), lhs_arena); | |
| // rhs needs to be destroyed before overwritten. | |
| rhs->Destroy(); | |
| rhs->InitDefault(); | |
| } else if (rhs->IsDefault()) { | |
| rhs->Set(lhs->Get(), rhs_arena); | |
| // lhs needs to be destroyed before overwritten. | |
| lhs->Destroy(); | |
| lhs->InitDefault(); | |
| } else { | |
| std::string temp = lhs->Get(); | |
| lhs->Set(rhs->Get(), lhs_arena); | |
| rhs->Set(std::move(temp), rhs_arena); | |
| } | |
| } | |
| template <bool unsafe_shallow_swap> | |
| void SwapFieldHelper::SwapRepeatedMessageField(const Reflection* r, | |
| Message* lhs, Message* rhs, | |
| const FieldDescriptor* field) { | |
| if (IsMapFieldInApi(field)) { | |
| auto* lhs_map = r->MutableRaw<MapFieldBase>(lhs, field); | |
| auto* rhs_map = r->MutableRaw<MapFieldBase>(rhs, field); | |
| if (unsafe_shallow_swap) { | |
| lhs_map->InternalSwap(rhs_map); | |
| } else { | |
| lhs_map->Swap(lhs->GetArena(), rhs_map, rhs->GetArena()); | |
| } | |
| } else { | |
| auto* lhs_rm = r->MutableRaw<RepeatedPtrFieldBase>(lhs, field); | |
| auto* rhs_rm = r->MutableRaw<RepeatedPtrFieldBase>(rhs, field); | |
| if (unsafe_shallow_swap) { | |
| lhs_rm->InternalSwap(rhs_rm); | |
| } else { | |
| lhs_rm->Swap<GenericTypeHandler<Message>>(lhs->GetArena(), rhs_rm, | |
| rhs->GetArena()); | |
| } | |
| } | |
| } | |
| template <bool unsafe_shallow_swap> | |
| void SwapFieldHelper::SwapMessageField(const Reflection* r, Message* lhs, | |
| Message* rhs, | |
| const FieldDescriptor* field) { | |
| if (unsafe_shallow_swap) { | |
| std::swap(*r->MutableRaw<Message*>(lhs, field), | |
| *r->MutableRaw<Message*>(rhs, field)); | |
| } else { | |
| SwapMessage(r, lhs, lhs->GetArena(), rhs, rhs->GetArena(), field); | |
| } | |
| } | |
| void SwapFieldHelper::SwapMessage(const Reflection* r, Message* lhs, | |
| Arena* lhs_arena, Message* rhs, | |
| Arena* rhs_arena, | |
| const FieldDescriptor* field) { | |
| Message** lhs_sub = r->MutableRaw<Message*>(lhs, field); | |
| Message** rhs_sub = r->MutableRaw<Message*>(rhs, field); | |
| if (*lhs_sub == *rhs_sub) return; | |
| if (internal::CanUseInternalSwap(lhs_arena, rhs_arena)) { | |
| std::swap(*lhs_sub, *rhs_sub); | |
| return; | |
| } | |
| if (*lhs_sub != nullptr && *rhs_sub != nullptr) { | |
| (*lhs_sub)->GetReflection()->Swap(*lhs_sub, *rhs_sub); | |
| } else if (*lhs_sub == nullptr && r->HasFieldWithHasbits(*rhs, field)) { | |
| *lhs_sub = (*rhs_sub)->New(lhs_arena); | |
| (*lhs_sub)->CopyFrom(**rhs_sub); | |
| r->ClearField(rhs, field); | |
| // Ensures has bit is unchanged after ClearField. | |
| r->SetHasBit(rhs, field); | |
| } else if (*rhs_sub == nullptr && r->HasFieldWithHasbits(*lhs, field)) { | |
| *rhs_sub = (*lhs_sub)->New(rhs_arena); | |
| (*rhs_sub)->CopyFrom(**lhs_sub); | |
| r->ClearField(lhs, field); | |
| // Ensures has bit is unchanged after ClearField. | |
| r->SetHasBit(lhs, field); | |
| } | |
| } | |
| void SwapFieldHelper::SwapNonMessageNonStringField( | |
| const Reflection* r, Message* lhs, Message* rhs, | |
| const FieldDescriptor* field) { | |
| switch (field->cpp_type()) { | |
| #define SWAP_VALUES(CPPTYPE, TYPE) \ | |
| case FieldDescriptor::CPPTYPE_##CPPTYPE: \ | |
| std::swap(*r->MutableRaw<TYPE>(lhs, field), \ | |
| *r->MutableRaw<TYPE>(rhs, field)); \ | |
| break; | |
| SWAP_VALUES(INT32, int32_t); | |
| SWAP_VALUES(INT64, int64_t); | |
| SWAP_VALUES(UINT32, uint32_t); | |
| SWAP_VALUES(UINT64, uint64_t); | |
| SWAP_VALUES(FLOAT, float); | |
| SWAP_VALUES(DOUBLE, double); | |
| SWAP_VALUES(BOOL, bool); | |
| SWAP_VALUES(ENUM, int); | |
| #undef SWAP_VALUES | |
| default: | |
| ABSL_LOG(FATAL) << "Unimplemented type: " << field->cpp_type(); | |
| } | |
| } | |
| } // namespace internal | |
| void Reflection::SwapField(Message* message1, Message* message2, | |
| const FieldDescriptor* field) const { | |
| if (field->is_repeated()) { | |
| switch (field->cpp_type()) { | |
| #define SWAP_ARRAYS(CPPTYPE, TYPE) \ | |
| case FieldDescriptor::CPPTYPE_##CPPTYPE: \ | |
| MutableRaw<RepeatedField<TYPE> >(message1, field) \ | |
| ->Swap(MutableRaw<RepeatedField<TYPE> >(message2, field)); \ | |
| break; | |
| SWAP_ARRAYS(INT32, int32_t); | |
| SWAP_ARRAYS(INT64, int64_t); | |
| SWAP_ARRAYS(UINT32, uint32_t); | |
| SWAP_ARRAYS(UINT64, uint64_t); | |
| SWAP_ARRAYS(FLOAT, float); | |
| SWAP_ARRAYS(DOUBLE, double); | |
| SWAP_ARRAYS(BOOL, bool); | |
| SWAP_ARRAYS(ENUM, int); | |
| #undef SWAP_ARRAYS | |
| case FieldDescriptor::CPPTYPE_STRING: | |
| internal::SwapFieldHelper::SwapRepeatedStringField<false>( | |
| this, message1, message2, field); | |
| break; | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| internal::SwapFieldHelper::SwapRepeatedMessageField<false>( | |
| this, message1, message2, field); | |
| break; | |
| default: | |
| ABSL_LOG(FATAL) << "Unimplemented type: " << field->cpp_type(); | |
| } | |
| } else { | |
| switch (field->cpp_type()) { | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| internal::SwapFieldHelper::SwapMessageField<false>(this, message1, | |
| message2, field); | |
| break; | |
| case FieldDescriptor::CPPTYPE_STRING: | |
| internal::SwapFieldHelper::SwapStringField<false>(this, message1, | |
| message2, field); | |
| break; | |
| default: | |
| internal::SwapFieldHelper::SwapNonMessageNonStringField( | |
| this, message1, message2, field); | |
| } | |
| } | |
| } | |
| void Reflection::UnsafeShallowSwapField(Message* message1, Message* message2, | |
| const FieldDescriptor* field) const { | |
| if (!field->is_repeated()) { | |
| if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | |
| internal::SwapFieldHelper::SwapMessageField<true>(this, message1, | |
| message2, field); | |
| } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { | |
| internal::SwapFieldHelper::SwapStringField<true>(this, message1, message2, | |
| field); | |
| } else { | |
| internal::SwapFieldHelper::SwapNonMessageNonStringField(this, message1, | |
| message2, field); | |
| } | |
| return; | |
| } | |
| switch (field->cpp_type()) { | |
| #define SHALLOW_SWAP_ARRAYS(CPPTYPE, TYPE) \ | |
| case FieldDescriptor::CPPTYPE_##CPPTYPE: \ | |
| MutableRaw<RepeatedField<TYPE>>(message1, field) \ | |
| ->InternalSwap(MutableRaw<RepeatedField<TYPE>>(message2, field)); \ | |
| break; | |
| SHALLOW_SWAP_ARRAYS(INT32, int32_t); | |
| SHALLOW_SWAP_ARRAYS(INT64, int64_t); | |
| SHALLOW_SWAP_ARRAYS(UINT32, uint32_t); | |
| SHALLOW_SWAP_ARRAYS(UINT64, uint64_t); | |
| SHALLOW_SWAP_ARRAYS(FLOAT, float); | |
| SHALLOW_SWAP_ARRAYS(DOUBLE, double); | |
| SHALLOW_SWAP_ARRAYS(BOOL, bool); | |
| SHALLOW_SWAP_ARRAYS(ENUM, int); | |
| #undef SHALLOW_SWAP_ARRAYS | |
| case FieldDescriptor::CPPTYPE_STRING: | |
| internal::SwapFieldHelper::SwapRepeatedStringField<true>(this, message1, | |
| message2, field); | |
| break; | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| internal::SwapFieldHelper::SwapRepeatedMessageField<true>( | |
| this, message1, message2, field); | |
| break; | |
| default: | |
| ABSL_LOG(FATAL) << "Unimplemented type: " << field->cpp_type(); | |
| } | |
| } | |
| namespace { | |
| // This type is defined outside of SwapOneofField to workaround | |
| // https://github.com/llvm/llvm-project/issues/59706 | |
| using SwapOneofFieldVariant = | |
| std::variant<int32_t, int64_t, uint32_t, uint64_t, float, double, bool, | |
| Message*, ArenaStringPtr, MicroString, absl::Cord*, | |
| std::string>; | |
| } // namespace | |
| // Swaps oneof field between lhs and rhs. If unsafe_shallow_swap is true, it | |
| // directly swaps oneof values; otherwise, it may involve copy/delete. Note that | |
| // two messages may have different oneof cases. So, it has to be done in three | |
| // steps (i.e. lhs -> temp, rhs -> lhs, temp -> rhs). | |
| template <bool unsafe_shallow_swap> | |
| void Reflection::SwapOneofField(Message* lhs, Message* rhs, | |
| const OneofDescriptor* oneof_descriptor) const { | |
| // Wraps a local variable to temporarily store oneof value. | |
| struct LocalVarWrapper { | |
| #define LOCAL_VAR_ACCESSOR(type, name) \ | |
| type Get##name() const { return std::get<type>(val); } \ | |
| void Set##name(type v) { val.emplace<type>(v); } | |
| LOCAL_VAR_ACCESSOR(int32_t, Int32); | |
| LOCAL_VAR_ACCESSOR(int64_t, Int64); | |
| LOCAL_VAR_ACCESSOR(uint32_t, Uint32); | |
| LOCAL_VAR_ACCESSOR(uint64_t, Uint64); | |
| LOCAL_VAR_ACCESSOR(float, Float); | |
| LOCAL_VAR_ACCESSOR(double, Double); | |
| LOCAL_VAR_ACCESSOR(bool, Bool); | |
| LOCAL_VAR_ACCESSOR(int, Enum); | |
| LOCAL_VAR_ACCESSOR(Message*, Message); | |
| LOCAL_VAR_ACCESSOR(ArenaStringPtr, ArenaStringPtr); | |
| LOCAL_VAR_ACCESSOR(MicroString, MicroString); | |
| LOCAL_VAR_ACCESSOR(absl::Cord*, Cord); | |
| LOCAL_VAR_ACCESSOR(std::string, String); | |
| Message* UnsafeGetMessage() const { return GetMessage(); } | |
| void UnsafeSetMessage(Message* v) { SetMessage(v); } | |
| void ClearOneofCase() {} | |
| SwapOneofFieldVariant val; | |
| }; | |
| // Wraps a message pointer to read and write a field. | |
| struct MessageWrapper { | |
| #define MESSAGE_FIELD_ACCESSOR(type, name) \ | |
| type Get##name() const { \ | |
| return reflection->GetField<type>(*message, field); \ | |
| } \ | |
| void Set##name(type v) { reflection->SetField<type>(message, field, v); } | |
| MESSAGE_FIELD_ACCESSOR(int32_t, Int32); | |
| MESSAGE_FIELD_ACCESSOR(int64_t, Int64); | |
| MESSAGE_FIELD_ACCESSOR(uint32_t, Uint32); | |
| MESSAGE_FIELD_ACCESSOR(uint64_t, Uint64); | |
| MESSAGE_FIELD_ACCESSOR(float, Float); | |
| MESSAGE_FIELD_ACCESSOR(double, Double); | |
| MESSAGE_FIELD_ACCESSOR(bool, Bool); | |
| MESSAGE_FIELD_ACCESSOR(int, Enum); | |
| MESSAGE_FIELD_ACCESSOR(ArenaStringPtr, ArenaStringPtr); | |
| MESSAGE_FIELD_ACCESSOR(MicroString, MicroString); | |
| MESSAGE_FIELD_ACCESSOR(absl::Cord*, Cord); | |
| std::string GetString() const { | |
| return reflection->GetString(*message, field); | |
| } | |
| void SetString(const std::string& v) { | |
| reflection->SetString(message, field, v); | |
| } | |
| Message* GetMessage() const { | |
| return reflection->ReleaseMessage(message, field); | |
| } | |
| void SetMessage(Message* v) { | |
| reflection->SetAllocatedMessage(message, v, field); | |
| } | |
| Message* UnsafeGetMessage() const { | |
| return reflection->UnsafeArenaReleaseMessage(message, field); | |
| } | |
| void UnsafeSetMessage(Message* v) { | |
| reflection->UnsafeArenaSetAllocatedMessage(message, v, field); | |
| } | |
| void ClearOneofCase() { | |
| *reflection->MutableOneofCase(message, field->containing_oneof()) = 0; | |
| } | |
| const Reflection* reflection; | |
| Message* message; | |
| const FieldDescriptor* field; | |
| }; | |
| ABSL_DCHECK(!oneof_descriptor->is_synthetic()); | |
| uint32_t oneof_case_lhs = GetOneofCase(*lhs, oneof_descriptor); | |
| uint32_t oneof_case_rhs = GetOneofCase(*rhs, oneof_descriptor); | |
| LocalVarWrapper temp; | |
| MessageWrapper lhs_wrapper, rhs_wrapper; | |
| const FieldDescriptor* field_lhs = nullptr; | |
| // lhs --> temp | |
| if (oneof_case_lhs > 0) { | |
| field_lhs = descriptor_->FindFieldByNumber(oneof_case_lhs); | |
| lhs_wrapper = {this, lhs, field_lhs}; | |
| InternalMoveOneofField<unsafe_shallow_swap>(field_lhs, &lhs_wrapper, &temp); | |
| } | |
| // rhs --> lhs | |
| if (oneof_case_rhs > 0) { | |
| const FieldDescriptor* f = descriptor_->FindFieldByNumber(oneof_case_rhs); | |
| lhs_wrapper = {this, lhs, f}; | |
| rhs_wrapper = {this, rhs, f}; | |
| InternalMoveOneofField<unsafe_shallow_swap>(f, &rhs_wrapper, &lhs_wrapper); | |
| } else if (!unsafe_shallow_swap) { | |
| ClearOneof(lhs, oneof_descriptor); | |
| } | |
| // temp --> rhs | |
| if (oneof_case_lhs > 0) { | |
| rhs_wrapper = {this, rhs, field_lhs}; | |
| InternalMoveOneofField<unsafe_shallow_swap>(field_lhs, &temp, &rhs_wrapper); | |
| } else if (!unsafe_shallow_swap) { | |
| ClearOneof(rhs, oneof_descriptor); | |
| } | |
| if (unsafe_shallow_swap) { | |
| *MutableOneofCase(lhs, oneof_descriptor) = oneof_case_rhs; | |
| *MutableOneofCase(rhs, oneof_descriptor) = oneof_case_lhs; | |
| } | |
| } | |
| void Reflection::Swap(Message* lhs, Message* rhs) const { | |
| if (lhs == rhs) return; | |
| Arena* lhs_arena = lhs->GetArena(); | |
| Arena* rhs_arena = rhs->GetArena(); | |
| // TODO: Other Reflection methods should probably check this too. | |
| ABSL_CHECK_EQ(lhs->GetReflection(), this) | |
| << "First argument to Swap() (of type \"" | |
| << lhs->GetDescriptor()->full_name() | |
| << "\") is not compatible with this reflection object (which is for type " | |
| "\"" | |
| << descriptor_->full_name() | |
| << "\"). Note that the exact same class is required; not just the same " | |
| "descriptor."; | |
| ABSL_CHECK_EQ(rhs->GetReflection(), this) | |
| << "Second argument to Swap() (of type \"" | |
| << rhs->GetDescriptor()->full_name() | |
| << "\") is not compatible with this reflection object (which is for type " | |
| "\"" | |
| << descriptor_->full_name() | |
| << "\"). Note that the exact same class is required; not just the same " | |
| "descriptor."; | |
| // Check that both messages are in the same arena (or both on the heap). We | |
| // need to copy all data if not, due to ownership semantics. | |
| if (!internal::CanUseInternalSwap(lhs_arena, rhs_arena)) { | |
| // One of the two is guaranteed to have an arena. Switch things around | |
| // to guarantee that lhs has an arena. | |
| Arena* arena = lhs_arena; | |
| if (arena == nullptr) { | |
| arena = rhs_arena; | |
| std::swap(lhs, rhs); // Swapping names for pointers! | |
| } | |
| Message* temp = lhs->New(arena); | |
| temp->MergeFrom(*rhs); | |
| rhs->CopyFrom(*lhs); | |
| if (internal::DebugHardenForceCopyInSwap()) { | |
| lhs->CopyFrom(*temp); | |
| if (arena == nullptr) delete temp; | |
| } else { | |
| Swap(lhs, temp); | |
| } | |
| return; | |
| } | |
| UnsafeArenaSwap(lhs, rhs); | |
| } | |
| template <bool unsafe_shallow_swap> | |
| void Reflection::SwapFieldsImpl( | |
| Message* message1, Message* message2, | |
| const std::vector<const FieldDescriptor*>& fields) const { | |
| if (message1 == message2) return; | |
| // TODO: Other Reflection methods should probably check this too. | |
| ABSL_CHECK_EQ(message1->GetReflection(), this) | |
| << "First argument to SwapFields() (of type \"" | |
| << message1->GetDescriptor()->full_name() | |
| << "\") is not compatible with this reflection object (which is for type " | |
| "\"" | |
| << descriptor_->full_name() | |
| << "\"). Note that the exact same class is required; not just the same " | |
| "descriptor."; | |
| ABSL_CHECK_EQ(message2->GetReflection(), this) | |
| << "Second argument to SwapFields() (of type \"" | |
| << message2->GetDescriptor()->full_name() | |
| << "\") is not compatible with this reflection object (which is for type " | |
| "\"" | |
| << descriptor_->full_name() | |
| << "\"). Note that the exact same class is required; not just the same " | |
| "descriptor."; | |
| absl::flat_hash_set<int> swapped_oneof; | |
| for (const auto* field : fields) { | |
| if (field->is_extension()) { | |
| if constexpr (unsafe_shallow_swap) { | |
| MutableExtensionSet(message1)->UnsafeShallowSwapExtension( | |
| message1->GetArena(), MutableExtensionSet(message2), | |
| field->number()); | |
| } else { | |
| const Message* prototype = | |
| message_factory_->GetPrototype(message1->GetDescriptor()); | |
| MutableExtensionSet(message1)->SwapExtension( | |
| message1->GetArena(), prototype, MutableExtensionSet(message2), | |
| message2->GetArena(), field->number()); | |
| } | |
| continue; | |
| } else if (schema_.InRealOneof(field)) { | |
| int oneof_index = field->containing_oneof()->index(); | |
| // Only swap the oneof field once. | |
| if (swapped_oneof.insert(oneof_index).second) { | |
| SwapOneofField<unsafe_shallow_swap>(message1, message2, | |
| field->containing_oneof()); | |
| } | |
| continue; | |
| } | |
| // Swap field. | |
| if constexpr (unsafe_shallow_swap) { | |
| UnsafeShallowSwapField(message1, message2, field); | |
| } else { | |
| SwapField(message1, message2, field); | |
| } | |
| // If the hasbits for repeated fields experiment is disabled, we can | |
| // skip repeated fields since we know they don't have hasbits. | |
| if (!internal::EnableExperimentalHintHasBitsForRepeatedFields() && | |
| field->is_repeated()) { | |
| continue; | |
| } | |
| // Swap has bit. We have already checked for oneof already. This has to | |
| // be done after SwapField, because SwapField may depend on the | |
| // information in has bits. | |
| NaiveSwapHasBit(message1, message2, field); | |
| } | |
| } | |
| template void Reflection::SwapFieldsImpl<true>( | |
| Message* message1, Message* message2, | |
| const std::vector<const FieldDescriptor*>& fields) const; | |
| template void Reflection::SwapFieldsImpl<false>( | |
| Message* message1, Message* message2, | |
| const std::vector<const FieldDescriptor*>& fields) const; | |
| void Reflection::SwapFields( | |
| Message* message1, Message* message2, | |
| const std::vector<const FieldDescriptor*>& fields) const { | |
| SwapFieldsImpl<false>(message1, message2, fields); | |
| } | |
| void Reflection::UnsafeShallowSwapFields( | |
| Message* message1, Message* message2, | |
| const std::vector<const FieldDescriptor*>& fields) const { | |
| ABSL_DCHECK_EQ(message1->GetArena(), message2->GetArena()); | |
| SwapFieldsImpl<true>(message1, message2, fields); | |
| } | |
| void Reflection::UnsafeArenaSwapFields( | |
| Message* lhs, Message* rhs, | |
| const std::vector<const FieldDescriptor*>& fields) const { | |
| ABSL_DCHECK_EQ(lhs->GetArena(), rhs->GetArena()); | |
| UnsafeShallowSwapFields(lhs, rhs, fields); | |
| } | |
| // ------------------------------------------------------------------- | |
| bool Reflection::HasField(const Message& message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK_MESSAGE(HasField, &message); | |
| USAGE_CHECK_MESSAGE_TYPE(HasField); | |
| if (field->is_extension()) { | |
| const auto& ext = GetExtensionSet(message); | |
| return field->is_repeated() ? ext.ExtensionSize(field->number()) != 0 | |
| : ext.Has(field->number()); | |
| } else { | |
| if (schema_.InRealOneof(field)) { | |
| return HasOneofField(message, field); | |
| } else { | |
| return HasFieldWithHasbits(message, field); | |
| } | |
| } | |
| } | |
| void Reflection::UnsafeArenaSwap(Message* lhs, Message* rhs) const { | |
| ABSL_DCHECK_EQ(lhs->GetArena(), rhs->GetArena()); | |
| InternalSwap(lhs, rhs); | |
| } | |
| void Reflection::InternalSwap(Message* lhs, Message* rhs) const { | |
| if (lhs == rhs) return; | |
| MutableInternalMetadata(lhs)->InternalSwap(MutableInternalMetadata(rhs)); | |
| for (int i = 0; i <= last_non_weak_field_index_; i++) { | |
| const FieldDescriptor* field = descriptor_->field(i); | |
| if (schema_.InRealOneof(field)) continue; | |
| if (schema_.IsSplit(field)) { | |
| continue; | |
| } | |
| UnsafeShallowSwapField(lhs, rhs, field); | |
| } | |
| if (schema_.IsSplit()) { | |
| std::swap(*MutableSplitField(lhs), *MutableSplitField(rhs)); | |
| } | |
| const int oneof_decl_count = descriptor_->real_oneof_decl_count(); | |
| for (int i = 0; i < oneof_decl_count; i++) { | |
| const OneofDescriptor* oneof = descriptor_->real_oneof_decl(i); | |
| SwapOneofField<true>(lhs, rhs, oneof); | |
| } | |
| // Swapping bits need to happen after swapping fields, because the latter may | |
| // depend on the has bit information. | |
| if (schema_.HasHasbits()) { | |
| uint32_t* lhs_has_bits = MutableHasBits(lhs); | |
| uint32_t* rhs_has_bits = MutableHasBits(rhs); | |
| uint32_t max_has_bit_index = 0; | |
| for (int i = 0; i < descriptor_->field_count(); i++) { | |
| const FieldDescriptor* field = descriptor_->field(i); | |
| const uint32_t has_bit_index = schema_.HasBitIndex(field); | |
| if (has_bit_index != static_cast<uint32_t>(kNoHasbit)) { | |
| max_has_bit_index = std::max(max_has_bit_index, has_bit_index); | |
| } | |
| } | |
| int has_bits_size = max_has_bit_index / 32 + 1; | |
| for (int i = 0; i < has_bits_size; i++) { | |
| std::swap(lhs_has_bits[i], rhs_has_bits[i]); | |
| } | |
| } | |
| if (schema_.HasExtensionSet()) { | |
| MutableExtensionSet(lhs)->InternalSwap(MutableExtensionSet(rhs)); | |
| } | |
| } | |
| void Reflection::MaybePoisonAfterClear(Message& root) const { | |
| struct MemBlock { | |
| explicit MemBlock(Message& msg) | |
| : ptr(static_cast<void*>(&msg)), size(GetSize(msg)) {} | |
| static uint32_t GetSize(const Message& msg) { | |
| return msg.GetReflection()->schema_.GetObjectSize(); | |
| } | |
| void* ptr; | |
| uint32_t size; | |
| }; | |
| bool heap_alloc = root.GetArena() == nullptr; | |
| std::vector<MemBlock> nodes; | |
| nodes.emplace_back(root); | |
| std::queue<Message*> queue; | |
| queue.push(&root); | |
| while (!queue.empty() && !heap_alloc) { | |
| Message* curr = queue.front(); | |
| queue.pop(); | |
| internal::VisitMutableMessageFields(*curr, [&](Message& msg) { | |
| if (msg.GetArena() == nullptr) { | |
| heap_alloc = true; | |
| return; | |
| } | |
| nodes.emplace_back(msg); | |
| // Also visits child messages. | |
| queue.push(&msg); | |
| }); | |
| } | |
| root.Clear(); | |
| // Heap allocated oneof messages will be freed on clear. So, poisoning | |
| // afterwards may cause use-after-free. Bailout. | |
| if (heap_alloc) return; | |
| for (auto it : nodes) { | |
| (void)it; | |
| internal::PoisonMemoryRegion(it.ptr, it.size); | |
| } | |
| } | |
| int Reflection::FieldSize(const Message& message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK_MESSAGE(FieldSize, &message); | |
| USAGE_CHECK_MESSAGE_TYPE(FieldSize); | |
| USAGE_CHECK_REPEATED(FieldSize); | |
| if (field->is_extension()) { | |
| return GetExtensionSet(message).ExtensionSize(field->number()); | |
| } else { | |
| switch (field->cpp_type()) { | |
| #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ | |
| case FieldDescriptor::CPPTYPE_##UPPERCASE: \ | |
| return GetRaw<RepeatedField<LOWERCASE> >(message, field).size() | |
| HANDLE_TYPE(INT32, int32_t); | |
| HANDLE_TYPE(INT64, int64_t); | |
| HANDLE_TYPE(UINT32, uint32_t); | |
| HANDLE_TYPE(UINT64, uint64_t); | |
| HANDLE_TYPE(DOUBLE, double); | |
| HANDLE_TYPE(FLOAT, float); | |
| HANDLE_TYPE(BOOL, bool); | |
| HANDLE_TYPE(ENUM, int); | |
| #undef HANDLE_TYPE | |
| case FieldDescriptor::CPPTYPE_STRING: | |
| if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) { | |
| return GetRaw<RepeatedField<absl::Cord> >(message, field).size(); | |
| } | |
| ABSL_FALLTHROUGH_INTENDED; | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| if (IsMapFieldInApi(field)) { | |
| const internal::MapFieldBase& map = | |
| GetRaw<MapFieldBase>(message, field); | |
| if (map.IsRepeatedFieldValid()) { | |
| return map.GetRepeatedField().size(); | |
| } else { | |
| // No need to materialize the repeated field if it is out of sync: | |
| // its size will be the same as the map's size. | |
| return map.size(); | |
| } | |
| } else { | |
| return GetRaw<RepeatedPtrFieldBase>(message, field).size(); | |
| } | |
| } | |
| ABSL_LOG(FATAL) << "Can't get here."; | |
| return 0; | |
| } | |
| } | |
| void Reflection::ClearField(Message* message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK_MESSAGE(ClearField, message); | |
| USAGE_CHECK_MESSAGE_TYPE(ClearField); | |
| if (field->is_extension()) { | |
| MutableExtensionSet(message)->ClearExtension(field->number()); | |
| return; | |
| } else if (schema_.InRealOneof(field)) { | |
| ClearOneofField(message, field); | |
| return; | |
| } else if (!HasFieldWithHasbits(*message, field)) { | |
| // Clear the has bit even if the field is not present. If this is an empty | |
| // repeated field with a set has bit, we want to clear the has bit. | |
| ClearHasBit(message, field); | |
| return; | |
| } | |
| ClearHasBit(message, field); | |
| if (field->is_repeated()) { | |
| switch (field->cpp_type()) { | |
| #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ | |
| case FieldDescriptor::CPPTYPE_##UPPERCASE: \ | |
| MutableRaw<RepeatedField<LOWERCASE>>(message, field)->Clear(); \ | |
| break | |
| HANDLE_TYPE(INT32, int32_t); | |
| HANDLE_TYPE(INT64, int64_t); | |
| HANDLE_TYPE(UINT32, uint32_t); | |
| HANDLE_TYPE(UINT64, uint64_t); | |
| HANDLE_TYPE(DOUBLE, double); | |
| HANDLE_TYPE(FLOAT, float); | |
| HANDLE_TYPE(BOOL, bool); | |
| HANDLE_TYPE(ENUM, int); | |
| #undef HANDLE_TYPE | |
| case FieldDescriptor::CPPTYPE_STRING: { | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| MutableRaw<RepeatedField<absl::Cord>>(message, field)->Clear(); | |
| break; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| MutableRaw<RepeatedPtrField<std::string>>(message, field)->Clear(); | |
| break; | |
| } | |
| break; | |
| } | |
| case FieldDescriptor::CPPTYPE_MESSAGE: { | |
| if (IsMapFieldInApi(field)) { | |
| MutableRaw<MapFieldBase>(message, field)->Clear(); | |
| } else { | |
| // We don't know which subclass of RepeatedPtrFieldBase the type | |
| // is, so we use RepeatedPtrFieldBase directly. | |
| MutableRaw<RepeatedPtrFieldBase>(message, field) | |
| ->Clear<GenericTypeHandler<Message>>(); | |
| } | |
| break; | |
| } | |
| } | |
| } else { | |
| // We need to set the field back to its default value. | |
| switch (field->cpp_type()) { | |
| #define CLEAR_TYPE(CPPTYPE, TYPE) \ | |
| case FieldDescriptor::CPPTYPE_##CPPTYPE: \ | |
| *MutableRaw<TYPE>(message, field) = field->default_value_##TYPE(); \ | |
| break; | |
| CLEAR_TYPE(INT32, int32_t); | |
| CLEAR_TYPE(INT64, int64_t); | |
| CLEAR_TYPE(UINT32, uint32_t); | |
| CLEAR_TYPE(UINT64, uint64_t); | |
| CLEAR_TYPE(FLOAT, float); | |
| CLEAR_TYPE(DOUBLE, double); | |
| CLEAR_TYPE(BOOL, bool); | |
| #undef CLEAR_TYPE | |
| case FieldDescriptor::CPPTYPE_ENUM: | |
| *MutableRaw<int>(message, field) = | |
| field->default_value_enum()->number(); | |
| break; | |
| case FieldDescriptor::CPPTYPE_STRING: { | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| if (field->has_default_value()) { | |
| *MutableRaw<absl::Cord>(message, field) = | |
| field->default_value_string(); | |
| } else { | |
| MutableRaw<absl::Cord>(message, field)->Clear(); | |
| } | |
| break; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| if (IsInlined(field)) { | |
| // Currently, string with default value can't be inlined. So we | |
| // don't have to handle default value here. | |
| MutableRaw<InlinedStringField>(message, field)->ClearToEmpty(); | |
| } else if (IsMicroString(field)) { | |
| if (field->has_default_value()) { | |
| MutableRaw<MicroString>(message, field) | |
| ->ClearToDefault( | |
| GetRaw<MicroString>(*schema_.default_instance_, field), | |
| message->GetArena()); | |
| } else { | |
| MutableRaw<MicroString>(message, field)->Clear(); | |
| } | |
| } else { | |
| auto* str = MutableRaw<ArenaStringPtr>(message, field); | |
| str->Destroy(); | |
| str->InitDefault(); | |
| } | |
| break; | |
| } | |
| break; | |
| } | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| (*MutableRaw<Message*>(message, field))->Clear(); | |
| break; | |
| } | |
| } | |
| } | |
| void Reflection::RemoveLast(Message* message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK_MESSAGE(RemoveLast, message); | |
| USAGE_CHECK_MESSAGE_TYPE(RemoveLast); | |
| USAGE_CHECK_REPEATED(RemoveLast); | |
| if (field->is_extension()) { | |
| MutableExtensionSet(message)->RemoveLast(field->number()); | |
| } else { | |
| switch (field->cpp_type()) { | |
| #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ | |
| case FieldDescriptor::CPPTYPE_##UPPERCASE: \ | |
| MutableRaw<RepeatedField<LOWERCASE> >(message, field)->RemoveLast(); \ | |
| break | |
| HANDLE_TYPE(INT32, int32_t); | |
| HANDLE_TYPE(INT64, int64_t); | |
| HANDLE_TYPE(UINT32, uint32_t); | |
| HANDLE_TYPE(UINT64, uint64_t); | |
| HANDLE_TYPE(DOUBLE, double); | |
| HANDLE_TYPE(FLOAT, float); | |
| HANDLE_TYPE(BOOL, bool); | |
| HANDLE_TYPE(ENUM, int); | |
| #undef HANDLE_TYPE | |
| case FieldDescriptor::CPPTYPE_STRING: | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| MutableRaw<RepeatedField<absl::Cord>>(message, field)->RemoveLast(); | |
| break; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| MutableRaw<RepeatedPtrField<std::string> >(message, field) | |
| ->RemoveLast(); | |
| break; | |
| } | |
| break; | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| if (IsMapFieldInApi(field)) { | |
| MutableRaw<MapFieldBase>(message, field) | |
| ->MutableRepeatedField() | |
| ->RemoveLast<GenericTypeHandler<Message> >(); | |
| } else { | |
| MutableRaw<RepeatedPtrFieldBase>(message, field) | |
| ->RemoveLast<GenericTypeHandler<Message> >(); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| Message* Reflection::ReleaseLast(Message* message, | |
| const FieldDescriptor* field) const { | |
| USAGE_MUTABLE_CHECK_ALL(ReleaseLast, REPEATED, MESSAGE); | |
| Arena* arena = message->GetArena(); | |
| Message* released; | |
| if (field->is_extension()) { | |
| released = static_cast<Message*>( | |
| MutableExtensionSet(message)->ReleaseLast(arena, field->number())); | |
| } else { | |
| if (IsMapFieldInApi(field)) { | |
| released = MutableRaw<MapFieldBase>(message, field) | |
| ->MutableRepeatedField() | |
| ->ReleaseLast<GenericTypeHandler<Message>>(arena); | |
| } else { | |
| released = MutableRaw<RepeatedPtrFieldBase>(message, field) | |
| ->ReleaseLast<GenericTypeHandler<Message>>(arena); | |
| } | |
| } | |
| if (internal::DebugHardenForceCopyInRelease()) { | |
| return MaybeForceCopy(arena, released); | |
| } else { | |
| return released; | |
| } | |
| } | |
| Message* Reflection::UnsafeArenaReleaseLast( | |
| Message* message, const FieldDescriptor* field) const { | |
| USAGE_MUTABLE_CHECK_ALL(UnsafeArenaReleaseLast, REPEATED, MESSAGE); | |
| if (field->is_extension()) { | |
| return static_cast<Message*>( | |
| MutableExtensionSet(message)->UnsafeArenaReleaseLast( | |
| message->GetArena(), field->number())); | |
| } else { | |
| if (IsMapFieldInApi(field)) { | |
| return MutableRaw<MapFieldBase>(message, field) | |
| ->MutableRepeatedField() | |
| ->UnsafeArenaReleaseLast<GenericTypeHandler<Message>>(); | |
| } else { | |
| return MutableRaw<RepeatedPtrFieldBase>(message, field) | |
| ->UnsafeArenaReleaseLast<GenericTypeHandler<Message>>(); | |
| } | |
| } | |
| } | |
| void Reflection::SwapElements(Message* message, const FieldDescriptor* field, | |
| int index1, int index2) const { | |
| USAGE_CHECK_MESSAGE(Swap, message); | |
| USAGE_CHECK_MESSAGE_TYPE(Swap); | |
| USAGE_CHECK_REPEATED(Swap); | |
| if (field->is_extension()) { | |
| MutableExtensionSet(message)->SwapElements(field->number(), index1, index2); | |
| } else { | |
| switch (field->cpp_type()) { | |
| #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ | |
| case FieldDescriptor::CPPTYPE_##UPPERCASE: \ | |
| MutableRaw<RepeatedField<LOWERCASE> >(message, field) \ | |
| ->SwapElements(index1, index2); \ | |
| break | |
| HANDLE_TYPE(INT32, int32_t); | |
| HANDLE_TYPE(INT64, int64_t); | |
| HANDLE_TYPE(UINT32, uint32_t); | |
| HANDLE_TYPE(UINT64, uint64_t); | |
| HANDLE_TYPE(DOUBLE, double); | |
| HANDLE_TYPE(FLOAT, float); | |
| HANDLE_TYPE(BOOL, bool); | |
| HANDLE_TYPE(ENUM, int); | |
| #undef HANDLE_TYPE | |
| case FieldDescriptor::CPPTYPE_STRING: | |
| if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) { | |
| MutableRaw<RepeatedField<absl::Cord> >(message, field) | |
| ->SwapElements(index1, index2); | |
| break; | |
| } | |
| ABSL_FALLTHROUGH_INTENDED; | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| if (IsMapFieldInApi(field)) { | |
| MutableRaw<MapFieldBase>(message, field) | |
| ->MutableRepeatedField() | |
| ->SwapElements(index1, index2); | |
| } else { | |
| MutableRaw<RepeatedPtrFieldBase>(message, field) | |
| ->SwapElements(index1, index2); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| namespace { | |
| // Comparison functor for sorting FieldDescriptors by field number. | |
| struct FieldNumberSorter { | |
| bool operator()(const FieldDescriptor* left, | |
| const FieldDescriptor* right) const { | |
| return left->number() < right->number(); | |
| } | |
| }; | |
| bool IsIndexInHasBitSet(const uint32_t* has_bit_set, uint32_t has_bit_index) { | |
| ABSL_DCHECK_NE(has_bit_index, ~0u); | |
| return ((has_bit_set[has_bit_index / 32] >> (has_bit_index % 32)) & | |
| static_cast<uint32_t>(1)) != 0; | |
| } | |
| void CheckInOrder(const FieldDescriptor* field, uint32_t* last) { | |
| *last = *last <= static_cast<uint32_t>(field->number()) | |
| ? static_cast<uint32_t>(field->number()) | |
| : UINT32_MAX; | |
| } | |
| } // namespace | |
| namespace internal { | |
| bool CreateUnknownEnumValues(const FieldDescriptor* field) { | |
| bool open_enum = false; | |
| return !field->legacy_enum_field_treated_as_closed() || open_enum; | |
| } | |
| } // namespace internal | |
| using internal::CreateUnknownEnumValues; | |
| // Common functionality shared by IsEmpty and ListFields for iterating over | |
| // all set fields. | |
| // | |
| // If kForIsEmpty=true, returns 0 if the message is empty, and 1 otherwise. | |
| // | |
| // If kForIsEmpty=false, populates output with all filled fields. Return value | |
| // is the last field set, or 0 if the message is empty. | |
| template <bool kForIsEmpty, typename MaybeFieldDescriptorVec> | |
| inline int32_t Reflection::IsEmptyOrCollectSetFields( | |
| const Message& message, | |
| // Cached locally rather than a member variable for performance. | |
| const Descriptor& descriptor, | |
| [[maybe_unused]] MaybeFieldDescriptorVec output) const { | |
| // Output should be null only if we are not computing the full output list. | |
| static_assert(kForIsEmpty == | |
| std::is_same_v<MaybeFieldDescriptorVec, std::nullptr_t>); | |
| // Optimization: Avoid calling GetHasBits() and HasOneofField() many times | |
| // within the field loop. We allow this violation of ReflectionSchema | |
| // encapsulation because this function takes a noticeable about of CPU | |
| // fleetwide and properly allowing this optimization through public interfaces | |
| // seems more trouble than it is worth. | |
| const uint32_t* const has_bits = | |
| schema_.HasHasbits() ? GetHasBits(message) : nullptr; | |
| const uint32_t* const has_bits_indices = schema_.has_bit_indices_; | |
| if constexpr (!kForIsEmpty) { | |
| output->reserve(descriptor.field_count()); | |
| } | |
| // Fields in messages are usually added with the increasing tags. | |
| uint32_t last = 0; // UINT32_MAX if out-of-order | |
| // Stifle unused variable compilation error when kForIsEmpty is true. | |
| [[maybe_unused]] const auto append_to_output = | |
| [&last, output](const FieldDescriptor& field) { | |
| if constexpr (!kForIsEmpty) { | |
| CheckInOrder(&field, &last); | |
| output->push_back(&field); | |
| } | |
| }; | |
| // Core functionality difference depending on the value of kForIsEmpty. If we | |
| // encounter a set field, either return 1, or push it back into the vector. | |
| #define PROTO_REFLECTION_APPEND_OR_RETURN() \ | |
| do { \ | |
| if constexpr (kForIsEmpty) { \ | |
| return 1; \ | |
| } else { \ | |
| append_to_output(field); \ | |
| } \ | |
| } while (false) | |
| int i = -1; | |
| for (const FieldDescriptor& field : | |
| absl::MakeSpan(descriptor.fields_, last_non_weak_field_index_ + 1)) { | |
| ++i; | |
| const OneofDescriptor* containing_oneof = field.containing_oneof(); | |
| // If the hasbits for repeated fields experiment is disabled, we can | |
| // shortcut to checking the field size, since we know the field doesn't | |
| // have hasbits. | |
| if (!internal::EnableExperimentalHintHasBitsForRepeatedFields() && | |
| field.is_repeated()) { | |
| if (FieldSize(message, &field) > 0) { | |
| PROTO_REFLECTION_APPEND_OR_RETURN(); | |
| } | |
| } else if (schema_.InRealOneof(&field)) { | |
| const uint32_t* const oneof_case_array = | |
| GetConstPointerAtOffset<uint32_t>(&message, | |
| schema_.oneof_case_offset_); | |
| // Equivalent to: HasOneofField(message, field) | |
| if (static_cast<int64_t>(oneof_case_array[containing_oneof->index()]) == | |
| field.number()) { | |
| PROTO_REFLECTION_APPEND_OR_RETURN(); | |
| } | |
| } else if (has_bits && | |
| has_bits_indices[i] != static_cast<uint32_t>(kNoHasbit)) { | |
| // Equivalent to: HasFieldSingular(message, field) | |
| if (IsFieldPresentGivenHasbits(message, &field, has_bits, | |
| has_bits_indices[i])) { | |
| PROTO_REFLECTION_APPEND_OR_RETURN(); | |
| } | |
| } else if (HasFieldWithHasbits(message, &field)) { | |
| PROTO_REFLECTION_APPEND_OR_RETURN(); | |
| } | |
| } | |
| #undef PROTO_REFLECTION_APPEND_OR_RETURN | |
| // Last will be 0 if no fields were encountered. Otherwise it contains the | |
| // last encountered field. | |
| return last; | |
| } | |
| void Reflection::ListFields(const Message& message, | |
| std::vector<const FieldDescriptor*>* output) const { | |
| output->clear(); | |
| // Optimization: The default instance never has any fields set. | |
| if (schema_.IsDefaultInstance(message)) return; | |
| const Descriptor* const descriptor = descriptor_; | |
| uint32_t last = IsEmptyOrCollectSetFields</*kForIsEmpty=*/false>( | |
| message, *descriptor, output); | |
| // Descriptors of ExtensionSet are appended in their increasing tag | |
| // order and they are usually bigger than the field tags so if all fields are | |
| // not sorted, let them be sorted. | |
| if (last == UINT32_MAX) { | |
| std::sort(output->begin(), output->end(), FieldNumberSorter()); | |
| last = output->back()->number(); | |
| } | |
| size_t last_size = output->size(); | |
| if (schema_.HasExtensionSet()) { | |
| // Descriptors of ExtensionSet are appended in their increasing order. | |
| GetExtensionSet(message).AppendToList(descriptor, descriptor_pool_, output); | |
| ABSL_DCHECK(std::is_sorted(output->begin() + last_size, output->end(), | |
| FieldNumberSorter())); | |
| if (output->size() != last_size) { | |
| CheckInOrder((*output)[last_size], &last); | |
| } | |
| } | |
| if (last != UINT32_MAX) { | |
| ABSL_DCHECK( | |
| std::is_sorted(output->begin(), output->end(), FieldNumberSorter())); | |
| } else { | |
| // ListFields() must sort output by field number. | |
| std::sort(output->begin(), output->end(), FieldNumberSorter()); | |
| } | |
| } | |
| bool Reflection::IsEmptyIgnoringUnknownFieldsImpl( | |
| const Message& message) const { | |
| if (IsEmptyOrCollectSetFields</*kForIsEmpty=*/true>(message, *descriptor_, | |
| nullptr) != 0) { | |
| return false; | |
| } | |
| return | |
| !(schema_.HasExtensionSet() && !GetExtensionSet(message).IsEmpty()); | |
| } | |
| bool Reflection::IsEmptyIgnoringUnknownFields(const Message& message) const { | |
| // Optimization: The default instance never has any fields set. | |
| if (schema_.IsDefaultInstance(message)) return true; | |
| return IsEmptyIgnoringUnknownFieldsImpl(message); | |
| } | |
| bool Reflection::IsEmpty(const Message& message) const { | |
| // Optimization: The default instance never has any fields set. | |
| if (schema_.IsDefaultInstance(message)) return true; | |
| return IsEmptyIgnoringUnknownFieldsImpl(message) && | |
| GetUnknownFields(message).empty(); | |
| } | |
| // ------------------------------------------------------------------- | |
| #undef DEFINE_PRIMITIVE_ACCESSORS | |
| #define DEFINE_PRIMITIVE_ACCESSORS(TYPENAME, TYPE, CPPTYPE) \ | |
| TYPE Reflection::Get##TYPENAME(const Message& message, \ | |
| const FieldDescriptor* field) const { \ | |
| USAGE_CHECK_ALL(Get##TYPENAME, SINGULAR, CPPTYPE); \ | |
| if (field->is_extension()) { \ | |
| return GetExtensionSet(message).Get<TYPE>( \ | |
| field->number(), field->default_value_##TYPE()); \ | |
| } else if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { \ | |
| return field->default_value_##TYPE(); \ | |
| } else { \ | |
| return GetField<TYPE>(message, field); \ | |
| } \ | |
| } \ | |
| \ | |
| void Reflection::Set##TYPENAME( \ | |
| Message* message, const FieldDescriptor* field, TYPE value) const { \ | |
| USAGE_MUTABLE_CHECK_ALL(Set##TYPENAME, SINGULAR, CPPTYPE); \ | |
| if (field->is_extension()) { \ | |
| return MutableExtensionSet(message)->Set<TYPE>( \ | |
| message->GetArena(), field->number(), field->type(), value, field); \ | |
| } else { \ | |
| SetField<TYPE>(message, field, value); \ | |
| } \ | |
| } \ | |
| \ | |
| TYPE Reflection::GetRepeated##TYPENAME( \ | |
| const Message& message, const FieldDescriptor* field, int index) const { \ | |
| USAGE_CHECK_ALL(GetRepeated##TYPENAME, REPEATED, CPPTYPE); \ | |
| if (field->is_extension()) { \ | |
| return GetExtensionSet(message).GetRepeated<TYPE>(field->number(), \ | |
| index); \ | |
| } else { \ | |
| return GetRepeatedField<TYPE>(message, field, index); \ | |
| } \ | |
| } \ | |
| \ | |
| void Reflection::SetRepeated##TYPENAME( \ | |
| Message* message, const FieldDescriptor* field, int index, TYPE value) \ | |
| const { \ | |
| USAGE_MUTABLE_CHECK_ALL(SetRepeated##TYPENAME, REPEATED, CPPTYPE); \ | |
| if (field->is_extension()) { \ | |
| MutableExtensionSet(message)->SetRepeated<TYPE>(field->number(), index, \ | |
| value); \ | |
| } else { \ | |
| SetRepeatedField<TYPE>(message, field, index, value); \ | |
| } \ | |
| } \ | |
| \ | |
| void Reflection::Add##TYPENAME( \ | |
| Message* message, const FieldDescriptor* field, TYPE value) const { \ | |
| USAGE_MUTABLE_CHECK_ALL(Add##TYPENAME, REPEATED, CPPTYPE); \ | |
| if (field->is_extension()) { \ | |
| MutableExtensionSet(message)->Add<TYPE>( \ | |
| message->GetArena(), field->number(), field->type(), \ | |
| field->is_packed(), value, field); \ | |
| } else { \ | |
| AddField<TYPE>(message, field, value); \ | |
| } \ | |
| } | |
| DEFINE_PRIMITIVE_ACCESSORS(Int32, int32_t, INT32) | |
| DEFINE_PRIMITIVE_ACCESSORS(Int64, int64_t, INT64) | |
| DEFINE_PRIMITIVE_ACCESSORS(UInt32, uint32_t, UINT32) | |
| DEFINE_PRIMITIVE_ACCESSORS(UInt64, uint64_t, UINT64) | |
| DEFINE_PRIMITIVE_ACCESSORS(Float, float, FLOAT) | |
| DEFINE_PRIMITIVE_ACCESSORS(Double, double, DOUBLE) | |
| DEFINE_PRIMITIVE_ACCESSORS(Bool, bool, BOOL) | |
| #undef DEFINE_PRIMITIVE_ACCESSORS | |
| // ------------------------------------------------------------------- | |
| std::string Reflection::GetString(const Message& message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK_ALL(GetString, SINGULAR, STRING); | |
| if (field->is_extension()) { | |
| return GetExtensionSet(message).Get<std::string>( | |
| field->number(), internal::DefaultValueStringAsString(field)); | |
| } else { | |
| if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { | |
| return std::string(field->default_value_string()); | |
| } | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| if (schema_.InRealOneof(field)) { | |
| return std::string(*GetField<absl::Cord*>(message, field)); | |
| } else { | |
| return std::string(GetField<absl::Cord>(message, field)); | |
| } | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| if (IsInlined(field)) { | |
| return GetField<InlinedStringField>(message, field).GetNoArena(); | |
| } else if (IsMicroString(field)) { | |
| return std::string(GetField<MicroString>(message, field).Get()); | |
| } else { | |
| const auto& str = GetField<ArenaStringPtr>(message, field); | |
| return str.IsDefault() ? std::string(field->default_value_string()) | |
| : str.Get(); | |
| } | |
| } | |
| internal::Unreachable(); | |
| } | |
| } | |
| const std::string& Reflection::GetStringReference(const Message& message, | |
| const FieldDescriptor* field, | |
| std::string* scratch) const { | |
| (void)scratch; // Parameter is used by Google-internal code. | |
| USAGE_CHECK_ALL(GetStringReference, SINGULAR, STRING); | |
| if (field->is_extension()) { | |
| return GetExtensionSet(message).Get<std::string>( | |
| field->number(), internal::DefaultValueStringAsString(field)); | |
| } else { | |
| if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { | |
| return internal::DefaultValueStringAsString(field); | |
| } | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| if (schema_.InRealOneof(field)) { | |
| absl::CopyCordToString(*GetField<absl::Cord*>(message, field), | |
| scratch); | |
| } else { | |
| absl::CopyCordToString(GetField<absl::Cord>(message, field), scratch); | |
| } | |
| return *scratch; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| if (IsInlined(field)) { | |
| return GetField<InlinedStringField>(message, field).GetNoArena(); | |
| } else if (IsMicroString(field)) { | |
| *scratch = std::string(GetField<MicroString>(message, field).Get()); | |
| return *scratch; | |
| } else { | |
| const auto& str = GetField<ArenaStringPtr>(message, field); | |
| return str.IsDefault() ? internal::DefaultValueStringAsString(field) | |
| : str.Get(); | |
| } | |
| } | |
| internal::Unreachable(); | |
| } | |
| } | |
| absl::Cord Reflection::GetCord(const Message& message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK_ALL(GetCord, SINGULAR, STRING); | |
| if (field->is_extension()) { | |
| return absl::Cord(GetExtensionSet(message).Get<std::string>( | |
| field->number(), internal::DefaultValueStringAsString(field))); | |
| } else { | |
| if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { | |
| return absl::Cord(field->default_value_string()); | |
| } | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| if (schema_.InRealOneof(field)) { | |
| return *GetField<absl::Cord*>(message, field); | |
| } else { | |
| return GetField<absl::Cord>(message, field); | |
| } | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| if (IsInlined(field)) { | |
| return absl::Cord( | |
| GetField<InlinedStringField>(message, field).GetNoArena()); | |
| } else if (IsMicroString(field)) { | |
| return absl::Cord(GetField<MicroString>(message, field).Get()); | |
| } else { | |
| const auto& str = GetField<ArenaStringPtr>(message, field); | |
| return absl::Cord(str.IsDefault() ? field->default_value_string() | |
| : str.Get()); | |
| } | |
| } | |
| internal::Unreachable(); | |
| } | |
| } | |
| absl::string_view Reflection::GetStringViewImpl(const Message& message, | |
| const FieldDescriptor* field, | |
| ScratchSpace* scratch) const { | |
| if (field->is_extension()) { | |
| return GetExtensionSet(message).Get<std::string>( | |
| field->number(), internal::DefaultValueStringAsString(field)); | |
| } | |
| if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { | |
| return field->default_value_string(); | |
| } | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: { | |
| const auto& cord = schema_.InRealOneof(field) | |
| ? *GetField<absl::Cord*>(message, field) | |
| : GetField<absl::Cord>(message, field); | |
| ABSL_DCHECK(scratch); | |
| return scratch->CopyFromCord(cord); | |
| } | |
| default: | |
| auto str = GetField<ArenaStringPtr>(message, field); | |
| return str.IsDefault() ? field->default_value_string() : str.Get(); | |
| } | |
| } | |
| absl::string_view Reflection::GetStringView(const Message& message, | |
| const FieldDescriptor* field, | |
| ScratchSpace& scratch) const { | |
| USAGE_CHECK_ALL(GetStringView, SINGULAR, STRING); | |
| return GetStringViewImpl(message, field, &scratch); | |
| } | |
| void Reflection::SetString(Message* message, const FieldDescriptor* field, | |
| std::string value) const { | |
| USAGE_MUTABLE_CHECK_ALL(SetString, SINGULAR, STRING); | |
| Arena* arena = message->GetArena(); | |
| if (field->is_extension()) { | |
| return MutableExtensionSet(message)->Set<std::string>( | |
| arena, field->number(), field->type(), std::move(value), field); | |
| } else { | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| if (schema_.InRealOneof(field)) { | |
| if (!HasOneofField(*message, field)) { | |
| ClearOneof(message, field->containing_oneof()); | |
| *MutableField<absl::Cord*>(message, field) = | |
| Arena::Create<absl::Cord>(arena); | |
| } | |
| *(*MutableField<absl::Cord*>(message, field)) = value; | |
| break; | |
| } | |
| *MutableField<absl::Cord>(message, field) = value; | |
| break; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: { | |
| if (IsInlined(field)) { | |
| MutableField<InlinedStringField>(message, field)->Set(value, arena); | |
| break; | |
| } else if (IsMicroString(field)) { | |
| if (schema_.InRealOneof(field) && !HasOneofField(*message, field)) { | |
| ClearOneof(message, field->containing_oneof()); | |
| MutableField<MicroString>(message, field)->InitDefault(); | |
| } | |
| MutableField<MicroString>(message, field) | |
| ->Set(std::move(value), arena); | |
| break; | |
| } | |
| // Oneof string fields are never set as a default instance. | |
| // We just need to pass some arbitrary default string to make it work. | |
| // This allows us to not have the real default accessible from | |
| // reflection. | |
| if (schema_.InRealOneof(field) && !HasOneofField(*message, field)) { | |
| ClearOneof(message, field->containing_oneof()); | |
| MutableField<ArenaStringPtr>(message, field)->InitDefault(); | |
| } | |
| MutableField<ArenaStringPtr>(message, field) | |
| ->Set(std::move(value), arena); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| void Reflection::SetString(Message* message, const FieldDescriptor* field, | |
| const absl::Cord& value) const { | |
| USAGE_MUTABLE_CHECK_ALL(SetString, SINGULAR, STRING); | |
| Arena* arena = message->GetArena(); | |
| if (field->is_extension()) { | |
| return absl::CopyCordToString( | |
| value, MutableExtensionSet(message)->MutableString( | |
| arena, field->number(), field->type(), field)); | |
| } else { | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| if (schema_.InRealOneof(field)) { | |
| if (!HasOneofField(*message, field)) { | |
| ClearOneof(message, field->containing_oneof()); | |
| *MutableField<absl::Cord*>(message, field) = | |
| Arena::Create<absl::Cord>(arena); | |
| } | |
| *(*MutableField<absl::Cord*>(message, field)) = value; | |
| } else { | |
| *MutableField<absl::Cord>(message, field) = value; | |
| } | |
| break; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: { | |
| if (IsInlined(field)) { | |
| auto* str = MutableField<InlinedStringField>(message, field); | |
| str->Set(std::string(value), arena); | |
| } else if (IsMicroString(field)) { | |
| if (schema_.InRealOneof(field) && !HasOneofField(*message, field)) { | |
| ClearOneof(message, field->containing_oneof()); | |
| MutableField<MicroString>(message, field)->InitDefault(); | |
| } | |
| auto* str = MutableField<MicroString>(message, field); | |
| str->Set(std::string(value), arena); | |
| } else { | |
| if (schema_.InRealOneof(field) && !HasOneofField(*message, field)) { | |
| ClearOneof(message, field->containing_oneof()); | |
| MutableField<ArenaStringPtr>(message, field)->InitDefault(); | |
| } | |
| auto* str = MutableField<ArenaStringPtr>(message, field); | |
| str->Set(std::string(value), arena); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| std::string Reflection::GetRepeatedString(const Message& message, | |
| const FieldDescriptor* field, | |
| int index) const { | |
| USAGE_CHECK_ALL(GetRepeatedString, REPEATED, STRING); | |
| if (field->is_extension()) { | |
| return GetExtensionSet(message).GetRepeated<std::string>(field->number(), | |
| index); | |
| } else { | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| return std::string(GetRepeatedField<absl::Cord>(message, field, index)); | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| return GetRepeatedPtrField<std::string>(message, field, index); | |
| } | |
| internal::Unreachable(); | |
| } | |
| } | |
| const std::string& Reflection::GetRepeatedStringReference( | |
| const Message& message, const FieldDescriptor* field, int index, | |
| std::string* scratch) const { | |
| (void)scratch; // Parameter is used by Google-internal code. | |
| USAGE_CHECK_ALL(GetRepeatedStringReference, REPEATED, STRING); | |
| if (field->is_extension()) { | |
| return GetExtensionSet(message).GetRepeated<std::string>(field->number(), | |
| index); | |
| } else { | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| absl::CopyCordToString( | |
| GetRepeatedField<absl::Cord>(message, field, index), scratch); | |
| return *scratch; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| return GetRepeatedPtrField<std::string>(message, field, index); | |
| } | |
| internal::Unreachable(); | |
| } | |
| } | |
| // See GetStringView(), above. | |
| absl::string_view Reflection::GetRepeatedStringViewImpl( | |
| const Message& message, const FieldDescriptor* field, int index, | |
| ScratchSpace* scratch) const { | |
| if (field->is_extension()) { | |
| return GetExtensionSet(message).GetRepeated<std::string>(field->number(), | |
| index); | |
| } | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: { | |
| auto& cord = GetRepeatedField<absl::Cord>(message, field, index); | |
| ABSL_DCHECK(scratch); | |
| return scratch->CopyFromCord(cord); | |
| } | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| return GetRepeatedPtrField<std::string>(message, field, index); | |
| } | |
| internal::Unreachable(); | |
| } | |
| absl::string_view Reflection::GetRepeatedStringView( | |
| const Message& message, const FieldDescriptor* field, int index, | |
| ScratchSpace& scratch) const { | |
| USAGE_CHECK_ALL(GetRepeatedStringView, REPEATED, STRING); | |
| return GetRepeatedStringViewImpl(message, field, index, &scratch); | |
| } | |
| void Reflection::SetRepeatedString(Message* message, | |
| const FieldDescriptor* field, int index, | |
| std::string value) const { | |
| USAGE_MUTABLE_CHECK_ALL(SetRepeatedString, REPEATED, STRING); | |
| if (field->is_extension()) { | |
| MutableExtensionSet(message)->SetRepeated<std::string>( | |
| field->number(), index, std::move(value)); | |
| } else { | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| SetRepeatedField<absl::Cord>(message, field, index, absl::Cord(value)); | |
| break; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| MutableRepeatedField<std::string>(message, field, index) | |
| ->assign(std::move(value)); | |
| break; | |
| } | |
| } | |
| } | |
| void Reflection::AddString(Message* message, const FieldDescriptor* field, | |
| std::string value) const { | |
| USAGE_MUTABLE_CHECK_ALL(AddString, REPEATED, STRING); | |
| if (field->is_extension()) { | |
| MutableExtensionSet(message)->Add<std::string>( | |
| message->GetArena(), field->number(), | |
| field->requires_utf8_validation() ? FieldDescriptor::TYPE_STRING | |
| : FieldDescriptor::TYPE_BYTES, | |
| field) = std::move(value); | |
| } else { | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| AddField<absl::Cord>(message, field, absl::Cord(value)); | |
| break; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| AddField<std::string>(message, field)->assign(std::move(value)); | |
| break; | |
| } | |
| } | |
| } | |
| // ------------------------------------------------------------------- | |
| const EnumValueDescriptor* Reflection::GetEnum( | |
| const Message& message, const FieldDescriptor* field) const { | |
| // Usage checked by GetEnumValue. | |
| int value = GetEnumValue(message, field); | |
| return field->enum_type()->FindValueByNumberCreatingIfUnknown(value); | |
| } | |
| int Reflection::GetEnumValue(const Message& message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK_ALL(GetEnumValue, SINGULAR, ENUM); | |
| int32_t value; | |
| if (field->is_extension()) { | |
| value = GetExtensionSet(message).Get<int>( | |
| field->number(), field->default_value_enum()->number()); | |
| } else if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { | |
| value = field->default_value_enum()->number(); | |
| } else { | |
| value = GetField<int>(message, field); | |
| } | |
| return value; | |
| } | |
| void Reflection::SetEnum(Message* message, const FieldDescriptor* field, | |
| const EnumValueDescriptor* value) const { | |
| // Usage checked by SetEnumValue. | |
| USAGE_CHECK_ENUM_VALUE(SetEnum); | |
| SetEnumValueInternal(message, field, value->number()); | |
| } | |
| void Reflection::SetEnumValue(Message* message, const FieldDescriptor* field, | |
| int value) const { | |
| USAGE_MUTABLE_CHECK_ALL(SetEnumValue, SINGULAR, ENUM); | |
| if (!CreateUnknownEnumValues(field)) { | |
| // Check that the value is valid if we don't support direct storage of | |
| // unknown enum values. | |
| const EnumValueDescriptor* value_desc = | |
| field->enum_type()->FindValueByNumber(value); | |
| if (value_desc == nullptr) { | |
| MutableUnknownFields(message)->AddVarint(field->number(), value); | |
| return; | |
| } | |
| } | |
| SetEnumValueInternal(message, field, value); | |
| } | |
| void Reflection::SetEnumValueInternal(Message* message, | |
| const FieldDescriptor* field, | |
| int value) const { | |
| if (field->is_extension()) { | |
| MutableExtensionSet(message)->Set<int>(message->GetArena(), field->number(), | |
| field->type(), value, field); | |
| } else { | |
| SetField<int>(message, field, value); | |
| } | |
| } | |
| const EnumValueDescriptor* Reflection::GetRepeatedEnum( | |
| const Message& message, const FieldDescriptor* field, int index) const { | |
| // Usage checked by GetRepeatedEnumValue. | |
| int value = GetRepeatedEnumValue(message, field, index); | |
| return field->enum_type()->FindValueByNumberCreatingIfUnknown(value); | |
| } | |
| int Reflection::GetRepeatedEnumValue(const Message& message, | |
| const FieldDescriptor* field, | |
| int index) const { | |
| USAGE_CHECK_ALL(GetRepeatedEnumValue, REPEATED, ENUM); | |
| int value; | |
| if (field->is_extension()) { | |
| value = GetExtensionSet(message).GetRepeated<int>(field->number(), index); | |
| } else { | |
| value = GetRepeatedField<int>(message, field, index); | |
| } | |
| return value; | |
| } | |
| void Reflection::SetRepeatedEnum(Message* message, const FieldDescriptor* field, | |
| int index, | |
| const EnumValueDescriptor* value) const { | |
| // Usage checked by SetRepeatedEnumValue. | |
| USAGE_CHECK_ENUM_VALUE(SetRepeatedEnum); | |
| SetRepeatedEnumValueInternal(message, field, index, value->number()); | |
| } | |
| void Reflection::SetRepeatedEnumValue(Message* message, | |
| const FieldDescriptor* field, int index, | |
| int value) const { | |
| USAGE_MUTABLE_CHECK_ALL(SetRepeatedEnum, REPEATED, ENUM); | |
| if (!CreateUnknownEnumValues(field)) { | |
| // Check that the value is valid if we don't support direct storage of | |
| // unknown enum values. | |
| const EnumValueDescriptor* value_desc = | |
| field->enum_type()->FindValueByNumber(value); | |
| if (value_desc == nullptr) { | |
| MutableUnknownFields(message)->AddVarint(field->number(), value); | |
| return; | |
| } | |
| } | |
| SetRepeatedEnumValueInternal(message, field, index, value); | |
| } | |
| void Reflection::SetRepeatedEnumValueInternal(Message* message, | |
| const FieldDescriptor* field, | |
| int index, int value) const { | |
| if (field->is_extension()) { | |
| MutableExtensionSet(message)->SetRepeated<int>(field->number(), index, | |
| value); | |
| } else { | |
| SetRepeatedField<int>(message, field, index, value); | |
| } | |
| } | |
| void Reflection::AddEnum(Message* message, const FieldDescriptor* field, | |
| const EnumValueDescriptor* value) const { | |
| // Usage checked by AddEnumValue. | |
| USAGE_CHECK_ENUM_VALUE(AddEnum); | |
| AddEnumValueInternal(message, field, value->number()); | |
| } | |
| void Reflection::AddEnumValue(Message* message, const FieldDescriptor* field, | |
| int value) const { | |
| USAGE_MUTABLE_CHECK_ALL(AddEnum, REPEATED, ENUM); | |
| if (!CreateUnknownEnumValues(field)) { | |
| // Check that the value is valid if we don't support direct storage of | |
| // unknown enum values. | |
| const EnumValueDescriptor* value_desc = | |
| field->enum_type()->FindValueByNumber(value); | |
| if (value_desc == nullptr) { | |
| MutableUnknownFields(message)->AddVarint(field->number(), value); | |
| return; | |
| } | |
| } | |
| AddEnumValueInternal(message, field, value); | |
| } | |
| void Reflection::AddEnumValueInternal(Message* message, | |
| const FieldDescriptor* field, | |
| int value) const { | |
| if (field->is_extension()) { | |
| MutableExtensionSet(message)->Add<int>(message->GetArena(), field->number(), | |
| field->type(), field->is_packed(), | |
| value, field); | |
| } else { | |
| AddField<int>(message, field, value); | |
| } | |
| } | |
| // ------------------------------------------------------------------- | |
| const Message* Reflection::GetDefaultMessageInstance( | |
| const FieldDescriptor* field) const { | |
| // If we are using the generated factory, we cache the prototype in the field | |
| // descriptor for faster access. | |
| // The default instances of generated messages are not cross-linked, which | |
| // means they contain null pointers on their message fields and can't be used | |
| // to get the default of submessages. | |
| if (message_factory_ == MessageFactory::generated_factory()) { | |
| auto& ptr = field->default_generated_instance_; | |
| auto* res = ptr.load(std::memory_order_acquire); | |
| if (res == nullptr) { | |
| // First time asking for this field's default. Load it and cache it. | |
| res = message_factory_->GetPrototype(field->message_type()); | |
| ptr.store(res, std::memory_order_release); | |
| } | |
| return res; | |
| } | |
| // For other factories, we try the default's object field. | |
| // In particular, the DynamicMessageFactory will cross link the default | |
| // instances to allow for this. But only do this for real fields. | |
| // This is an optimization to avoid going to GetPrototype() below, as that | |
| // requires a lock and a map lookup. | |
| if (!field->is_extension() && !field->options().weak() && | |
| !IsLazyField(field) && !schema_.InRealOneof(field)) { | |
| auto* res = DefaultRaw<const Message*>(field); | |
| if (res != nullptr) { | |
| return res; | |
| } | |
| } | |
| // Otherwise, just go to the factory. | |
| return message_factory_->GetPrototype(field->message_type()); | |
| } | |
| const Message& Reflection::GetMessage(const Message& message, | |
| const FieldDescriptor* field, | |
| MessageFactory* factory) const { | |
| USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE); | |
| if (factory == nullptr) factory = message_factory_; | |
| if (field->is_extension()) { | |
| return static_cast<const Message&>(GetExtensionSet(message).GetMessage( | |
| message.GetArena(), field->number(), field->message_type(), factory)); | |
| } else { | |
| if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { | |
| return *GetDefaultMessageInstance(field); | |
| } | |
| const Message* result = GetRaw<const Message*>(message, field); | |
| if (result == nullptr) { | |
| result = GetDefaultMessageInstance(field); | |
| } | |
| return *result; | |
| } | |
| } | |
| Message* Reflection::MutableMessage(Message* message, | |
| const FieldDescriptor* field, | |
| MessageFactory* factory) const { | |
| USAGE_MUTABLE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE); | |
| if (factory == nullptr) factory = message_factory_; | |
| Arena* arena = message->GetArena(); | |
| if (field->is_extension()) { | |
| return static_cast<Message*>( | |
| MutableExtensionSet(message)->MutableMessage(arena, field, factory)); | |
| } else { | |
| Message* result; | |
| Message** result_holder = MutableRaw<Message*>(message, field); | |
| if (schema_.InRealOneof(field)) { | |
| if (!HasOneofField(*message, field)) { | |
| ClearOneof(message, field->containing_oneof()); | |
| result_holder = MutableField<Message*>(message, field); | |
| const Message* default_message = GetDefaultMessageInstance(field); | |
| *result_holder = default_message->New(arena); | |
| } | |
| } else { | |
| SetHasBit(message, field); | |
| } | |
| if (*result_holder == nullptr) { | |
| const Message* default_message = GetDefaultMessageInstance(field); | |
| *result_holder = default_message->New(arena); | |
| } | |
| result = *result_holder; | |
| return result; | |
| } | |
| } | |
| void Reflection::UnsafeArenaSetAllocatedMessage( | |
| Message* message, Message* sub_message, | |
| const FieldDescriptor* field) const { | |
| USAGE_MUTABLE_CHECK_ALL(SetAllocatedMessage, SINGULAR, MESSAGE); | |
| Arena* arena = message->GetArena(); | |
| if (field->is_extension()) { | |
| MutableExtensionSet(message)->UnsafeArenaSetAllocatedMessage( | |
| arena, field->number(), field->type(), field, sub_message); | |
| } else { | |
| if (schema_.InRealOneof(field)) { | |
| if (sub_message == nullptr) { | |
| ClearOneof(message, field->containing_oneof()); | |
| return; | |
| } | |
| ClearOneof(message, field->containing_oneof()); | |
| *MutableRaw<Message*>(message, field) = sub_message; | |
| SetOneofCase(message, field); | |
| return; | |
| } | |
| if (sub_message == nullptr) { | |
| ClearHasBit(message, field); | |
| } else { | |
| SetHasBit(message, field); | |
| } | |
| Message** sub_message_holder = MutableRaw<Message*>(message, field); | |
| if (arena == nullptr) { | |
| delete *sub_message_holder; | |
| } | |
| *sub_message_holder = sub_message; | |
| } | |
| } | |
| void Reflection::SetAllocatedMessage(Message* message, Message* sub_message, | |
| const FieldDescriptor* field) const { | |
| ABSL_DCHECK(sub_message == nullptr || sub_message->GetArena() == nullptr || | |
| sub_message->GetArena() == message->GetArena()); | |
| if (sub_message == nullptr) { | |
| UnsafeArenaSetAllocatedMessage(message, nullptr, field); | |
| return; | |
| } | |
| Arena* arena = message->GetArena(); | |
| Arena* sub_arena = sub_message->GetArena(); | |
| if (arena == sub_arena) { | |
| UnsafeArenaSetAllocatedMessage(message, sub_message, field); | |
| return; | |
| } | |
| // If message and sub-message are in different memory ownership domains | |
| // (different arenas, or one is on heap and one is not), then we may need to | |
| // do a copy. | |
| if (sub_arena == nullptr) { | |
| ABSL_DCHECK_NE(arena, nullptr); | |
| // Case 1: parent is on an arena and child is heap-allocated. We can add | |
| // the child to the arena's Own() list to free on arena destruction, then | |
| // set our pointer. | |
| arena->Own(sub_message); | |
| UnsafeArenaSetAllocatedMessage(message, sub_message, field); | |
| } else { | |
| // Case 2: all other cases. We need to make a copy. MutableMessage() will | |
| // either get the existing message object, or instantiate a new one as | |
| // appropriate w.r.t. our arena. | |
| Message* sub_message_copy = MutableMessage(message, field); | |
| sub_message_copy->CopyFrom(*sub_message); | |
| } | |
| } | |
| Message* Reflection::UnsafeArenaReleaseMessage(Message* message, | |
| const FieldDescriptor* field, | |
| MessageFactory* factory) const { | |
| USAGE_MUTABLE_CHECK_ALL(ReleaseMessage, SINGULAR, MESSAGE); | |
| if (factory == nullptr) factory = message_factory_; | |
| Arena* arena = message->GetArena(); | |
| if (field->is_extension()) { | |
| return static_cast<Message*>( | |
| MutableExtensionSet(message)->UnsafeArenaReleaseMessage(arena, field, | |
| factory)); | |
| } else { | |
| if (!schema_.InRealOneof(field)) { | |
| ClearHasBit(message, field); | |
| } | |
| if (schema_.InRealOneof(field)) { | |
| if (HasOneofField(*message, field)) { | |
| *MutableOneofCase(message, field->containing_oneof()) = 0; | |
| } else { | |
| return nullptr; | |
| } | |
| } | |
| Message** result = MutableRaw<Message*>(message, field); | |
| Message* ret = *result; | |
| *result = nullptr; | |
| return ret; | |
| } | |
| } | |
| Message* Reflection::ReleaseMessage(Message* message, | |
| const FieldDescriptor* field, | |
| MessageFactory* factory) const { | |
| Message* released = UnsafeArenaReleaseMessage(message, field, factory); | |
| if (internal::DebugHardenForceCopyInRelease()) { | |
| released = MaybeForceCopy(message->GetArena(), released); | |
| } | |
| if (message->GetArena() != nullptr && released != nullptr) { | |
| Message* copy_from_arena = released->New(); | |
| copy_from_arena->CopyFrom(*released); | |
| released = copy_from_arena; | |
| } | |
| return released; | |
| } | |
| const Message& Reflection::GetRepeatedMessage(const Message& message, | |
| const FieldDescriptor* field, | |
| int index) const { | |
| USAGE_CHECK_ALL(GetRepeatedMessage, REPEATED, MESSAGE); | |
| if (field->is_extension()) { | |
| return static_cast<const Message&>( | |
| GetExtensionSet(message).GetRepeatedMessage(field->number(), index)); | |
| } else { | |
| if (IsMapFieldInApi(field)) { | |
| return GetRaw<MapFieldBase>(message, field) | |
| .GetRepeatedField() | |
| .Get<GenericTypeHandler<Message> >(index); | |
| } else { | |
| return GetRaw<RepeatedPtrFieldBase>(message, field) | |
| .Get<GenericTypeHandler<Message> >(index); | |
| } | |
| } | |
| } | |
| Message* Reflection::MutableRepeatedMessage(Message* message, | |
| const FieldDescriptor* field, | |
| int index) const { | |
| USAGE_MUTABLE_CHECK_ALL(MutableRepeatedMessage, REPEATED, MESSAGE); | |
| if (field->is_extension()) { | |
| return static_cast<Message*>( | |
| MutableExtensionSet(message)->MutableRepeatedMessage(field->number(), | |
| index)); | |
| } else { | |
| SetHasBitForRepeated(message, field); | |
| if (IsMapFieldInApi(field)) { | |
| return MutableRaw<MapFieldBase>(message, field) | |
| ->MutableRepeatedField() | |
| ->Mutable<GenericTypeHandler<Message> >(index); | |
| } else { | |
| return MutableRaw<RepeatedPtrFieldBase>(message, field) | |
| ->Mutable<GenericTypeHandler<Message> >(index); | |
| } | |
| } | |
| } | |
| Message* Reflection::AddMessage(Message* message, const FieldDescriptor* field, | |
| MessageFactory* factory) const { | |
| USAGE_MUTABLE_CHECK_ALL(AddMessage, REPEATED, MESSAGE); | |
| if (factory == nullptr) factory = message_factory_; | |
| Arena* arena = message->GetArena(); | |
| if (field->is_extension()) { | |
| return static_cast<Message*>( | |
| MutableExtensionSet(message)->AddMessage(arena, field, factory)); | |
| } else { | |
| Message* result = nullptr; | |
| SetHasBitForRepeated(message, field); | |
| // We can't use AddField<Message>() because RepeatedPtrFieldBase doesn't | |
| // know how to allocate one. | |
| RepeatedPtrFieldBase* repeated = nullptr; | |
| if (IsMapFieldInApi(field)) { | |
| repeated = | |
| MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField(); | |
| } else { | |
| repeated = MutableRaw<RepeatedPtrFieldBase>(message, field); | |
| } | |
| result = repeated->AddFromCleared<GenericTypeHandler<Message> >(); | |
| if (result == nullptr) { | |
| // We must allocate a new object. | |
| const Message* prototype; | |
| if (repeated->size() == 0) { | |
| prototype = factory->GetPrototype(field->message_type()); | |
| } else { | |
| prototype = &repeated->Get<GenericTypeHandler<Message> >(0); | |
| } | |
| result = prototype->New(arena); | |
| // We can guarantee here that repeated and result are either both heap | |
| // allocated or arena owned. So it is safe to call the unsafe version | |
| // of AddAllocated. | |
| repeated->UnsafeArenaAddAllocated<GenericTypeHandler<Message>>(arena, | |
| result); | |
| } | |
| return result; | |
| } | |
| } | |
| void Reflection::AddAllocatedMessage(Message* message, | |
| const FieldDescriptor* field, | |
| Message* new_entry) const { | |
| USAGE_MUTABLE_CHECK_ALL(AddAllocatedMessage, REPEATED, MESSAGE); | |
| Arena* arena = message->GetArena(); | |
| if (field->is_extension()) { | |
| MutableExtensionSet(message)->AddAllocatedMessage(arena, field, new_entry); | |
| } else { | |
| RepeatedPtrFieldBase* repeated = nullptr; | |
| if (IsMapFieldInApi(field)) { | |
| repeated = | |
| MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField(); | |
| } else { | |
| repeated = MutableRaw<RepeatedPtrFieldBase>(message, field); | |
| } | |
| repeated->AddAllocated<GenericTypeHandler<Message>>(arena, new_entry); | |
| SetHasBitForRepeated(message, field); | |
| } | |
| } | |
| void Reflection::UnsafeArenaAddAllocatedMessage(Message* message, | |
| const FieldDescriptor* field, | |
| Message* new_entry) const { | |
| USAGE_MUTABLE_CHECK_ALL(UnsafeArenaAddAllocatedMessage, REPEATED, MESSAGE); | |
| Arena* arena = message->GetArena(); | |
| if (field->is_extension()) { | |
| MutableExtensionSet(message)->UnsafeArenaAddAllocatedMessage(arena, field, | |
| new_entry); | |
| } else { | |
| RepeatedPtrFieldBase* repeated = nullptr; | |
| if (IsMapFieldInApi(field)) { | |
| repeated = | |
| MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField(); | |
| } else { | |
| repeated = MutableRaw<RepeatedPtrFieldBase>(message, field); | |
| } | |
| repeated->UnsafeArenaAddAllocated<GenericTypeHandler<Message>>(arena, | |
| new_entry); | |
| SetHasBitForRepeated(message, field); | |
| } | |
| } | |
| bool Reflection::IsRepeatedOrMapFieldEmpty(const Message& message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK_MESSAGE(IsRepeatedOrMapFieldEmpty, &message); | |
| USAGE_CHECK_MESSAGE_TYPE(IsRepeatedOrMapFieldEmpty); | |
| USAGE_CHECK_REPEATED(IsRepeatedOrMapFieldEmpty); | |
| if (field->is_extension()) { | |
| return GetExtensionSet(message).ExtensionSize(field->number()) == 0; | |
| } else { | |
| switch (field->cpp_type()) { | |
| #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ | |
| case FieldDescriptor::CPPTYPE_##UPPERCASE: \ | |
| return GetRaw<RepeatedField<LOWERCASE>>(message, field).empty() | |
| HANDLE_TYPE(INT32, int32_t); | |
| HANDLE_TYPE(INT64, int64_t); | |
| HANDLE_TYPE(UINT32, uint32_t); | |
| HANDLE_TYPE(UINT64, uint64_t); | |
| HANDLE_TYPE(DOUBLE, double); | |
| HANDLE_TYPE(FLOAT, float); | |
| HANDLE_TYPE(BOOL, bool); | |
| HANDLE_TYPE(ENUM, int); | |
| #undef HANDLE_TYPE | |
| case FieldDescriptor::CPPTYPE_STRING: | |
| if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) { | |
| return GetRaw<RepeatedField<absl::Cord>>(message, field).empty(); | |
| } else { | |
| return GetRaw<RepeatedPtrFieldBase>(message, field).empty(); | |
| } | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| if (IsMapFieldInApi(field)) { | |
| const internal::MapFieldBase& map = | |
| GetRaw<MapFieldBase>(message, field); | |
| if (map.IsRepeatedFieldValid()) { | |
| return map.GetRepeatedField().empty(); | |
| } else { | |
| // No need to materialize the repeated field if it is out of sync: | |
| // its size will be the same as the map's size. | |
| return map.size() == 0; | |
| } | |
| } else { | |
| return GetRaw<RepeatedPtrFieldBase>(message, field).empty(); | |
| } | |
| default: | |
| internal::Unreachable(); | |
| } | |
| } | |
| } | |
| void* Reflection::MutableRawRepeatedField(Message* message, | |
| const FieldDescriptor* field, | |
| FieldDescriptor::CppType cpptype, | |
| int ctype, | |
| const Descriptor* desc) const { | |
| (void)ctype; // Parameter is used by Google-internal code. | |
| USAGE_CHECK_REPEATED("MutableRawRepeatedField"); | |
| USAGE_CHECK_MESSAGE_TYPE(MutableRawRepeatedField); | |
| if (field->cpp_type() != cpptype && | |
| (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM || | |
| cpptype != FieldDescriptor::CPPTYPE_INT32)) | |
| ReportReflectionUsageTypeError(descriptor_, field, | |
| "MutableRawRepeatedField", cpptype); | |
| if (desc != nullptr) | |
| ABSL_CHECK_EQ(field->message_type(), desc) << "wrong submessage type"; | |
| if (field->is_extension()) { | |
| return MutableExtensionSet(message)->MutableRawRepeatedField( | |
| message->GetArena(), field->number(), field->type(), field->is_packed(), | |
| field); | |
| } else { | |
| // Trigger transform for MapField | |
| if (IsMapFieldInApi(field)) { | |
| return MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField(); | |
| } | |
| return MutableRaw<void>(message, field); | |
| } | |
| } | |
| const void* Reflection::GetRawRepeatedField(const Message& message, | |
| const FieldDescriptor* field, | |
| FieldDescriptor::CppType cpptype, | |
| int ctype, | |
| const Descriptor* desc) const { | |
| USAGE_CHECK_REPEATED("GetRawRepeatedField"); | |
| USAGE_CHECK_MESSAGE_TYPE(GetRawRepeatedField); | |
| if (field->cpp_type() != cpptype && | |
| (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM || | |
| cpptype != FieldDescriptor::CPPTYPE_INT32)) | |
| ReportReflectionUsageTypeError(descriptor_, field, "GetRawRepeatedField", | |
| cpptype); | |
| if (ctype >= 0) | |
| ABSL_CHECK(IsMatchingCType(field, ctype)) << "subtype mismatch"; | |
| if (desc != nullptr) | |
| ABSL_CHECK_EQ(field->message_type(), desc) << "wrong submessage type"; | |
| if (field->is_extension()) { | |
| return GetExtensionSet(message).GetRawRepeatedField( | |
| field->number(), internal::DefaultRawPtr()); | |
| } else { | |
| // Trigger transform for MapField | |
| if (IsMapFieldInApi(field)) { | |
| return &(GetRaw<MapFieldBase>(message, field).GetRepeatedField()); | |
| } | |
| return &GetRaw<char>(message, field); | |
| } | |
| } | |
| const FieldDescriptor* Reflection::GetOneofFieldDescriptor( | |
| const Message& message, const OneofDescriptor* oneof_descriptor) const { | |
| if (oneof_descriptor->is_synthetic()) { | |
| const FieldDescriptor* field = oneof_descriptor->field(0); | |
| return HasField(message, field) ? field : nullptr; | |
| } | |
| uint32_t field_number = GetOneofCase(message, oneof_descriptor); | |
| if (field_number == 0) { | |
| return nullptr; | |
| } | |
| return descriptor_->FindFieldByNumber(field_number); | |
| } | |
| bool Reflection::ContainsMapKey(const Message& message, | |
| const FieldDescriptor* field, | |
| const MapKey& key) const { | |
| USAGE_CHECK(IsMapFieldInApi(field), LookupMapValue, | |
| "Field is not a map field."); | |
| return GetRaw<MapFieldBase>(message, field).ContainsMapKey(key); | |
| } | |
| bool Reflection::InsertOrLookupMapValue(Message* message, | |
| const FieldDescriptor* field, | |
| const MapKey& key, | |
| MapValueRef* val) const { | |
| USAGE_CHECK(IsMapFieldInApi(field), InsertOrLookupMapValue, | |
| "Field is not a map field."); | |
| val->SetType(field->message_type()->map_value()->cpp_type()); | |
| SetHasBitForRepeated(message, field); | |
| return MutableRaw<MapFieldBase>(message, field) | |
| ->InsertOrLookupMapValue(key, val); | |
| } | |
| bool Reflection::LookupMapValue(const Message& message, | |
| const FieldDescriptor* field, const MapKey& key, | |
| MapValueConstRef* val) const { | |
| USAGE_CHECK(IsMapFieldInApi(field), LookupMapValue, | |
| "Field is not a map field."); | |
| val->SetType(field->message_type()->map_value()->cpp_type()); | |
| return GetRaw<MapFieldBase>(message, field).LookupMapValue(key, val); | |
| } | |
| bool Reflection::DeleteMapValue(Message* message, const FieldDescriptor* field, | |
| const MapKey& key) const { | |
| USAGE_CHECK(IsMapFieldInApi(field), DeleteMapValue, | |
| "Field is not a map field."); | |
| return MutableRaw<MapFieldBase>(message, field) | |
| ->DeleteMapValue(message->GetArena(), key); | |
| } | |
| MapIterator Reflection::MapBegin(Message* message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK(IsMapFieldInApi(field), MapBegin, "Field is not a map field."); | |
| MapIterator iter(message, field); | |
| GetRaw<MapFieldBase>(*message, field).MapBegin(&iter); | |
| return iter; | |
| } | |
| MapIterator Reflection::MapEnd(Message* message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK(IsMapFieldInApi(field), MapEnd, "Field is not a map field."); | |
| MapIterator iter(message, field); | |
| GetRaw<MapFieldBase>(*message, field).MapEnd(&iter); | |
| return iter; | |
| } | |
| ConstMapIterator Reflection::ConstMapBegin(const Message* message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK(IsMapFieldInApi(field), ConstMapBegin, | |
| "Field is not a map field."); | |
| ConstMapIterator iter(message, field); | |
| GetRaw<MapFieldBase>(*message, field).ConstMapBegin(&iter); | |
| return iter; | |
| } | |
| ConstMapIterator Reflection::ConstMapEnd(const Message* message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK(IsMapFieldInApi(field), ConstMapEnd, "Field is not a map field."); | |
| ConstMapIterator iter(message, field); | |
| GetRaw<MapFieldBase>(*message, field).ConstMapEnd(&iter); | |
| return iter; | |
| } | |
| int Reflection::MapSize(const Message& message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK(IsMapFieldInApi(field), MapSize, "Field is not a map field."); | |
| return GetRaw<MapFieldBase>(message, field).size(); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| const FieldDescriptor* Reflection::FindKnownExtensionByName( | |
| absl::string_view name) const { | |
| if (!schema_.HasExtensionSet()) return nullptr; | |
| return descriptor_pool_->FindExtensionByPrintableName(descriptor_, name); | |
| } | |
| const FieldDescriptor* Reflection::FindKnownExtensionByNumber( | |
| int number) const { | |
| if (!schema_.HasExtensionSet()) return nullptr; | |
| return descriptor_pool_->FindExtensionByNumber(descriptor_, number); | |
| } | |
| // =================================================================== | |
| // Some private helpers. | |
| // These simple template accessors obtain pointers (or references) to | |
| // the given field. | |
| void Reflection::PrepareSplitMessageForWrite(Message* message) const { | |
| ABSL_DCHECK_NE(message, schema_.default_instance_); | |
| void** split = MutableSplitField(message); | |
| const void* default_split = GetSplitField(schema_.default_instance_); | |
| if (*split == default_split) { | |
| uint32_t size = schema_.SizeofSplit(); | |
| Arena* arena = message->GetArena(); | |
| *split = (arena == nullptr) ? internal::Allocate(size) | |
| : arena->AllocateAligned(size); | |
| memcpy(*split, default_split, size); | |
| } | |
| } | |
| template <class Type> | |
| static Type* AllocIfDefault(const FieldDescriptor* field, Type*& ptr, | |
| Arena* arena) { | |
| if (ptr == internal::DefaultRawPtr()) { | |
| // Note: we can't rely on Type to distinguish between these cases (Type can | |
| // be e.g. char). | |
| if (field->cpp_type() < FieldDescriptor::CPPTYPE_STRING || | |
| (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && | |
| field->cpp_string_type() == FieldDescriptor::CppStringType::kCord)) { | |
| ptr = | |
| reinterpret_cast<Type*>(Arena::Create<RepeatedField<int32_t>>(arena)); | |
| } else { | |
| ptr = reinterpret_cast<Type*>(Arena::Create<RepeatedPtrFieldBase>(arena)); | |
| } | |
| } | |
| return ptr; | |
| } | |
| void* Reflection::MutableRawSplitImpl(Message* message, | |
| const FieldDescriptor* field) const { | |
| ABSL_DCHECK(!schema_.InRealOneof(field)) << "Field = " << field->full_name(); | |
| const uint32_t field_offset = schema_.GetFieldOffset(field); | |
| PrepareSplitMessageForWrite(message); | |
| void** split = MutableSplitField(message); | |
| if (SplitFieldHasExtraIndirection(field)) { | |
| return AllocIfDefault(field, | |
| *GetPointerAtOffset<void*>(*split, field_offset), | |
| message->GetArena()); | |
| } | |
| return GetPointerAtOffset<void>(*split, field_offset); | |
| } | |
| const uint32_t* Reflection::GetHasBits(const Message& message) const { | |
| ABSL_DCHECK(schema_.HasHasbits()); | |
| return &GetConstRefAtOffset<uint32_t>(message, schema_.HasBitsOffset()); | |
| } | |
| uint32_t* Reflection::MutableHasBits(Message* message) const { | |
| ABSL_DCHECK(schema_.HasHasbits()); | |
| return GetPointerAtOffset<uint32_t>(message, schema_.HasBitsOffset()); | |
| } | |
| uint32_t Reflection::GetOneofCase( | |
| const Message& message, const OneofDescriptor* oneof_descriptor) const { | |
| ABSL_DCHECK(!oneof_descriptor->is_synthetic()); | |
| return internal::GetConstRefAtOffset<uint32_t>( | |
| message, schema_.GetOneofCaseOffset(oneof_descriptor)); | |
| } | |
| uint32_t* Reflection::MutableOneofCase( | |
| Message* message, const OneofDescriptor* oneof_descriptor) const { | |
| ABSL_DCHECK(!oneof_descriptor->is_synthetic()); | |
| return GetPointerAtOffset<uint32_t>( | |
| message, schema_.GetOneofCaseOffset(oneof_descriptor)); | |
| } | |
| const ExtensionSet& Reflection::GetExtensionSet(const Message& message) const { | |
| return GetConstRefAtOffset<ExtensionSet>(message, | |
| schema_.GetExtensionSetOffset()); | |
| } | |
| ExtensionSet* Reflection::MutableExtensionSet(Message* message) const { | |
| return GetPointerAtOffset<ExtensionSet>(message, | |
| schema_.GetExtensionSetOffset()); | |
| } | |
| bool Reflection::IsImplicitPresenceFieldNonEmpty( | |
| const Message& message, const FieldDescriptor* field) const { | |
| ABSL_DCHECK(IsMapEntry(field) || !field->has_presence()); | |
| ABSL_DCHECK(field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE || | |
| field->is_repeated()); | |
| if (field->is_repeated()) { | |
| return !IsRepeatedOrMapFieldEmpty(message, field); | |
| } | |
| // Scalar primitive (numeric or string/bytes) fields are present if | |
| // their value is non-zero (numeric) or non-empty (string/bytes). N.B.: | |
| // we must use this definition here, rather than the "scalar fields | |
| // always present" in the proto3 docs, because MergeFrom() semantics | |
| // require presence as "present on wire", and reflection-based merge | |
| // (which uses HasField()) needs to be consistent with this. | |
| switch (field->cpp_type()) { | |
| case FieldDescriptor::CPPTYPE_BOOL: | |
| return GetRaw<bool>(message, field) != false; | |
| case FieldDescriptor::CPPTYPE_INT32: | |
| return GetRaw<int32_t>(message, field) != 0; | |
| case FieldDescriptor::CPPTYPE_INT64: | |
| return GetRaw<int64_t>(message, field) != 0; | |
| case FieldDescriptor::CPPTYPE_UINT32: | |
| return GetRaw<uint32_t>(message, field) != 0; | |
| case FieldDescriptor::CPPTYPE_UINT64: | |
| return GetRaw<uint64_t>(message, field) != 0; | |
| case FieldDescriptor::CPPTYPE_FLOAT: | |
| static_assert(sizeof(uint32_t) == sizeof(float), | |
| "Code assumes uint32_t and float are the same size."); | |
| return absl::bit_cast<uint32_t>(GetRaw<float>(message, field)) != 0; | |
| case FieldDescriptor::CPPTYPE_DOUBLE: | |
| static_assert(sizeof(uint64_t) == sizeof(double), | |
| "Code assumes uint64_t and double are the same size."); | |
| return absl::bit_cast<uint64_t>(GetRaw<double>(message, field)) != 0; | |
| case FieldDescriptor::CPPTYPE_ENUM: | |
| return GetRaw<int>(message, field) != 0; | |
| case FieldDescriptor::CPPTYPE_STRING: | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| return !GetField<const absl::Cord>(message, field).empty(); | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: { | |
| if (IsInlined(field)) { | |
| return !GetField<InlinedStringField>(message, field) | |
| .GetNoArena() | |
| .empty(); | |
| } else if (IsMicroString(field)) { | |
| return !GetField<MicroString>(message, field).Get().empty(); | |
| } | |
| return !GetField<ArenaStringPtr>(message, field).Get().empty(); | |
| } | |
| default: | |
| internal::Unreachable(); | |
| } | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| default: | |
| internal::Unreachable(); | |
| } | |
| } | |
| bool Reflection::IsFieldPresentGivenHasbits(const Message& message, | |
| const FieldDescriptor* field, | |
| const uint32_t* hasbits, | |
| uint32_t hasbit_index) const { | |
| // If hasbit exists but is not set, field is guaranteed to be missing. | |
| if (!IsIndexInHasBitSet(hasbits, hasbit_index)) { | |
| return false; | |
| } | |
| // For explicit-presence fields, a set hasbit indicates a present field. | |
| if (field->has_presence()) { | |
| return true; | |
| } | |
| // proto3: hasbits are present, but an additional zero check must be | |
| // performed because hasbit can be set to true while field is zero. | |
| // Handling map entries in proto3: | |
| // Implicit presence map fields are represented as a native C++ map, but their | |
| // corresponding MapEntry messages (e.g. if we want to access them as repeated | |
| // MapEntry fields) will unconditionally be generated with hasbits. MapEntrys | |
| // behave like explicit presence fields. That is, in MapEntry's C++ | |
| // implementation... | |
| // - key can be null, empty, or nonempty; | |
| // - value can be null, empty, or nonempty. | |
| if (IsMapEntry(field)) { | |
| return true; | |
| } | |
| // This is the vanilla case: for a non-repeated primitive or string field, | |
| // returns if the field is nonzero (i.e. present in proto3 semantics). | |
| return IsImplicitPresenceFieldNonEmpty(message, field); | |
| } | |
| bool Reflection::HasFieldWithHasbits(const Message& message, | |
| const FieldDescriptor* field) const { | |
| ABSL_DCHECK(!field->options().weak()); | |
| ABSL_DCHECK(!field->is_extension()); | |
| if (schema_.HasBitIndex(field) != static_cast<uint32_t>(kNoHasbit)) { | |
| return IsFieldPresentGivenHasbits(message, field, GetHasBits(message), | |
| schema_.HasBitIndex(field)); | |
| } | |
| if (field->is_repeated()) { | |
| return !IsRepeatedOrMapFieldEmpty(message, field); | |
| } | |
| // The python implementation traditionally assumes that proto3 messages don't | |
| // have hasbits. As a result, proto3 objects created through dynamic message | |
| // in Python won't have hasbits. We need the following code to preserve | |
| // compatibility. | |
| // NOTE: It would be nice to be able to remove it, but we need one | |
| // or more breaking changes in order to do so. | |
| // | |
| // proto3 with no has-bits. All fields present except messages, which are | |
| // present only if their message-field pointer is non-null. | |
| if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | |
| return !schema_.IsDefaultInstance(message) && | |
| GetRaw<const Message*>(message, field) != nullptr; | |
| } | |
| // Non-message field (and non-oneof, since that was handled in HasField() | |
| // before calling us). | |
| return IsImplicitPresenceFieldNonEmpty(message, field); | |
| } | |
| void Reflection::SetHasBit(Message* message, | |
| const FieldDescriptor* field) const { | |
| ABSL_DCHECK(!field->options().weak()); | |
| const uint32_t index = schema_.HasBitIndex(field); | |
| if (index == static_cast<uint32_t>(kNoHasbit)) return; | |
| MutableHasBits(message)[index / 32] |= | |
| (static_cast<uint32_t>(1) << (index % 32)); | |
| } | |
| void Reflection::ClearHasBit(Message* message, | |
| const FieldDescriptor* field) const { | |
| ABSL_DCHECK(!field->options().weak()); | |
| const uint32_t index = schema_.HasBitIndex(field); | |
| if (index == static_cast<uint32_t>(kNoHasbit)) return; | |
| MutableHasBits(message)[index / 32] &= | |
| ~(static_cast<uint32_t>(1) << (index % 32)); | |
| } | |
| void Reflection::NaiveSwapHasBit(Message* message1, Message* message2, | |
| const FieldDescriptor* field) const { | |
| ABSL_DCHECK(!field->options().weak()); | |
| if (!schema_.HasHasbits() || | |
| schema_.HasBitIndex(field) == static_cast<uint32_t>(kNoHasbit)) { | |
| return; | |
| } | |
| const Reflection* r1 = message1->GetReflection(); | |
| const Reflection* r2 = message2->GetReflection(); | |
| bool is_m1_hasbit_set = IsIndexInHasBitSet(r1->GetHasBits(*message1), | |
| r1->schema_.HasBitIndex(field)); | |
| bool is_m2_hasbit_set = IsIndexInHasBitSet(r2->GetHasBits(*message2), | |
| r2->schema_.HasBitIndex(field)); | |
| if (is_m1_hasbit_set) { | |
| SetHasBit(message2, field); | |
| } else { | |
| ClearHasBit(message2, field); | |
| } | |
| if (is_m2_hasbit_set) { | |
| SetHasBit(message1, field); | |
| } else { | |
| ClearHasBit(message1, field); | |
| } | |
| } | |
| bool Reflection::HasOneof(const Message& message, | |
| const OneofDescriptor* oneof_descriptor) const { | |
| if (oneof_descriptor->is_synthetic()) { | |
| return HasField(message, oneof_descriptor->field(0)); | |
| } | |
| return (GetOneofCase(message, oneof_descriptor) > 0); | |
| } | |
| void Reflection::SetOneofCase(Message* message, | |
| const FieldDescriptor* field) const { | |
| *MutableOneofCase(message, field->containing_oneof()) = field->number(); | |
| } | |
| void Reflection::ClearOneofField(Message* message, | |
| const FieldDescriptor* field) const { | |
| if (HasOneofField(*message, field)) { | |
| ClearOneof(message, field->containing_oneof()); | |
| } | |
| } | |
| void Reflection::ClearOneof(Message* message, | |
| const OneofDescriptor* oneof_descriptor) const { | |
| if (oneof_descriptor->is_synthetic()) { | |
| ClearField(message, oneof_descriptor->field(0)); | |
| return; | |
| } | |
| // TODO: Consider to cache the unused object instead of deleting | |
| // it. It will be much faster if an application switches a lot from | |
| // a few oneof fields. Time/space tradeoff | |
| uint32_t oneof_case = GetOneofCase(*message, oneof_descriptor); | |
| if (oneof_case > 0) { | |
| const FieldDescriptor* field = descriptor_->FindFieldByNumber(oneof_case); | |
| if (message->GetArena() == nullptr) { | |
| switch (field->cpp_type()) { | |
| case FieldDescriptor::CPPTYPE_STRING: { | |
| switch (field->cpp_string_type()) { | |
| case FieldDescriptor::CppStringType::kCord: | |
| delete *MutableRaw<absl::Cord*>(message, field); | |
| break; | |
| case FieldDescriptor::CppStringType::kView: | |
| case FieldDescriptor::CppStringType::kString: | |
| if (IsMicroString(field)) { | |
| MutableField<MicroString>(message, field)->Destroy(); | |
| } else { | |
| // Oneof string fields are never set as a default instance. | |
| // We just need to pass some arbitrary default string to make it | |
| // work. This allows us to not have the real default accessible | |
| // from reflection. | |
| MutableField<ArenaStringPtr>(message, field)->Destroy(); | |
| } | |
| break; | |
| } | |
| break; | |
| } | |
| case FieldDescriptor::CPPTYPE_MESSAGE: | |
| delete *MutableRaw<Message*>(message, field); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| *MutableOneofCase(message, oneof_descriptor) = 0; | |
| } | |
| } | |
| #define HANDLE_TYPE(TYPE, CPPTYPE, CTYPE) \ | |
| template <> \ | |
| const RepeatedField<TYPE>& Reflection::GetRepeatedFieldInternal<TYPE>( \ | |
| const Message& message, const FieldDescriptor* field) const { \ | |
| return *static_cast<const RepeatedField<TYPE>*>( \ | |
| GetRawRepeatedField(message, field, CPPTYPE, CTYPE, nullptr)); \ | |
| } \ | |
| \ | |
| template <> \ | |
| RepeatedField<TYPE>* Reflection::MutableRepeatedFieldInternal<TYPE>( \ | |
| Message * message, const FieldDescriptor* field) const { \ | |
| if (!field->is_extension()) { \ | |
| SetHasBitForRepeated(message, field); \ | |
| } \ | |
| return static_cast<RepeatedField<TYPE>*>( \ | |
| MutableRawRepeatedField(message, field, CPPTYPE, CTYPE, nullptr)); \ | |
| } | |
| HANDLE_TYPE(int32_t, FieldDescriptor::CPPTYPE_INT32, -1); | |
| HANDLE_TYPE(int64_t, FieldDescriptor::CPPTYPE_INT64, -1); | |
| HANDLE_TYPE(uint32_t, FieldDescriptor::CPPTYPE_UINT32, -1); | |
| HANDLE_TYPE(uint64_t, FieldDescriptor::CPPTYPE_UINT64, -1); | |
| HANDLE_TYPE(float, FieldDescriptor::CPPTYPE_FLOAT, -1); | |
| HANDLE_TYPE(double, FieldDescriptor::CPPTYPE_DOUBLE, -1); | |
| HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1); | |
| #undef HANDLE_TYPE | |
| const void* Reflection::GetRawRepeatedString(const Message& message, | |
| const FieldDescriptor* field, | |
| bool is_string) const { | |
| (void)is_string; // Parameter is used by Google-internal code. | |
| return GetRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_STRING, | |
| FieldOptions::STRING, nullptr); | |
| } | |
| void* Reflection::MutableRawRepeatedString(Message* message, | |
| const FieldDescriptor* field, | |
| bool is_string) const { | |
| (void)is_string; // Parameter is used by Google-internal code. | |
| return MutableRawRepeatedField(message, field, | |
| FieldDescriptor::CPPTYPE_STRING, | |
| FieldOptions::STRING, nullptr); | |
| } | |
| // Template implementations of basic accessors. Inline because each | |
| // template instance is only called from one location. These are | |
| // used for all types except messages. | |
| template <typename Type> | |
| const Type& Reflection::GetField(const Message& message, | |
| const FieldDescriptor* field) const { | |
| return GetRaw<Type>(message, field); | |
| } | |
| template <typename Type> | |
| void Reflection::SetField(Message* message, const FieldDescriptor* field, | |
| const Type& value) const { | |
| bool real_oneof = schema_.InRealOneof(field); | |
| if (real_oneof && !HasOneofField(*message, field)) { | |
| ClearOneof(message, field->containing_oneof()); | |
| } | |
| *MutableRaw<Type>(message, field) = value; | |
| real_oneof ? SetOneofCase(message, field) : SetHasBit(message, field); | |
| } | |
| template <typename Type> | |
| Type* Reflection::MutableField(Message* message, | |
| const FieldDescriptor* field) const { | |
| schema_.InRealOneof(field) ? SetOneofCase(message, field) | |
| : SetHasBit(message, field); | |
| return MutableRaw<Type>(message, field); | |
| } | |
| template <typename Type> | |
| const Type& Reflection::GetRepeatedField(const Message& message, | |
| const FieldDescriptor* field, | |
| int index) const { | |
| return GetRaw<RepeatedField<Type>>(message, field).Get(index); | |
| } | |
| template <typename Type> | |
| const Type& Reflection::GetRepeatedPtrField(const Message& message, | |
| const FieldDescriptor* field, | |
| int index) const { | |
| return GetRaw<RepeatedPtrField<Type>>(message, field).Get(index); | |
| } | |
| template <typename Type> | |
| void Reflection::SetRepeatedField(Message* message, | |
| const FieldDescriptor* field, int index, | |
| Type value) const { | |
| MutableRaw<RepeatedField<Type>>(message, field)->Set(index, value); | |
| } | |
| template <typename Type> | |
| Type* Reflection::MutableRepeatedField(Message* message, | |
| const FieldDescriptor* field, | |
| int index) const { | |
| RepeatedPtrField<Type>* repeated = | |
| MutableRaw<RepeatedPtrField<Type>>(message, field); | |
| return repeated->Mutable(index); | |
| } | |
| template <typename Type> | |
| void Reflection::AddField(Message* message, const FieldDescriptor* field, | |
| const Type& value) const { | |
| MutableRaw<RepeatedField<Type>>(message, field) | |
| ->AddWithArena(message->GetArena(), value); | |
| SetHasBitForRepeated(message, field); | |
| } | |
| template <typename Type> | |
| Type* Reflection::AddField(Message* message, | |
| const FieldDescriptor* field) const { | |
| RepeatedPtrField<Type>* repeated = | |
| MutableRaw<RepeatedPtrField<Type>>(message, field); | |
| SetHasBitForRepeated(message, field); | |
| return repeated->AddWithArena(message->GetArena()); | |
| } | |
| MessageFactory* Reflection::GetMessageFactory() const { | |
| return message_factory_; | |
| } | |
| const void* Reflection::RepeatedFieldData( | |
| const Message& message, const FieldDescriptor* field, | |
| FieldDescriptor::CppType cpp_type, const Descriptor* message_type) const { | |
| ABSL_CHECK(field->is_repeated()); | |
| ABSL_CHECK(field->cpp_type() == cpp_type || | |
| (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM && | |
| cpp_type == FieldDescriptor::CPPTYPE_INT32)) | |
| << "The type parameter T in RepeatedFieldRef<T> API doesn't match " | |
| << "the actual field type (for enums T should be the generated enum " | |
| << "type or int32_t)."; | |
| if (message_type != nullptr) { | |
| ABSL_CHECK_EQ(message_type, field->message_type()); | |
| } | |
| if (field->is_extension()) { | |
| return GetExtensionSet(message).GetRawRepeatedField( | |
| field->number(), internal::DefaultRawPtr()); | |
| } else { | |
| return &GetRaw<char>(message, field); | |
| } | |
| } | |
| void* Reflection::RepeatedFieldData(Message* message, | |
| const FieldDescriptor* field, | |
| FieldDescriptor::CppType cpp_type, | |
| const Descriptor* message_type) const { | |
| ABSL_CHECK(field->is_repeated()); | |
| ABSL_CHECK(field->cpp_type() == cpp_type || | |
| (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM && | |
| cpp_type == FieldDescriptor::CPPTYPE_INT32)) | |
| << "The type parameter T in RepeatedFieldRef<T> API doesn't match " | |
| << "the actual field type (for enums T should be the generated enum " | |
| << "type or int32_t)."; | |
| if (message_type != nullptr) { | |
| ABSL_CHECK_EQ(message_type, field->message_type()); | |
| } | |
| if (field->is_extension()) { | |
| return MutableExtensionSet(message)->MutableRawRepeatedField( | |
| message->GetArena(), field->number(), field->type(), field->is_packed(), | |
| field); | |
| } else { | |
| return MutableRaw<char>(message, field); | |
| } | |
| } | |
| MapFieldBase* Reflection::MutableMapData(Message* message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK(IsMapFieldInApi(field), GetMapData, "Field is not a map field."); | |
| SetHasBitForRepeated(message, field); | |
| auto* map = MutableRaw<MapFieldBase>(message, field); | |
| map->MutableAccess(); | |
| return map; | |
| } | |
| const MapFieldBase* Reflection::GetMapData(const Message& message, | |
| const FieldDescriptor* field) const { | |
| USAGE_CHECK(IsMapFieldInApi(field), GetMapData, "Field is not a map field."); | |
| const auto* map = &(GetRaw<MapFieldBase>(message, field)); | |
| map->ConstAccess(); | |
| return map; | |
| } | |
| template <typename T> | |
| static uint32_t AlignTo(uint32_t v) { | |
| return (v + alignof(T) - 1) & ~(alignof(T) - 1); | |
| } | |
| static internal::TailCallParseFunc GetFastParseFunction( | |
| internal::TcParseFunction func) { | |
| #define PROTOBUF_TC_PARSE_FUNCTION_X(value) internal::TcParser::value, | |
| static constexpr internal::TailCallParseFunc kFuncs[] = { | |
| {}, PROTOBUF_TC_PARSE_FUNCTION_LIST}; | |
| #undef PROTOBUF_TC_PARSE_FUNCTION_X | |
| const int index = static_cast<int>(func); | |
| if (index < 0 || index >= std::end(kFuncs) - std::begin(kFuncs) || | |
| kFuncs[index] == nullptr) { | |
| ABSL_DLOG(FATAL) << "Failed to find function: " << static_cast<int>(func); | |
| // Let's not crash in opt, just in case. | |
| // MiniParse is always a valid parser. | |
| return &internal::TcParser::MiniParse; | |
| } | |
| return kFuncs[index]; | |
| } | |
| void Reflection::PopulateTcParseFastEntries( | |
| const internal::TailCallTableInfo& table_info, | |
| TcParseTableBase::FastFieldEntry* fast_entries) const { | |
| for (const auto& fast_field : table_info.fast_path_fields) { | |
| if (auto* nonfield = fast_field.AsNonField()) { | |
| // No field, but still a special entry. | |
| *fast_entries++ = {GetFastParseFunction(nonfield->func), | |
| {nonfield->coded_tag, nonfield->nonfield_info}}; | |
| } else if (auto* as_field = fast_field.AsField()) { | |
| *fast_entries++ = { | |
| GetFastParseFunction(as_field->func), | |
| {as_field->coded_tag, as_field->hasbit_idx, as_field->aux_idx, | |
| static_cast<uint16_t>(schema_.GetFieldOffset(as_field->field))}}; | |
| } else { | |
| ABSL_DCHECK(fast_field.is_empty()); | |
| // No fast entry here. Use mini parser. | |
| *fast_entries++ = {internal::TcParser::MiniParse, {}}; | |
| } | |
| } | |
| } | |
| static void PopulateTcParseLookupTable( | |
| const internal::TailCallTableInfo& table_info, uint16_t* lookup_table) { | |
| for (const auto& entry_block : table_info.num_to_entry_table.blocks) { | |
| *lookup_table++ = entry_block.first_fnum & 0xFFFF; | |
| *lookup_table++ = entry_block.first_fnum >> 16; | |
| *lookup_table++ = entry_block.entries.size(); | |
| for (auto se16 : entry_block.entries) { | |
| *lookup_table++ = se16.skipmap; | |
| *lookup_table++ = se16.field_entry_offset; | |
| } | |
| } | |
| *lookup_table++ = 0xFFFF; | |
| *lookup_table++ = 0xFFFF; | |
| } | |
| static std::vector<uint32_t> MakeEnumValidatorData(const EnumDescriptor* desc) { | |
| std::vector<int> numbers; | |
| numbers.reserve(desc->value_count()); | |
| for (int i = 0; i < desc->value_count(); ++i) { | |
| numbers.push_back(desc->value(i)->number()); | |
| } | |
| absl::c_sort(numbers); | |
| numbers.erase(std::unique(numbers.begin(), numbers.end()), numbers.end()); | |
| return internal::GenerateEnumData(numbers); | |
| } | |
| void Reflection::PopulateTcParseEntries( | |
| internal::TailCallTableInfo& table_info, | |
| TcParseTableBase::FieldEntry* entries) const { | |
| for (const auto& entry : table_info.field_entries) { | |
| const FieldDescriptor* field = entry.field; | |
| const OneofDescriptor* oneof = field->real_containing_oneof(); | |
| entries->offset = schema_.GetFieldOffset(field); | |
| if (oneof != nullptr) { | |
| entries->has_idx = schema_.oneof_case_offset_ + 4 * oneof->index(); | |
| } else if (schema_.HasHasbits()) { | |
| entries->has_idx = | |
| entry.hasbit_idx >= 0 | |
| ? static_cast<int>(8 * schema_.HasBitsOffset() + entry.hasbit_idx) | |
| : kNoHasbit; | |
| } else { | |
| entries->has_idx = 0; | |
| } | |
| entries->aux_idx = entry.aux_idx; | |
| entries->type_card = entry.type_card; | |
| ++entries; | |
| } | |
| } | |
| void Reflection::PopulateTcParseFieldAux( | |
| const internal::TailCallTableInfo& table_info, | |
| TcParseTableBase::FieldAux* field_aux) const { | |
| for (const auto& aux_entry : table_info.aux_entries) { | |
| switch (aux_entry.type) { | |
| case internal::TailCallTableInfo::kNothing: | |
| *field_aux++ = {}; | |
| break; | |
| case internal::TailCallTableInfo::kSplitOffset: | |
| field_aux++->offset = schema_.SplitOffset(); | |
| break; | |
| case internal::TailCallTableInfo::kSplitSizeof: | |
| field_aux++->offset = schema_.SizeofSplit(); | |
| break; | |
| case internal::TailCallTableInfo::kSubTable: | |
| case internal::TailCallTableInfo::kSubMessageWeak: | |
| case internal::TailCallTableInfo::kMessageVerifyFunc: | |
| case internal::TailCallTableInfo::kSelfVerifyFunc: | |
| ABSL_LOG(FATAL) << "Not supported"; | |
| break; | |
| case internal::TailCallTableInfo::kMapAuxInfo: | |
| // TODO: Fix this now that dynamic uses normal map ABIs. | |
| // Default constructed info, which causes MpMap to call the fallback. | |
| // DynamicMessage uses DynamicMapField, which uses variant keys and | |
| // values. TcParser does not support them yet, so mark the field as | |
| // unsupported to fallback to reflection. | |
| field_aux++->map_info = internal::MapAuxInfo{}; | |
| break; | |
| case internal::TailCallTableInfo::kSubMessage: | |
| field_aux++->message_default_p = | |
| GetDefaultMessageInstance(aux_entry.field); | |
| break; | |
| case internal::TailCallTableInfo::kEnumRange: | |
| field_aux++->enum_range = {aux_entry.enum_range.first, | |
| aux_entry.enum_range.last}; | |
| break; | |
| case internal::TailCallTableInfo::kEnumValidator: | |
| field_aux++->enum_data = | |
| DescriptorPool::MemoizeProjection( | |
| aux_entry.field->enum_type(), | |
| [](auto* e) { return MakeEnumValidatorData(e); }) | |
| .data(); | |
| break; | |
| case internal::TailCallTableInfo::kNumericOffset: | |
| field_aux++->offset = aux_entry.offset; | |
| break; | |
| } | |
| } | |
| } | |
| const internal::TcParseTableBase* Reflection::CreateTcParseTable() const { | |
| using TcParseTableBase = internal::TcParseTableBase; | |
| std::vector<internal::TailCallTableInfo::FieldOptions> fields; | |
| fields.reserve(descriptor_->field_count()); | |
| for (int i = 0; i < descriptor_->field_count(); ++i) { | |
| auto* field = descriptor_->field(i); | |
| const bool is_inlined = IsInlined(field); | |
| fields.push_back({ | |
| field, // | |
| static_cast<int>(schema_.HasBitIndex(field)), | |
| 1.f, // All fields are assumed present. | |
| GetLazyStyle(field), | |
| is_inlined, | |
| // Only LITE can be implicitly weak. | |
| /* is_implicitly_weak */ false, | |
| // We could change this to use direct table. | |
| // Might be easier to do when all messages support TDP. | |
| /* use_direct_tcparser_table */ false, | |
| schema_.IsSplit(field), | |
| field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && | |
| IsMicroString(field), | |
| }); | |
| } | |
| std::sort(fields.begin(), fields.end(), [](const auto& a, const auto& b) { | |
| return a.field->number() < b.field->number(); | |
| }); | |
| internal::TailCallTableInfo table_info( | |
| descriptor_, | |
| { | |
| /* is_lite */ false, | |
| /* uses_codegen */ false, | |
| }, | |
| fields); | |
| const size_t fast_entries_count = table_info.fast_path_fields.size(); | |
| ABSL_CHECK_EQ(static_cast<int>(fast_entries_count), | |
| 1 << table_info.table_size_log2); | |
| const uint16_t lookup_table_offset = AlignTo<uint16_t>( | |
| sizeof(TcParseTableBase) + | |
| fast_entries_count * sizeof(TcParseTableBase::FastFieldEntry)); | |
| const uint32_t field_entry_offset = AlignTo<TcParseTableBase::FieldEntry>( | |
| lookup_table_offset + | |
| sizeof(uint16_t) * table_info.num_to_entry_table.size16()); | |
| const uint32_t aux_offset = AlignTo<TcParseTableBase::FieldAux>( | |
| field_entry_offset + | |
| sizeof(TcParseTableBase::FieldEntry) * fields.size()); | |
| int byte_size = | |
| aux_offset + | |
| sizeof(TcParseTableBase::FieldAux) * table_info.aux_entries.size() + | |
| sizeof(char) * table_info.field_name_data.size(); | |
| void* p = internal::Allocate(byte_size); | |
| auto* res = ::new (p) TcParseTableBase{ | |
| static_cast<uint16_t>( | |
| schema_.HasHasbits() | |
| ? schema_.HasBitsOffset() | |
| // Just put something safe here. _cached_size_ is fine. | |
| : schema_.default_instance_->GetClassData()->cached_size_offset), | |
| schema_.HasExtensionSet() | |
| ? static_cast<uint16_t>(schema_.GetExtensionSetOffset()) | |
| : uint16_t{0}, | |
| static_cast<uint32_t>(fields.empty() ? 0 : fields.back().field->number()), | |
| static_cast<uint8_t>((fast_entries_count - 1) << 3), | |
| lookup_table_offset, | |
| table_info.num_to_entry_table.skipmap32, | |
| field_entry_offset, | |
| static_cast<uint16_t>(fields.size()), | |
| static_cast<uint16_t>(table_info.aux_entries.size()), | |
| aux_offset, | |
| schema_.default_instance_->GetClassData(), | |
| nullptr, | |
| GetFastParseFunction(table_info.fallback_function) | |
| #ifdef PROTOBUF_PREFETCH_PARSE_TABLE | |
| , | |
| nullptr | |
| #endif // PROTOBUF_PREFETCH_PARSE_TABLE | |
| }; | |
| #ifdef PROTOBUF_PREFETCH_PARSE_TABLE | |
| // We'll prefetch `to_prefetch->to_prefetch` unconditionally to avoid | |
| // branches. Here we don't know which field is the hottest, so set the pointer | |
| // to itself to avoid nullptr. | |
| res->to_prefetch = res; | |
| #endif // PROTOBUF_PREFETCH_PARSE_TABLE | |
| // Now copy the rest of the payloads | |
| PopulateTcParseFastEntries(table_info, res->fast_entry(0)); | |
| PopulateTcParseLookupTable(table_info, res->field_lookup_begin()); | |
| PopulateTcParseEntries(table_info, res->field_entries_begin()); | |
| PopulateTcParseFieldAux(table_info, res->field_aux(0u)); | |
| // Copy the name data. | |
| if (!table_info.field_name_data.empty()) { | |
| memcpy(res->name_data(), table_info.field_name_data.data(), | |
| table_info.field_name_data.size()); | |
| } | |
| // Validation to make sure we used all the bytes correctly. | |
| ABSL_CHECK_EQ(res->name_data() + table_info.field_name_data.size() - | |
| reinterpret_cast<char*>(res), | |
| byte_size) | |
| << "message = " << descriptor_->full_name(); | |
| return res; | |
| } | |
| namespace { | |
| // Helper function to transform migration schema into reflection schema. | |
| ReflectionSchema MigrationToReflectionSchema( | |
| const Message* const* default_instance, const uint32_t* offsets, | |
| MigrationSchema migration_schema) { | |
| ReflectionSchema result; | |
| result.default_instance_ = *default_instance; | |
| int index = migration_schema.offsets_index; | |
| // First values are offsets to the special fields, but they are optional. | |
| // The first value is a bitmap marking which fields are present. | |
| // The order of the fields must match MessageGenerator::GenerateOffsets | |
| // | |
| // To add new fields, we add them at the end and since they are optional the | |
| // bootstrap files will automatically look as if those fields are not present. | |
| const uint32_t bits = offsets[index++]; | |
| int bit = 0; | |
| const auto next = [&] { | |
| return (bits & (1 << bit++)) ? offsets[index++] : ~uint32_t{}; | |
| }; | |
| const auto next_pointer = [&]() -> const uint32_t* { | |
| const uint32_t n = next(); | |
| if (n == ~uint32_t{}) { | |
| return nullptr; | |
| } | |
| return offsets + migration_schema.offsets_index + n; | |
| }; | |
| result.has_bits_offset_ = next(); | |
| result.extensions_offset_ = next(); | |
| result.oneof_case_offset_ = next(); | |
| result.weak_field_map_offset_ = next(); | |
| // Old result.inlined_string_donated_offset_ | |
| ABSL_CHECK_EQ(next(), ~uint32_t{}); | |
| result.split_offset_ = next(); | |
| result.sizeof_split_ = next(); | |
| result.has_bit_indices_ = next_pointer(); | |
| // Old result.inlined_string_indices_ | |
| ABSL_CHECK_EQ(next_pointer(), nullptr); | |
| result.offsets_ = offsets + index; | |
| result.object_size_ = migration_schema.object_size; | |
| return result; | |
| } | |
| } // namespace | |
| class AssignDescriptorsHelper { | |
| public: | |
| AssignDescriptorsHelper(MessageFactory* factory, | |
| const EnumDescriptor** file_level_enum_descriptors, | |
| const MigrationSchema* schemas, | |
| const Message* const* default_instance_data, | |
| const uint32_t* offsets) | |
| : factory_(factory), | |
| file_level_enum_descriptors_(file_level_enum_descriptors), | |
| schemas_(schemas), | |
| default_instance_data_(default_instance_data), | |
| offsets_(offsets) {} | |
| void AssignMessageDescriptor(const Descriptor* descriptor) { | |
| for (int i = 0; i < descriptor->nested_type_count(); i++) { | |
| AssignMessageDescriptor(descriptor->nested_type(i)); | |
| } | |
| // If there is no default instance we only want to initialize the descriptor | |
| // without updating the reflection. | |
| if (default_instance_data_[0] != nullptr) { | |
| auto& class_data = default_instance_data_[0]->GetClassData()->full(); | |
| // If there is no descriptor_table in the class data, then it is not | |
| // interested in receiving reflection information either. | |
| if (class_data.descriptor_table != nullptr) { | |
| class_data.descriptor = descriptor; | |
| class_data.reflection = OnShutdownDelete(new Reflection( | |
| descriptor, | |
| MigrationToReflectionSchema(default_instance_data_, offsets_, | |
| *schemas_), | |
| DescriptorPool::internal_generated_pool(), factory_)); | |
| } | |
| } | |
| for (int i = 0; i < descriptor->enum_type_count(); i++) { | |
| AssignEnumDescriptor(descriptor->enum_type(i)); | |
| } | |
| schemas_++; | |
| default_instance_data_++; | |
| } | |
| void AssignEnumDescriptor(const EnumDescriptor* descriptor) { | |
| *file_level_enum_descriptors_ = descriptor; | |
| file_level_enum_descriptors_++; | |
| } | |
| private: | |
| MessageFactory* factory_; | |
| const EnumDescriptor** file_level_enum_descriptors_; | |
| const MigrationSchema* schemas_; | |
| const Message* const* default_instance_data_; | |
| const uint32_t* offsets_; | |
| }; | |
| namespace { | |
| void AssignDescriptorsImpl(const DescriptorTable* table, bool eager) { | |
| // Ensure the file descriptor is added to the pool. | |
| { | |
| // This only happens once per proto file. So a global mutex to serialize | |
| // calls to AddDescriptors. | |
| static absl::Mutex mu{absl::kConstInit}; | |
| mu.Lock(); | |
| AddDescriptors(table); | |
| mu.Unlock(); | |
| } | |
| if (eager) { | |
| // Normally we do not want to eagerly build descriptors of our deps. | |
| // However if this proto is optimized for code size (ie using reflection) | |
| // and it has a message extending a custom option of a descriptor with that | |
| // message being optimized for code size as well. Building the descriptors | |
| // in this file requires parsing the serialized file descriptor, which now | |
| // requires parsing the message extension, which potentially requires | |
| // building the descriptor of the message extending one of the options. | |
| // However we are already updating descriptor pool under a lock. To prevent | |
| // this the compiler statically looks for this case and we just make sure we | |
| // first build the descriptors of all our dependencies, preventing the | |
| // deadlock. | |
| int num_deps = table->num_deps; | |
| for (int i = 0; i < num_deps; i++) { | |
| // In case of weak fields deps[i] could be null. | |
| if (table->deps[i]) { | |
| absl::call_once(*table->deps[i]->once, AssignDescriptorsImpl, | |
| table->deps[i], | |
| /*eager=*/true); | |
| } | |
| } | |
| } | |
| // Fill the arrays with pointers to descriptors and reflection classes. | |
| const FileDescriptor* file = | |
| DescriptorPool::internal_generated_pool()->FindFileByName( | |
| table->filename); | |
| ABSL_CHECK(file != nullptr); | |
| MessageFactory* factory = MessageFactory::generated_factory(); | |
| AssignDescriptorsHelper helper(factory, table->file_level_enum_descriptors, | |
| table->schemas, table->default_instances, | |
| table->offsets); | |
| for (int i = 0; i < file->message_type_count(); i++) { | |
| helper.AssignMessageDescriptor(file->message_type(i)); | |
| } | |
| for (int i = 0; i < file->enum_type_count(); i++) { | |
| helper.AssignEnumDescriptor(file->enum_type(i)); | |
| } | |
| if (file->options().cc_generic_services()) { | |
| for (int i = 0; i < file->service_count(); i++) { | |
| table->file_level_service_descriptors[i] = file->service(i); | |
| } | |
| } | |
| } | |
| void MaybeInitializeLazyDescriptors(const DescriptorTable* table) { | |
| if (!IsLazilyInitializedFile(table->filename)) { | |
| // Ensure the generated pool has been lazily initialized. | |
| (void)DescriptorPool::generated_pool(); | |
| } | |
| } | |
| void AddDescriptorsImpl(const DescriptorTable* table) { | |
| // Reflection refers to the default fields so make sure they are initialized. | |
| internal::InitProtobufDefaults(); | |
| internal::InitializeFileDescriptorDefaultInstances(); | |
| internal::InitializeLazyExtensionSet(); | |
| // Ensure all dependent descriptors are registered to the generated descriptor | |
| // pool and message factory. | |
| int num_deps = table->num_deps; | |
| for (int i = 0; i < num_deps; i++) { | |
| // In case of weak fields deps[i] could be null. | |
| if (table->deps[i]) AddDescriptors(table->deps[i]); | |
| } | |
| // Register the descriptor of this file. | |
| DescriptorPool::InternalAddGeneratedFile(table->descriptor, table->size); | |
| MessageFactory::InternalRegisterGeneratedFile(table); | |
| // Ensure that any lazily loaded static initializers from the generated pool | |
| // (e.g. from bootstrapped protos) are run before building any descriptors. We | |
| // have do it in reflection code like this, because we need to ensure that the | |
| // linker --gc-sections step can strip out the full runtime if it is unused. | |
| // If we try to avoid pre-main initialization (e.g. during DescriptorBuilder), | |
| // we hit data races and would need to add locks. | |
| [[maybe_unused]] static std::true_type lazy_register = | |
| (internal::ExtensionSet::RegisterMessageExtension( | |
| &FeatureSet::default_instance(), pb::cpp.number(), | |
| FieldDescriptor::TYPE_MESSAGE, false, false, | |
| &pb::CppFeatures::default_instance(), | |
| nullptr, | |
| internal::LazyAnnotation::kUndefined), | |
| std::true_type{}); | |
| } | |
| } // namespace | |
| namespace internal { | |
| void AddDescriptors(const DescriptorTable* table) { | |
| // AddDescriptors is not thread safe. Callers need to ensure calls are | |
| // properly serialized. This function is only called pre-main by global | |
| // descriptors and we can assume single threaded access or it's called | |
| // by AssignDescriptorImpl which uses a mutex to sequence calls. | |
| if (table->is_initialized) return; | |
| table->is_initialized = true; | |
| AddDescriptorsImpl(table); | |
| } | |
| void AssignDescriptorsOnceInnerCall(const DescriptorTable* table) { | |
| MaybeInitializeLazyDescriptors(table); | |
| AssignDescriptorsImpl(table, table->is_eager); | |
| } | |
| void AssignDescriptors(const DescriptorTable* table) { | |
| absl::call_once(*table->once, [=] { AssignDescriptorsOnceInnerCall(table); }); | |
| } | |
| AddDescriptorsRunner::AddDescriptorsRunner(const DescriptorTable* table) { | |
| AddDescriptors(table); | |
| } | |
| void RegisterFileLevelMetadata(const DescriptorTable* table) { | |
| AssignDescriptors(table); | |
| auto* file = DescriptorPool::internal_generated_pool()->FindFileByName( | |
| table->filename); | |
| auto defaults = table->default_instances; | |
| internal::cpp::VisitDescriptorsInFileOrder(file, [&](auto* desc) { | |
| MessageFactory::InternalRegisterGeneratedMessage(desc, *defaults); | |
| ++defaults; | |
| return std::false_type{}; | |
| }); | |
| } | |
| void UnknownFieldSetSerializer(const uint8_t* base, uint32_t offset, | |
| uint32_t /*tag*/, uint32_t /*has_offset*/, | |
| io::CodedOutputStream* output) { | |
| const void* ptr = base + offset; | |
| const InternalMetadata* metadata = static_cast<const InternalMetadata*>(ptr); | |
| if (metadata->have_unknown_fields()) { | |
| // TODO: Remove this suppression. | |
| (void)metadata | |
| ->unknown_fields<UnknownFieldSet>(UnknownFieldSet::default_instance) | |
| .SerializeToCodedStream(output); | |
| } | |
| } | |
| bool IsDescendant(const Message& root, const Message& message) { | |
| const Reflection* reflection = root.GetReflection(); | |
| std::vector<const FieldDescriptor*> fields; | |
| reflection->ListFields(root, &fields); | |
| for (const auto* field : fields) { | |
| // Skip non-message fields. | |
| if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue; | |
| // Optional messages. | |
| if (!field->is_repeated()) { | |
| const Message& sub_message = reflection->GetMessage(root, field); | |
| if (&sub_message == &message || IsDescendant(sub_message, message)) { | |
| return true; | |
| } | |
| continue; | |
| } | |
| if (IsMapFieldInApi(field)) { | |
| // Map field: if accessed as repeated fields, messages are *copied* and | |
| // matching pointer won't work. Must directly access map. | |
| constexpr int kValIdx = 1; | |
| const FieldDescriptor* val_field = field->message_type()->field(kValIdx); | |
| // Skip map fields whose value type is not message. | |
| if (val_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue; | |
| const auto& map = reflection->GetRaw<MapFieldBase>(root, field); | |
| if (map.IsMapValid()) { | |
| const auto end = reflection->ConstMapEnd(&root, field); | |
| for (auto iter = reflection->ConstMapBegin(&root, field); iter != end; | |
| ++iter) { | |
| const Message& sub_message = iter.GetValueRef().GetMessageValue(); | |
| if (&sub_message == &message || IsDescendant(sub_message, message)) { | |
| return true; | |
| } | |
| } | |
| continue; | |
| } | |
| // If the map is in state STATE_MODIFIED_REPEATED, then accessing it as a | |
| // repeated message field will not require syncing. | |
| } | |
| // Repeated messages. | |
| int count = reflection->FieldSize(root, field); | |
| for (int i = 0; i < count; i++) { | |
| const Message& sub_message = | |
| reflection->GetRepeatedMessage(root, field, i); | |
| if (&sub_message == &message || IsDescendant(sub_message, message)) { | |
| return true; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| bool SplitFieldHasExtraIndirection(const FieldDescriptor* field) { | |
| return field->is_repeated(); | |
| } | |
| #if defined(PROTOBUF_DESCRIPTOR_WEAK_MESSAGES_ALLOWED) | |
| const Message* GetPrototypeForWeakDescriptor(const DescriptorTable* table, | |
| int index, bool force_build) { | |
| // First, make sure we inject the surviving default instances. | |
| InitProtobufDefaults(); | |
| // Now check if the table has it. If so, return it. | |
| if (const auto* msg = table->default_instances[index]) { | |
| return msg; | |
| } | |
| if (!force_build) { | |
| return nullptr; | |
| } | |
| // Fallback to dynamic messages. | |
| // Register the dep and generate the prototype via the generated pool. | |
| AssignDescriptors(table); | |
| const FileDescriptor* file = | |
| DescriptorPool::internal_generated_pool()->FindFileByName( | |
| table->filename); | |
| const Descriptor* descriptor = internal::cpp::VisitDescriptorsInFileOrder( | |
| file, [&](auto* desc) -> const Descriptor* { | |
| if (index == 0) return desc; | |
| --index; | |
| return nullptr; | |
| }); | |
| return MessageFactory::generated_factory()->GetPrototype(descriptor); | |
| } | |
| #endif // PROTOBUF_DESCRIPTOR_WEAK_MESSAGES_ALLOWED | |
| } // namespace internal | |
| } // namespace protobuf | |
| } // namespace google | |
| #include "google/protobuf/port_undef.inc" |