// 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()) {
      const uint32_t field_offset = schema_.GetFieldOffset(as_field->field);
      if (static_cast<uint16_t>(field_offset) == field_offset) {
        *fast_entries++ = {
            GetFastParseFunction(as_field->func),
            {as_field->coded_tag, as_field->hasbit_idx, as_field->aux_idx,
             static_cast<uint16_t>(field_offset)}};
      } else {
        // The offset is too large, so just ignore the fast field.
        *fast_entries++ = {internal::TcParser::MiniParse, {}};
      }
    } 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"
