void ExtensionSet::Swap()

in extra/protobuf/protobuf-24.4/src/google/protobuf/extension_set.cc [1126:1973]


void ExtensionSet::Swap(const MessageLite* extendee, ExtensionSet* other) {
#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
  if (GetArena() != nullptr && GetArena() == other->GetArena()) {
#else   // PROTOBUF_FORCE_COPY_IN_SWAP
  if (GetArena() == other->GetArena()) {
#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
    InternalSwap(other);
  } else {
    // TODO(cfallin, rohananil): We maybe able to optimize a case where we are
    // swapping from heap to arena-allocated extension set, by just Own()'ing
    // the extensions.
    ExtensionSet extension_set;
    extension_set.MergeFrom(extendee, *other);
    other->Clear();
    other->MergeFrom(extendee, *this);
    Clear();
    MergeFrom(extendee, extension_set);
  }
}

void ExtensionSet::InternalSwap(ExtensionSet* other) {
  using std::swap;
  swap(arena_, other->arena_);
  swap(flat_capacity_, other->flat_capacity_);
  swap(flat_size_, other->flat_size_);
  swap(map_, other->map_);
}

void ExtensionSet::SwapExtension(const MessageLite* extendee,
                                 ExtensionSet* other, int number) {
  if (this == other) return;

  if (GetArena() == other->GetArena()) {
    UnsafeShallowSwapExtension(other, number);
    return;
  }

  Extension* this_ext = FindOrNull(number);
  Extension* other_ext = other->FindOrNull(number);

  if (this_ext == other_ext) return;

  if (this_ext != nullptr && other_ext != nullptr) {
    // TODO(cfallin, rohananil): We could further optimize these cases,
    // especially avoid creation of ExtensionSet, and move MergeFrom logic
    // into Extensions itself (which takes arena as an argument).
    // We do it this way to reuse the copy-across-arenas logic already
    // implemented in ExtensionSet's MergeFrom.
    ExtensionSet temp;
    temp.InternalExtensionMergeFrom(extendee, number, *other_ext,
                                    other->GetArena());
    Extension* temp_ext = temp.FindOrNull(number);

    other_ext->Clear();
    other->InternalExtensionMergeFrom(extendee, number, *this_ext,
                                      this->GetArena());
    this_ext->Clear();
    InternalExtensionMergeFrom(extendee, number, *temp_ext, temp.GetArena());
  } else if (this_ext == nullptr) {
    InternalExtensionMergeFrom(extendee, number, *other_ext, other->GetArena());
    if (other->GetArena() == nullptr) other_ext->Free();
    other->Erase(number);
  } else {
    other->InternalExtensionMergeFrom(extendee, number, *this_ext,
                                      this->GetArena());
    if (GetArena() == nullptr) this_ext->Free();
    Erase(number);
  }
}

void ExtensionSet::UnsafeShallowSwapExtension(ExtensionSet* other, int number) {
  if (this == other) return;

  Extension* this_ext = FindOrNull(number);
  Extension* other_ext = other->FindOrNull(number);

  if (this_ext == other_ext) return;

  ABSL_DCHECK_EQ(GetArena(), other->GetArena());

  if (this_ext != nullptr && other_ext != nullptr) {
    std::swap(*this_ext, *other_ext);
  } else if (this_ext == nullptr) {
    *Insert(number).first = *other_ext;
    other->Erase(number);
  } else {
    *other->Insert(number).first = *this_ext;
    Erase(number);
  }
}

bool ExtensionSet::IsInitialized(const MessageLite* extendee) const {
  // Extensions are never required.  However, we need to check that all
  // embedded messages are initialized.
  if (PROTOBUF_PREDICT_FALSE(is_large())) {
    for (const auto& kv : *map_.large) {
      if (!kv.second.IsInitialized(this, extendee, kv.first, arena_)) {
        return false;
      }
    }
    return true;
  }
  for (const KeyValue* it = flat_begin(); it != flat_end(); ++it) {
    if (!it->second.IsInitialized(this, extendee, it->first, arena_)) {
      return false;
    }
  }
  return true;
}

const char* ExtensionSet::ParseField(uint64_t tag, const char* ptr,
                                     const MessageLite* extendee,
                                     internal::InternalMetadata* metadata,
                                     internal::ParseContext* ctx) {
  GeneratedExtensionFinder finder(extendee);
  int number = tag >> 3;
  bool was_packed_on_wire;
  ExtensionInfo extension;
  if (!FindExtensionInfoFromFieldNumber(tag & 7, number, &finder, &extension,
                                        &was_packed_on_wire)) {
    return UnknownFieldParse(
        tag, metadata->mutable_unknown_fields<std::string>(), ptr, ctx);
  }
  return ParseFieldWithExtensionInfo<std::string>(
      number, was_packed_on_wire, extension, metadata, ptr, ctx);
}

const char* ExtensionSet::ParseMessageSetItem(
    const char* ptr, const MessageLite* extendee,
    internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
  return ParseMessageSetItemTmpl<MessageLite, std::string>(ptr, extendee,
                                                           metadata, ctx);
}

uint8_t* ExtensionSet::_InternalSerializeImpl(
    const MessageLite* extendee, int start_field_number, int end_field_number,
    uint8_t* target, io::EpsCopyOutputStream* stream) const {
  if (PROTOBUF_PREDICT_FALSE(is_large())) {
    const auto& end = map_.large->end();
    for (auto it = map_.large->lower_bound(start_field_number);
         it != end && it->first < end_field_number; ++it) {
      target = it->second.InternalSerializeFieldWithCachedSizesToArray(
          extendee, this, it->first, target, stream);
    }
    return target;
  }
  const KeyValue* end = flat_end();
  for (const KeyValue* it = std::lower_bound(
           flat_begin(), end, start_field_number, KeyValue::FirstComparator());
       it != end && it->first < end_field_number; ++it) {
    target = it->second.InternalSerializeFieldWithCachedSizesToArray(
        extendee, this, it->first, target, stream);
  }
  return target;
}

uint8_t* ExtensionSet::InternalSerializeMessageSetWithCachedSizesToArray(
    const MessageLite* extendee, uint8_t* target,
    io::EpsCopyOutputStream* stream) const {
  const ExtensionSet* extension_set = this;
  ForEach([&target, extendee, stream, extension_set](int number,
                                                     const Extension& ext) {
    target = ext.InternalSerializeMessageSetItemWithCachedSizesToArray(
        extendee, extension_set, number, target, stream);
  });
  return target;
}

size_t ExtensionSet::ByteSize() const {
  size_t total_size = 0;
  ForEach([&total_size](int number, const Extension& ext) {
    total_size += ext.ByteSize(number);
  });
  return total_size;
}

// Defined in extension_set_heavy.cc.
// int ExtensionSet::SpaceUsedExcludingSelf() const

bool ExtensionSet::MaybeNewExtension(int number,
                                     const FieldDescriptor* descriptor,
                                     Extension** result) {
  bool extension_is_new = false;
  std::tie(*result, extension_is_new) = Insert(number);
  (*result)->descriptor = descriptor;
  return extension_is_new;
}

// ===================================================================
// Methods of ExtensionSet::Extension

void ExtensionSet::Extension::Clear() {
  if (is_repeated) {
    switch (cpp_type(type)) {
#define HANDLE_TYPE(UPPERCASE, LOWERCASE)   \
  case WireFormatLite::CPPTYPE_##UPPERCASE: \
    repeated_##LOWERCASE##_value->Clear();  \
    break

      HANDLE_TYPE(INT32, int32_t);
      HANDLE_TYPE(INT64, int64_t);
      HANDLE_TYPE(UINT32, uint32_t);
      HANDLE_TYPE(UINT64, uint64_t);
      HANDLE_TYPE(FLOAT, float);
      HANDLE_TYPE(DOUBLE, double);
      HANDLE_TYPE(BOOL, bool);
      HANDLE_TYPE(ENUM, enum);
      HANDLE_TYPE(STRING, string);
      HANDLE_TYPE(MESSAGE, message);
#undef HANDLE_TYPE
    }
  } else {
    if (!is_cleared) {
      switch (cpp_type(type)) {
        case WireFormatLite::CPPTYPE_STRING:
          string_value->clear();
          break;
        case WireFormatLite::CPPTYPE_MESSAGE:
          if (is_lazy) {
            lazymessage_value->Clear();
          } else {
            message_value->Clear();
          }
          break;
        default:
          // No need to do anything.  Get*() will return the default value
          // as long as is_cleared is true and Set*() will overwrite the
          // previous value.
          break;
      }

      is_cleared = true;
    }
  }
}

size_t ExtensionSet::Extension::ByteSize(int number) const {
  size_t result = 0;

  if (is_repeated) {
    if (is_packed) {
      switch (real_type(type)) {
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
  case WireFormatLite::TYPE_##UPPERCASE:                             \
    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
      result += WireFormatLite::CAMELCASE##Size(                     \
          repeated_##LOWERCASE##_value->Get(i));                     \
    }                                                                \
    break

        HANDLE_TYPE(INT32, Int32, int32_t);
        HANDLE_TYPE(INT64, Int64, int64_t);
        HANDLE_TYPE(UINT32, UInt32, uint32_t);
        HANDLE_TYPE(UINT64, UInt64, uint64_t);
        HANDLE_TYPE(SINT32, SInt32, int32_t);
        HANDLE_TYPE(SINT64, SInt64, int64_t);
        HANDLE_TYPE(ENUM, Enum, enum);
#undef HANDLE_TYPE

        // Stuff with fixed size.
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)             \
  case WireFormatLite::TYPE_##UPPERCASE:                         \
    result += WireFormatLite::k##CAMELCASE##Size *               \
              FromIntSize(repeated_##LOWERCASE##_value->size()); \
    break
        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
        HANDLE_TYPE(FLOAT, Float, float);
        HANDLE_TYPE(DOUBLE, Double, double);
        HANDLE_TYPE(BOOL, Bool, bool);
#undef HANDLE_TYPE

        case WireFormatLite::TYPE_STRING:
        case WireFormatLite::TYPE_BYTES:
        case WireFormatLite::TYPE_GROUP:
        case WireFormatLite::TYPE_MESSAGE:
          ABSL_LOG(FATAL) << "Non-primitive types can't be packed.";
          break;
      }

      cached_size = ToCachedSize(result);
      if (result > 0) {
        result += io::CodedOutputStream::VarintSize32(result);
        result += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
            number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
      }
    } else {
      size_t tag_size = WireFormatLite::TagSize(number, real_type(type));

      switch (real_type(type)) {
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                        \
  case WireFormatLite::TYPE_##UPPERCASE:                                    \
    result += tag_size * FromIntSize(repeated_##LOWERCASE##_value->size()); \
    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) {        \
      result += WireFormatLite::CAMELCASE##Size(                            \
          repeated_##LOWERCASE##_value->Get(i));                            \
    }                                                                       \
    break

        HANDLE_TYPE(INT32, Int32, int32_t);
        HANDLE_TYPE(INT64, Int64, int64_t);
        HANDLE_TYPE(UINT32, UInt32, uint32_t);
        HANDLE_TYPE(UINT64, UInt64, uint64_t);
        HANDLE_TYPE(SINT32, SInt32, int32_t);
        HANDLE_TYPE(SINT64, SInt64, int64_t);
        HANDLE_TYPE(STRING, String, string);
        HANDLE_TYPE(BYTES, Bytes, string);
        HANDLE_TYPE(ENUM, Enum, enum);
        HANDLE_TYPE(GROUP, Group, message);
        HANDLE_TYPE(MESSAGE, Message, message);
#undef HANDLE_TYPE

        // Stuff with fixed size.
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)             \
  case WireFormatLite::TYPE_##UPPERCASE:                         \
    result += (tag_size + WireFormatLite::k##CAMELCASE##Size) *  \
              FromIntSize(repeated_##LOWERCASE##_value->size()); \
    break
        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
        HANDLE_TYPE(FLOAT, Float, float);
        HANDLE_TYPE(DOUBLE, Double, double);
        HANDLE_TYPE(BOOL, Bool, bool);
#undef HANDLE_TYPE
      }
    }
  } else if (!is_cleared) {
    result += WireFormatLite::TagSize(number, real_type(type));
    switch (real_type(type)) {
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)      \
  case WireFormatLite::TYPE_##UPPERCASE:                  \
    result += WireFormatLite::CAMELCASE##Size(LOWERCASE); \
    break

      HANDLE_TYPE(INT32, Int32, int32_t_value);
      HANDLE_TYPE(INT64, Int64, int64_t_value);
      HANDLE_TYPE(UINT32, UInt32, uint32_t_value);
      HANDLE_TYPE(UINT64, UInt64, uint64_t_value);
      HANDLE_TYPE(SINT32, SInt32, int32_t_value);
      HANDLE_TYPE(SINT64, SInt64, int64_t_value);
      HANDLE_TYPE(STRING, String, *string_value);
      HANDLE_TYPE(BYTES, Bytes, *string_value);
      HANDLE_TYPE(ENUM, Enum, enum_value);
      HANDLE_TYPE(GROUP, Group, *message_value);
#undef HANDLE_TYPE
      case WireFormatLite::TYPE_MESSAGE: {
        if (is_lazy) {
          size_t size = lazymessage_value->ByteSizeLong();
          result += io::CodedOutputStream::VarintSize32(size) + size;
        } else {
          result += WireFormatLite::MessageSize(*message_value);
        }
        break;
      }

      // Stuff with fixed size.
#define HANDLE_TYPE(UPPERCASE, CAMELCASE)         \
  case WireFormatLite::TYPE_##UPPERCASE:          \
    result += WireFormatLite::k##CAMELCASE##Size; \
    break
        HANDLE_TYPE(FIXED32, Fixed32);
        HANDLE_TYPE(FIXED64, Fixed64);
        HANDLE_TYPE(SFIXED32, SFixed32);
        HANDLE_TYPE(SFIXED64, SFixed64);
        HANDLE_TYPE(FLOAT, Float);
        HANDLE_TYPE(DOUBLE, Double);
        HANDLE_TYPE(BOOL, Bool);
#undef HANDLE_TYPE
    }
  }

  return result;
}

int ExtensionSet::Extension::GetSize() const {
  ABSL_DCHECK(is_repeated);
  switch (cpp_type(type)) {
#define HANDLE_TYPE(UPPERCASE, LOWERCASE)   \
  case WireFormatLite::CPPTYPE_##UPPERCASE: \
    return repeated_##LOWERCASE##_value->size()

    HANDLE_TYPE(INT32, int32_t);
    HANDLE_TYPE(INT64, int64_t);
    HANDLE_TYPE(UINT32, uint32_t);
    HANDLE_TYPE(UINT64, uint64_t);
    HANDLE_TYPE(FLOAT, float);
    HANDLE_TYPE(DOUBLE, double);
    HANDLE_TYPE(BOOL, bool);
    HANDLE_TYPE(ENUM, enum);
    HANDLE_TYPE(STRING, string);
    HANDLE_TYPE(MESSAGE, message);
#undef HANDLE_TYPE
  }

  ABSL_LOG(FATAL) << "Can't get here.";
  return 0;
}

// This function deletes all allocated objects. This function should be only
// called if the Extension was created without an arena.
void ExtensionSet::Extension::Free() {
  if (is_repeated) {
    switch (cpp_type(type)) {
#define HANDLE_TYPE(UPPERCASE, LOWERCASE)   \
  case WireFormatLite::CPPTYPE_##UPPERCASE: \
    delete repeated_##LOWERCASE##_value;    \
    break

      HANDLE_TYPE(INT32, int32_t);
      HANDLE_TYPE(INT64, int64_t);
      HANDLE_TYPE(UINT32, uint32_t);
      HANDLE_TYPE(UINT64, uint64_t);
      HANDLE_TYPE(FLOAT, float);
      HANDLE_TYPE(DOUBLE, double);
      HANDLE_TYPE(BOOL, bool);
      HANDLE_TYPE(ENUM, enum);
      HANDLE_TYPE(STRING, string);
      HANDLE_TYPE(MESSAGE, message);
#undef HANDLE_TYPE
    }
  } else {
    switch (cpp_type(type)) {
      case WireFormatLite::CPPTYPE_STRING:
        delete string_value;
        break;
      case WireFormatLite::CPPTYPE_MESSAGE:
        if (is_lazy) {
          delete lazymessage_value;
        } else {
          delete message_value;
        }
        break;
      default:
        break;
    }
  }
}

// Defined in extension_set_heavy.cc.
// int ExtensionSet::Extension::SpaceUsedExcludingSelf() const

bool ExtensionSet::Extension::IsInitialized(const ExtensionSet* ext_set,
                                            const MessageLite* extendee,
                                            int number, Arena* arena) const {
  if (cpp_type(type) != WireFormatLite::CPPTYPE_MESSAGE) return true;

  if (is_repeated) {
    for (int i = 0; i < repeated_message_value->size(); i++) {
      if (!repeated_message_value->Get(i).IsInitialized()) {
        return false;
      }
    }
    return true;
  }

  if (is_cleared) return true;

  if (!is_lazy) return message_value->IsInitialized();

  const MessageLite* prototype =
      ext_set->GetPrototypeForLazyMessage(extendee, number);
  ABSL_DCHECK_NE(prototype, nullptr)
      << "extendee: " << extendee->GetTypeName() << "; number: " << number;
  return lazymessage_value->IsInitialized(prototype, arena);
}

// Dummy key method to avoid weak vtable.
void ExtensionSet::LazyMessageExtension::UnusedKeyMethod() {}

const ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) const {
  if (flat_size_ == 0) {
    return nullptr;
  } else if (PROTOBUF_PREDICT_TRUE(!is_large())) {
    auto it = std::lower_bound(flat_begin(), flat_end() - 1, key,
                               KeyValue::FirstComparator());
    return it->first == key ? &it->second : nullptr;
  } else {
    return FindOrNullInLargeMap(key);
  }
}

const ExtensionSet::Extension* ExtensionSet::FindOrNullInLargeMap(
    int key) const {
  assert(is_large());
  LargeMap::const_iterator it = map_.large->find(key);
  if (it != map_.large->end()) {
    return &it->second;
  }
  return nullptr;
}

ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) {
  const auto* const_this = this;
  return const_cast<ExtensionSet::Extension*>(const_this->FindOrNull(key));
}

ExtensionSet::Extension* ExtensionSet::FindOrNullInLargeMap(int key) {
  const auto* const_this = this;
  return const_cast<ExtensionSet::Extension*>(
      const_this->FindOrNullInLargeMap(key));
}

std::pair<ExtensionSet::Extension*, bool> ExtensionSet::Insert(int key) {
  if (PROTOBUF_PREDICT_FALSE(is_large())) {
    auto maybe = map_.large->insert({key, Extension()});
    return {&maybe.first->second, maybe.second};
  }
  KeyValue* end = flat_end();
  KeyValue* it =
      std::lower_bound(flat_begin(), end, key, KeyValue::FirstComparator());
  if (it != end && it->first == key) {
    return {&it->second, false};
  }
  if (flat_size_ < flat_capacity_) {
    std::copy_backward(it, end, end + 1);
    ++flat_size_;
    it->first = key;
    it->second = Extension();
    return {&it->second, true};
  }
  GrowCapacity(flat_size_ + 1);
  return Insert(key);
}

void ExtensionSet::GrowCapacity(size_t minimum_new_capacity) {
  if (PROTOBUF_PREDICT_FALSE(is_large())) {
    return;  // LargeMap does not have a "reserve" method.
  }
  if (flat_capacity_ >= minimum_new_capacity) {
    return;
  }

  auto new_flat_capacity = flat_capacity_;
  do {
    new_flat_capacity = new_flat_capacity == 0 ? 1 : new_flat_capacity * 4;
  } while (new_flat_capacity < minimum_new_capacity);

  const KeyValue* begin = flat_begin();
  const KeyValue* end = flat_end();
  AllocatedData new_map;
  if (new_flat_capacity > kMaximumFlatCapacity) {
    new_map.large = Arena::Create<LargeMap>(arena_);
    LargeMap::iterator hint = new_map.large->begin();
    for (const KeyValue* it = begin; it != end; ++it) {
      hint = new_map.large->insert(hint, {it->first, it->second});
    }
    flat_size_ = static_cast<uint16_t>(-1);
    ABSL_DCHECK(is_large());
  } else {
    new_map.flat = Arena::CreateArray<KeyValue>(arena_, new_flat_capacity);
    std::copy(begin, end, new_map.flat);
  }

  if (arena_ == nullptr) {
    DeleteFlatMap(begin, flat_capacity_);
  }
  flat_capacity_ = new_flat_capacity;
  map_ = new_map;
}

#if (__cplusplus < 201703) && \
    (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
// static
constexpr uint16_t ExtensionSet::kMaximumFlatCapacity;
#endif  //  (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900
        //  && _MSC_VER < 1912))

void ExtensionSet::Erase(int key) {
  if (PROTOBUF_PREDICT_FALSE(is_large())) {
    map_.large->erase(key);
    return;
  }
  KeyValue* end = flat_end();
  KeyValue* it =
      std::lower_bound(flat_begin(), end, key, KeyValue::FirstComparator());
  if (it != end && it->first == key) {
    std::copy(it + 1, end, it);
    --flat_size_;
  }
}

// ==================================================================
// Default repeated field instances for iterator-compatible accessors

const RepeatedPrimitiveDefaults* RepeatedPrimitiveDefaults::default_instance() {
  static auto instance = OnShutdownDelete(new RepeatedPrimitiveDefaults);
  return instance;
}

const RepeatedStringTypeTraits::RepeatedFieldType*
RepeatedStringTypeTraits::GetDefaultRepeatedField() {
  static auto instance = OnShutdownDelete(new RepeatedFieldType);
  return instance;
}

uint8_t* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray(
    const MessageLite* extendee, const ExtensionSet* extension_set, int number,
    uint8_t* target, io::EpsCopyOutputStream* stream) const {
  if (is_repeated) {
    if (is_packed) {
      if (cached_size == 0) return target;

      target = stream->EnsureSpace(target);
      target = WireFormatLite::WriteTagToArray(
          number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target);
      target = WireFormatLite::WriteInt32NoTagToArray(cached_size, target);

      switch (real_type(type)) {
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
  case WireFormatLite::TYPE_##UPPERCASE:                             \
    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
      target = stream->EnsureSpace(target);                          \
      target = WireFormatLite::Write##CAMELCASE##NoTagToArray(       \
          repeated_##LOWERCASE##_value->Get(i), target);             \
    }                                                                \
    break

        HANDLE_TYPE(INT32, Int32, int32_t);
        HANDLE_TYPE(INT64, Int64, int64_t);
        HANDLE_TYPE(UINT32, UInt32, uint32_t);
        HANDLE_TYPE(UINT64, UInt64, uint64_t);
        HANDLE_TYPE(SINT32, SInt32, int32_t);
        HANDLE_TYPE(SINT64, SInt64, int64_t);
        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
        HANDLE_TYPE(FLOAT, Float, float);
        HANDLE_TYPE(DOUBLE, Double, double);
        HANDLE_TYPE(BOOL, Bool, bool);
        HANDLE_TYPE(ENUM, Enum, enum);
#undef HANDLE_TYPE

        case WireFormatLite::TYPE_STRING:
        case WireFormatLite::TYPE_BYTES:
        case WireFormatLite::TYPE_GROUP:
        case WireFormatLite::TYPE_MESSAGE:
          ABSL_LOG(FATAL) << "Non-primitive types can't be packed.";
          break;
      }
    } else {
      switch (real_type(type)) {
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
  case WireFormatLite::TYPE_##UPPERCASE:                             \
    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
      target = stream->EnsureSpace(target);                          \
      target = WireFormatLite::Write##CAMELCASE##ToArray(            \
          number, repeated_##LOWERCASE##_value->Get(i), target);     \
    }                                                                \
    break

        HANDLE_TYPE(INT32, Int32, int32_t);
        HANDLE_TYPE(INT64, Int64, int64_t);
        HANDLE_TYPE(UINT32, UInt32, uint32_t);
        HANDLE_TYPE(UINT64, UInt64, uint64_t);
        HANDLE_TYPE(SINT32, SInt32, int32_t);
        HANDLE_TYPE(SINT64, SInt64, int64_t);
        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
        HANDLE_TYPE(FLOAT, Float, float);
        HANDLE_TYPE(DOUBLE, Double, double);
        HANDLE_TYPE(BOOL, Bool, bool);
        HANDLE_TYPE(ENUM, Enum, enum);
#undef HANDLE_TYPE
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
  case WireFormatLite::TYPE_##UPPERCASE:                             \
    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
      target = stream->EnsureSpace(target);                          \
      target = stream->WriteString(                                  \
          number, repeated_##LOWERCASE##_value->Get(i), target);     \
    }                                                                \
    break
        HANDLE_TYPE(STRING, String, string);
        HANDLE_TYPE(BYTES, Bytes, string);
#undef HANDLE_TYPE
        case WireFormatLite::TYPE_GROUP:
          for (int i = 0; i < repeated_message_value->size(); i++) {
            target = stream->EnsureSpace(target);
            target = WireFormatLite::InternalWriteGroup(
                number, repeated_message_value->Get(i), target, stream);
          }
          break;
        case WireFormatLite::TYPE_MESSAGE:
          for (int i = 0; i < repeated_message_value->size(); i++) {
            auto& msg = repeated_message_value->Get(i);
            target = WireFormatLite::InternalWriteMessage(
                number, msg, msg.GetCachedSize(), target, stream);
          }
          break;
      }
    }
  } else if (!is_cleared) {
    switch (real_type(type)) {
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE)                               \
  case WireFormatLite::TYPE_##UPPERCASE:                                       \
    target = stream->EnsureSpace(target);                                      \
    target = WireFormatLite::Write##CAMELCASE##ToArray(number, VALUE, target); \
    break

      HANDLE_TYPE(INT32, Int32, int32_t_value);
      HANDLE_TYPE(INT64, Int64, int64_t_value);
      HANDLE_TYPE(UINT32, UInt32, uint32_t_value);
      HANDLE_TYPE(UINT64, UInt64, uint64_t_value);
      HANDLE_TYPE(SINT32, SInt32, int32_t_value);
      HANDLE_TYPE(SINT64, SInt64, int64_t_value);
      HANDLE_TYPE(FIXED32, Fixed32, uint32_t_value);
      HANDLE_TYPE(FIXED64, Fixed64, uint64_t_value);
      HANDLE_TYPE(SFIXED32, SFixed32, int32_t_value);
      HANDLE_TYPE(SFIXED64, SFixed64, int64_t_value);
      HANDLE_TYPE(FLOAT, Float, float_value);
      HANDLE_TYPE(DOUBLE, Double, double_value);
      HANDLE_TYPE(BOOL, Bool, bool_value);
      HANDLE_TYPE(ENUM, Enum, enum_value);
#undef HANDLE_TYPE
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE)         \
  case WireFormatLite::TYPE_##UPPERCASE:                 \
    target = stream->EnsureSpace(target);                \
    target = stream->WriteString(number, VALUE, target); \
    break
      HANDLE_TYPE(STRING, String, *string_value);
      HANDLE_TYPE(BYTES, Bytes, *string_value);
#undef HANDLE_TYPE
      case WireFormatLite::TYPE_GROUP:
        target = stream->EnsureSpace(target);
        target = WireFormatLite::InternalWriteGroup(number, *message_value,
                                                    target, stream);
        break;
      case WireFormatLite::TYPE_MESSAGE:
        if (is_lazy) {
          const auto* prototype =
              extension_set->GetPrototypeForLazyMessage(extendee, number);
          target = lazymessage_value->WriteMessageToArray(prototype, number,
                                                          target, stream);
        } else {
          target = WireFormatLite::InternalWriteMessage(
              number, *message_value, message_value->GetCachedSize(), target,
              stream);
        }
        break;
    }
  }
  return target;
}

const MessageLite* ExtensionSet::GetPrototypeForLazyMessage(
    const MessageLite* extendee, int number) const {
  GeneratedExtensionFinder finder(extendee);
  bool was_packed_on_wire = false;
  ExtensionInfo extension_info;
  if (!FindExtensionInfoFromFieldNumber(
          WireFormatLite::WireType::WIRETYPE_LENGTH_DELIMITED, number, &finder,
          &extension_info, &was_packed_on_wire)) {
    return nullptr;
  }
  return extension_info.message_info.prototype;
}

uint8_t*
ExtensionSet::Extension::InternalSerializeMessageSetItemWithCachedSizesToArray(
    const MessageLite* extendee, const ExtensionSet* extension_set, int number,
    uint8_t* target, io::EpsCopyOutputStream* stream) const {
  if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
    // Not a valid MessageSet extension, but serialize it the normal way.
    ABSL_LOG(WARNING) << "Invalid message set extension.";
    return InternalSerializeFieldWithCachedSizesToArray(extendee, extension_set,
                                                        number, target, stream);
  }

  if (is_cleared) return target;

  target = stream->EnsureSpace(target);
  // Start group.
  target = io::CodedOutputStream::WriteTagToArray(
      WireFormatLite::kMessageSetItemStartTag, target);
  // Write type ID.
  target = WireFormatLite::WriteUInt32ToArray(
      WireFormatLite::kMessageSetTypeIdNumber, number, target);
  // Write message.
  if (is_lazy) {
    const auto* prototype =
        extension_set->GetPrototypeForLazyMessage(extendee, number);
    target = lazymessage_value->WriteMessageToArray(
        prototype, WireFormatLite::kMessageSetMessageNumber, target, stream);
  } else {
    target = WireFormatLite::InternalWriteMessage(
        WireFormatLite::kMessageSetMessageNumber, *message_value,
        message_value->GetCachedSize(), target, stream);
  }
  // End group.
  target = stream->EnsureSpace(target);
  target = io::CodedOutputStream::WriteTagToArray(
      WireFormatLite::kMessageSetItemEndTag, target);
  return target;
}

size_t ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
  if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
    // Not a valid MessageSet extension, but compute the byte size for it the
    // normal way.
    return ByteSize(number);
  }

  if (is_cleared) return 0;

  size_t our_size = WireFormatLite::kMessageSetItemTagsSize;

  // type_id
  our_size += io::CodedOutputStream::VarintSize32(number);

  // message
  size_t message_size = 0;
  if (is_lazy) {
    message_size = lazymessage_value->ByteSizeLong();
  } else {
    message_size = message_value->ByteSizeLong();
  }

  our_size += io::CodedOutputStream::VarintSize32(message_size);
  our_size += message_size;

  return our_size;
}

size_t ExtensionSet::MessageSetByteSize() const {
  size_t total_size = 0;
  ForEach([&total_size](int number, const Extension& ext) {
    total_size += ext.MessageSetItemByteSize(number);
  });
  return total_size;
}

LazyEagerVerifyFnType FindExtensionLazyEagerVerifyFn(
    const MessageLite* extendee, int number) {
  const ExtensionInfo* registered = FindRegisteredExtension(extendee, number);
  if (registered != nullptr) {
    return registered->lazy_eager_verify_func;
  }
  return nullptr;
}


}  // namespace internal