diff options
author | spreis <spreis@yandex-team.com> | 2024-03-29 14:18:43 +0300 |
---|---|---|
committer | spreis <spreis@yandex-team.com> | 2024-03-29 14:31:49 +0300 |
commit | f39261a434c46274b5eaef0927ee3b2e0d95b41a (patch) | |
tree | e64c68742b1a7423d8b2809a5ca938f5ddbed2e2 /contrib/libs/protobuf_old/src/google/protobuf/extension_set.cc | |
parent | 9334caaba1f032fa294d74e7a74157e3fb263a3e (diff) | |
download | ydb-f39261a434c46274b5eaef0927ee3b2e0d95b41a.tar.gz |
Re-enable separation of protobufs for Python 2 and Python 3
Это откат коммита https://a.yandex-team.ru/arcadia/commit/rXXXXXX
И соответственно возврат коммитов https://a.yandex-team.ru/arcadia/commit/rXXXXXX и https://a.yandex-team.ru/arcadia/commit/rXXXXXX
Починка причины отката влилась здесь: https://a.yandex-team.ru/arcadia/commit/rXXXXXX
ae529e54d3ef7992b0e9f152373bc300061c1293
Diffstat (limited to 'contrib/libs/protobuf_old/src/google/protobuf/extension_set.cc')
-rw-r--r-- | contrib/libs/protobuf_old/src/google/protobuf/extension_set.cc | 2255 |
1 files changed, 2255 insertions, 0 deletions
diff --git a/contrib/libs/protobuf_old/src/google/protobuf/extension_set.cc b/contrib/libs/protobuf_old/src/google/protobuf/extension_set.cc new file mode 100644 index 0000000000..af851b2a45 --- /dev/null +++ b/contrib/libs/protobuf_old/src/google/protobuf/extension_set.cc @@ -0,0 +1,2255 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <google/protobuf/extension_set.h> + +#include <tuple> +#include <unordered_set> +#include <utility> + +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/extension_set_inl.h> +#include <google/protobuf/parse_context.h> +#include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/io/zero_copy_stream_impl_lite.h> +#include <google/protobuf/arena.h> +#include <google/protobuf/message_lite.h> +#include <google/protobuf/metadata_lite.h> +#include <google/protobuf/repeated_field.h> +#include <google/protobuf/stubs/map_util.h> +#include <google/protobuf/stubs/hash.h> + +// clang-format off +#include <google/protobuf/port_def.inc> // must be last. +// clang-format on +namespace google { +namespace protobuf { +namespace internal { + +namespace { + +inline WireFormatLite::FieldType real_type(FieldType type) { + GOOGLE_DCHECK(type > 0 && type <= WireFormatLite::MAX_FIELD_TYPE); + return static_cast<WireFormatLite::FieldType>(type); +} + +inline WireFormatLite::CppType cpp_type(FieldType type) { + return WireFormatLite::FieldTypeToCppType(real_type(type)); +} + +inline bool is_packable(WireFormatLite::WireType type) { + switch (type) { + case WireFormatLite::WIRETYPE_VARINT: + case WireFormatLite::WIRETYPE_FIXED64: + case WireFormatLite::WIRETYPE_FIXED32: + return true; + case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: + case WireFormatLite::WIRETYPE_START_GROUP: + case WireFormatLite::WIRETYPE_END_GROUP: + return false; + + // Do not add a default statement. Let the compiler complain when someone + // adds a new wire type. + } + GOOGLE_LOG(FATAL) << "can't reach here."; + return false; +} + +// Registry stuff. + +// Note that we cannot use hetererogeneous lookup for std containers since we +// need to support C++11. +struct ExtensionEq { + bool operator()(const ExtensionInfo& lhs, const ExtensionInfo& rhs) const { + return lhs.message == rhs.message && lhs.number == rhs.number; + } +}; + +struct ExtensionHasher { + std::size_t operator()(const ExtensionInfo& info) const { + return std::hash<const MessageLite*>{}(info.message) ^ + std::hash<int>{}(info.number); + } +}; + +using ExtensionRegistry = + std::unordered_set<ExtensionInfo, ExtensionHasher, ExtensionEq>; + +static const ExtensionRegistry* global_registry = nullptr; + +// This function is only called at startup, so there is no need for thread- +// safety. +void Register(const ExtensionInfo& info) { + static auto local_static_registry = OnShutdownDelete(new ExtensionRegistry); + global_registry = local_static_registry; + if (!InsertIfNotPresent(local_static_registry, info)) { + GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \"" + << info.message->GetTypeName() << "\", field number " + << info.number << "."; + } +} + +const ExtensionInfo* FindRegisteredExtension(const MessageLite* extendee, + int number) { + if (!global_registry) return nullptr; + + ExtensionInfo info; + info.message = extendee; + info.number = number; + + auto it = global_registry->find(info); + if (it == global_registry->end()) { + return nullptr; + } else { + return &*it; + } +} + +} // namespace + +ExtensionFinder::~ExtensionFinder() {} + +bool GeneratedExtensionFinder::Find(int number, ExtensionInfo* output) { + const ExtensionInfo* extension = FindRegisteredExtension(extendee_, number); + if (extension == nullptr) { + return false; + } else { + *output = *extension; + return true; + } +} + +void ExtensionSet::RegisterExtension(const MessageLite* extendee, int number, + FieldType type, bool is_repeated, + bool is_packed) { + GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_ENUM); + GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_MESSAGE); + GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_GROUP); + ExtensionInfo info(extendee, number, type, is_repeated, is_packed); + Register(info); +} + +static bool CallNoArgValidityFunc(const void* arg, int number) { + // Note: Must use C-style cast here rather than reinterpret_cast because + // the C++ standard at one point did not allow casts between function and + // data pointers and some compilers enforce this for C++-style casts. No + // compiler enforces it for C-style casts since lots of C-style code has + // relied on these kinds of casts for a long time, despite being + // technically undefined. See: + // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#195 + // Also note: Some compilers do not allow function pointers to be "const". + // Which makes sense, I suppose, because it's meaningless. + return ((EnumValidityFunc*)arg)(number); +} + +void ExtensionSet::RegisterEnumExtension(const MessageLite* extendee, + int number, FieldType type, + bool is_repeated, bool is_packed, + EnumValidityFunc* is_valid) { + GOOGLE_CHECK_EQ(type, WireFormatLite::TYPE_ENUM); + ExtensionInfo info(extendee, number, type, is_repeated, is_packed); + info.enum_validity_check.func = CallNoArgValidityFunc; + // See comment in CallNoArgValidityFunc() about why we use a c-style cast. + info.enum_validity_check.arg = (void*)is_valid; + Register(info); +} + +void ExtensionSet::RegisterMessageExtension(const MessageLite* extendee, + int number, FieldType type, + bool is_repeated, bool is_packed, + const MessageLite* prototype) { + GOOGLE_CHECK(type == WireFormatLite::TYPE_MESSAGE || + type == WireFormatLite::TYPE_GROUP); + ExtensionInfo info(extendee, number, type, is_repeated, is_packed); + info.message_info = {prototype}; + Register(info); +} + +// =================================================================== +// Constructors and basic methods. + +ExtensionSet::ExtensionSet(Arena* arena) + : arena_(arena), + flat_capacity_(0), + flat_size_(0), + map_{flat_capacity_ == 0 + ? nullptr + : Arena::CreateArray<KeyValue>(arena_, flat_capacity_)} {} + +ExtensionSet::~ExtensionSet() { + // Deletes all allocated extensions. + if (arena_ == nullptr) { + ForEach([](int /* number */, Extension& ext) { ext.Free(); }); + if (PROTOBUF_PREDICT_FALSE(is_large())) { + delete map_.large; + } else { + DeleteFlatMap(map_.flat, flat_capacity_); + } + } +} + +void ExtensionSet::DeleteFlatMap(const ExtensionSet::KeyValue* flat, + uint16_t flat_capacity) { +#ifdef __cpp_sized_deallocation + // Arena::CreateArray already requires a trivially destructible type, but + // ensure this constraint is not violated in the future. + static_assert(std::is_trivially_destructible<KeyValue>::value, + "CreateArray requires a trivially destructible type"); + // A const-cast is needed, but this is safe as we are about to deallocate the + // array. + ::operator delete[](const_cast<ExtensionSet::KeyValue*>(flat), + sizeof(*flat) * flat_capacity); +#else // !__cpp_sized_deallocation + delete[] flat; +#endif // !__cpp_sized_deallocation +} + +// Defined in extension_set_heavy.cc. +// void ExtensionSet::AppendToList(const Descriptor* extendee, +// const DescriptorPool* pool, +// vector<const FieldDescriptor*>* output) const + +bool ExtensionSet::Has(int number) const { + const Extension* ext = FindOrNull(number); + if (ext == nullptr) return false; + GOOGLE_DCHECK(!ext->is_repeated); + return !ext->is_cleared; +} + +bool ExtensionSet::HasLazy(int number) const { + return Has(number) && FindOrNull(number)->is_lazy; +} + +int ExtensionSet::NumExtensions() const { + int result = 0; + ForEach([&result](int /* number */, const Extension& ext) { + if (!ext.is_cleared) { + ++result; + } + }); + return result; +} + +int ExtensionSet::ExtensionSize(int number) const { + const Extension* ext = FindOrNull(number); + return ext == nullptr ? 0 : ext->GetSize(); +} + +FieldType ExtensionSet::ExtensionType(int number) const { + const Extension* ext = FindOrNull(number); + if (ext == nullptr) { + GOOGLE_LOG(DFATAL) << "Don't lookup extension types if they aren't present (1). "; + return 0; + } + if (ext->is_cleared) { + GOOGLE_LOG(DFATAL) << "Don't lookup extension types if they aren't present (2). "; + } + return ext->type; +} + +void ExtensionSet::ClearExtension(int number) { + Extension* ext = FindOrNull(number); + if (ext == nullptr) return; + ext->Clear(); +} + +// =================================================================== +// Field accessors + +namespace { + +enum { REPEATED_FIELD, OPTIONAL_FIELD }; + +} // namespace + +#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \ + GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? REPEATED_FIELD : OPTIONAL_FIELD, LABEL); \ + GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), WireFormatLite::CPPTYPE_##CPPTYPE) + +// ------------------------------------------------------------------- +// Primitives + +#define PRIMITIVE_ACCESSORS(UPPERCASE, LOWERCASE, CAMELCASE) \ + \ + LOWERCASE ExtensionSet::Get##CAMELCASE(int number, LOWERCASE default_value) \ + const { \ + const Extension* extension = FindOrNull(number); \ + if (extension == nullptr || extension->is_cleared) { \ + return default_value; \ + } else { \ + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE); \ + return extension->LOWERCASE##_value; \ + } \ + } \ + \ + const LOWERCASE& ExtensionSet::GetRef##CAMELCASE( \ + int number, const LOWERCASE& default_value) const { \ + const Extension* extension = FindOrNull(number); \ + if (extension == nullptr || extension->is_cleared) { \ + return default_value; \ + } else { \ + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE); \ + return extension->LOWERCASE##_value; \ + } \ + } \ + \ + void ExtensionSet::Set##CAMELCASE(int number, FieldType type, \ + LOWERCASE value, \ + const FieldDescriptor* descriptor) { \ + Extension* extension; \ + if (MaybeNewExtension(number, descriptor, &extension)) { \ + extension->type = type; \ + GOOGLE_DCHECK_EQ(cpp_type(extension->type), \ + WireFormatLite::CPPTYPE_##UPPERCASE); \ + extension->is_repeated = false; \ + } else { \ + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE); \ + } \ + extension->is_cleared = false; \ + extension->LOWERCASE##_value = value; \ + } \ + \ + LOWERCASE ExtensionSet::GetRepeated##CAMELCASE(int number, int index) \ + const { \ + const Extension* extension = FindOrNull(number); \ + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; \ + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE); \ + return extension->repeated_##LOWERCASE##_value->Get(index); \ + } \ + \ + const LOWERCASE& ExtensionSet::GetRefRepeated##CAMELCASE(int number, \ + int index) const { \ + const Extension* extension = FindOrNull(number); \ + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; \ + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE); \ + return extension->repeated_##LOWERCASE##_value->Get(index); \ + } \ + \ + void ExtensionSet::SetRepeated##CAMELCASE(int number, int index, \ + LOWERCASE value) { \ + Extension* extension = FindOrNull(number); \ + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; \ + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE); \ + extension->repeated_##LOWERCASE##_value->Set(index, value); \ + } \ + \ + void ExtensionSet::Add##CAMELCASE(int number, FieldType type, bool packed, \ + LOWERCASE value, \ + const FieldDescriptor* descriptor) { \ + Extension* extension; \ + if (MaybeNewExtension(number, descriptor, &extension)) { \ + extension->type = type; \ + GOOGLE_DCHECK_EQ(cpp_type(extension->type), \ + WireFormatLite::CPPTYPE_##UPPERCASE); \ + extension->is_repeated = true; \ + extension->is_packed = packed; \ + extension->repeated_##LOWERCASE##_value = \ + Arena::CreateMessage<RepeatedField<LOWERCASE>>(arena_); \ + } else { \ + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE); \ + GOOGLE_DCHECK_EQ(extension->is_packed, packed); \ + } \ + extension->repeated_##LOWERCASE##_value->Add(value); \ + } + +PRIMITIVE_ACCESSORS(INT32, arc_i32, Int32) +PRIMITIVE_ACCESSORS(INT64, arc_i64, Int64) +PRIMITIVE_ACCESSORS(UINT32, arc_ui32, UInt32) +PRIMITIVE_ACCESSORS(UINT64, arc_ui64, UInt64) +PRIMITIVE_ACCESSORS(FLOAT, float, Float) +PRIMITIVE_ACCESSORS(DOUBLE, double, Double) +PRIMITIVE_ACCESSORS(BOOL, bool, Bool) + +#undef PRIMITIVE_ACCESSORS + +const void* ExtensionSet::GetRawRepeatedField(int number, + const void* default_value) const { + const Extension* extension = FindOrNull(number); + if (extension == nullptr) { + return default_value; + } + // We assume that all the RepeatedField<>* pointers have the same + // size and alignment within the anonymous union in Extension. + return extension->repeated_arc_i32_value; +} + +void* ExtensionSet::MutableRawRepeatedField(int number, FieldType field_type, + bool packed, + const FieldDescriptor* desc) { + Extension* extension; + + // We instantiate an empty Repeated{,Ptr}Field if one doesn't exist for this + // extension. + if (MaybeNewExtension(number, desc, &extension)) { + extension->is_repeated = true; + extension->type = field_type; + extension->is_packed = packed; + + switch (WireFormatLite::FieldTypeToCppType( + static_cast<WireFormatLite::FieldType>(field_type))) { + case WireFormatLite::CPPTYPE_INT32: + extension->repeated_arc_i32_value = + Arena::CreateMessage<RepeatedField<arc_i32>>(arena_); + break; + case WireFormatLite::CPPTYPE_INT64: + extension->repeated_arc_i64_value = + Arena::CreateMessage<RepeatedField<arc_i64>>(arena_); + break; + case WireFormatLite::CPPTYPE_UINT32: + extension->repeated_arc_ui32_value = + Arena::CreateMessage<RepeatedField<arc_ui32>>(arena_); + break; + case WireFormatLite::CPPTYPE_UINT64: + extension->repeated_arc_ui64_value = + Arena::CreateMessage<RepeatedField<arc_ui64>>(arena_); + break; + case WireFormatLite::CPPTYPE_DOUBLE: + extension->repeated_double_value = + Arena::CreateMessage<RepeatedField<double>>(arena_); + break; + case WireFormatLite::CPPTYPE_FLOAT: + extension->repeated_float_value = + Arena::CreateMessage<RepeatedField<float>>(arena_); + break; + case WireFormatLite::CPPTYPE_BOOL: + extension->repeated_bool_value = + Arena::CreateMessage<RepeatedField<bool>>(arena_); + break; + case WireFormatLite::CPPTYPE_ENUM: + extension->repeated_enum_value = + Arena::CreateMessage<RepeatedField<int>>(arena_); + break; + case WireFormatLite::CPPTYPE_STRING: + extension->repeated_string_value = + Arena::CreateMessage<RepeatedPtrField<TProtoStringType>>(arena_); + break; + case WireFormatLite::CPPTYPE_MESSAGE: + extension->repeated_message_value = + Arena::CreateMessage<RepeatedPtrField<MessageLite>>(arena_); + break; + } + } + + // We assume that all the RepeatedField<>* pointers have the same + // size and alignment within the anonymous union in Extension. + return extension->repeated_arc_i32_value; +} + +// Compatible version using old call signature. Does not create extensions when +// the don't already exist; instead, just GOOGLE_CHECK-fails. +void* ExtensionSet::MutableRawRepeatedField(int number) { + Extension* extension = FindOrNull(number); + GOOGLE_CHECK(extension != nullptr) << "Extension not found."; + // We assume that all the RepeatedField<>* pointers have the same + // size and alignment within the anonymous union in Extension. + return extension->repeated_arc_i32_value; +} + +// ------------------------------------------------------------------- +// Enums + +int ExtensionSet::GetEnum(int number, int default_value) const { + const Extension* extension = FindOrNull(number); + if (extension == nullptr || extension->is_cleared) { + // Not present. Return the default value. + return default_value; + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM); + return extension->enum_value; + } +} + +const int& ExtensionSet::GetRefEnum(int number, + const int& default_value) const { + const Extension* extension = FindOrNull(number); + if (extension == nullptr || extension->is_cleared) { + // Not present. Return the default value. + return default_value; + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM); + return extension->enum_value; + } +} + +void ExtensionSet::SetEnum(int number, FieldType type, int value, + const FieldDescriptor* descriptor) { + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); + extension->is_repeated = false; + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM); + } + extension->is_cleared = false; + extension->enum_value = value; +} + +int ExtensionSet::GetRepeatedEnum(int number, int index) const { + const Extension* extension = FindOrNull(number); + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM); + return extension->repeated_enum_value->Get(index); +} + +const int& ExtensionSet::GetRefRepeatedEnum(int number, int index) const { + const Extension* extension = FindOrNull(number); + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM); + return extension->repeated_enum_value->Get(index); +} + +void ExtensionSet::SetRepeatedEnum(int number, int index, int value) { + Extension* extension = FindOrNull(number); + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM); + extension->repeated_enum_value->Set(index, value); +} + +void ExtensionSet::AddEnum(int number, FieldType type, bool packed, int value, + const FieldDescriptor* descriptor) { + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); + extension->is_repeated = true; + extension->is_packed = packed; + extension->repeated_enum_value = + Arena::CreateMessage<RepeatedField<int>>(arena_); + } else { + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM); + GOOGLE_DCHECK_EQ(extension->is_packed, packed); + } + extension->repeated_enum_value->Add(value); +} + +// ------------------------------------------------------------------- +// Strings + +const TProtoStringType& ExtensionSet::GetString( + int number, const TProtoStringType& default_value) const { + const Extension* extension = FindOrNull(number); + if (extension == nullptr || extension->is_cleared) { + // Not present. Return the default value. + return default_value; + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, STRING); + return *extension->string_value; + } +} + +TProtoStringType* ExtensionSet::MutableString(int number, FieldType type, + const FieldDescriptor* descriptor) { + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); + extension->is_repeated = false; + extension->string_value = Arena::Create<TProtoStringType>(arena_); + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, STRING); + } + extension->is_cleared = false; + return extension->string_value; +} + +const TProtoStringType& ExtensionSet::GetRepeatedString(int number, + int index) const { + const Extension* extension = FindOrNull(number); + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, STRING); + return extension->repeated_string_value->Get(index); +} + +TProtoStringType* ExtensionSet::MutableRepeatedString(int number, int index) { + Extension* extension = FindOrNull(number); + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, STRING); + return extension->repeated_string_value->Mutable(index); +} + +TProtoStringType* ExtensionSet::AddString(int number, FieldType type, + const FieldDescriptor* descriptor) { + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); + extension->is_repeated = true; + extension->is_packed = false; + extension->repeated_string_value = + Arena::CreateMessage<RepeatedPtrField<TProtoStringType>>(arena_); + } else { + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, STRING); + } + return extension->repeated_string_value->Add(); +} + +// ------------------------------------------------------------------- +// Messages + +const MessageLite& ExtensionSet::GetMessage( + int number, const MessageLite& default_value) const { + const Extension* extension = FindOrNull(number); + if (extension == nullptr) { + // Not present. Return the default value. + return default_value; + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE); + if (extension->is_lazy) { + return extension->lazymessage_value->GetMessage(default_value, arena_); + } else { + return *extension->message_value; + } + } +} + +// Defined in extension_set_heavy.cc. +// const MessageLite& ExtensionSet::GetMessage(int number, +// const Descriptor* message_type, +// MessageFactory* factory) const + +MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, + const MessageLite& prototype, + const FieldDescriptor* descriptor) { + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); + extension->is_repeated = false; + extension->is_lazy = false; + extension->message_value = prototype.New(arena_); + extension->is_cleared = false; + return extension->message_value; + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE); + extension->is_cleared = false; + if (extension->is_lazy) { + return extension->lazymessage_value->MutableMessage(prototype, arena_); + } else { + return extension->message_value; + } + } +} + +// Defined in extension_set_heavy.cc. +// MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, +// const Descriptor* message_type, +// MessageFactory* factory) + +void ExtensionSet::SetAllocatedMessage(int number, FieldType type, + const FieldDescriptor* descriptor, + MessageLite* message) { + if (message == nullptr) { + ClearExtension(number); + return; + } + GOOGLE_DCHECK(message->GetOwningArena() == nullptr || + message->GetOwningArena() == arena_); + Arena* message_arena = message->GetOwningArena(); + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); + extension->is_repeated = false; + extension->is_lazy = false; + if (message_arena == arena_) { + extension->message_value = message; + } else if (message_arena == nullptr) { + extension->message_value = message; + arena_->Own(message); // not nullptr because not equal to message_arena + } else { + extension->message_value = message->New(arena_); + extension->message_value->CheckTypeAndMergeFrom(*message); + } + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE); + if (extension->is_lazy) { + extension->lazymessage_value->SetAllocatedMessage(message, arena_); + } else { + if (arena_ == nullptr) { + delete extension->message_value; + } + if (message_arena == arena_) { + extension->message_value = message; + } else if (message_arena == nullptr) { + extension->message_value = message; + arena_->Own(message); // not nullptr because not equal to message_arena + } else { + extension->message_value = message->New(arena_); + extension->message_value->CheckTypeAndMergeFrom(*message); + } + } + } + extension->is_cleared = false; +} + +void ExtensionSet::UnsafeArenaSetAllocatedMessage( + int number, FieldType type, const FieldDescriptor* descriptor, + MessageLite* message) { + if (message == nullptr) { + ClearExtension(number); + return; + } + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); + extension->is_repeated = false; + extension->is_lazy = false; + extension->message_value = message; + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE); + if (extension->is_lazy) { + extension->lazymessage_value->UnsafeArenaSetAllocatedMessage(message, + arena_); + } else { + if (arena_ == nullptr) { + delete extension->message_value; + } + extension->message_value = message; + } + } + extension->is_cleared = false; +} + +MessageLite* ExtensionSet::ReleaseMessage(int number, + const MessageLite& prototype) { + Extension* extension = FindOrNull(number); + if (extension == nullptr) { + // Not present. Return nullptr. + return nullptr; + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE); + MessageLite* ret = nullptr; + if (extension->is_lazy) { + ret = extension->lazymessage_value->ReleaseMessage(prototype, arena_); + if (arena_ == nullptr) { + delete extension->lazymessage_value; + } + } else { + if (arena_ == nullptr) { + ret = extension->message_value; + } else { + // ReleaseMessage() always returns a heap-allocated message, and we are + // on an arena, so we need to make a copy of this message to return. + ret = extension->message_value->New(); + ret->CheckTypeAndMergeFrom(*extension->message_value); + } + } + Erase(number); + return ret; + } +} + +MessageLite* ExtensionSet::UnsafeArenaReleaseMessage( + int number, const MessageLite& prototype) { + Extension* extension = FindOrNull(number); + if (extension == nullptr) { + // Not present. Return nullptr. + return nullptr; + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE); + MessageLite* ret = nullptr; + if (extension->is_lazy) { + ret = extension->lazymessage_value->UnsafeArenaReleaseMessage(prototype, + arena_); + if (arena_ == nullptr) { + delete extension->lazymessage_value; + } + } else { + ret = extension->message_value; + } + Erase(number); + return ret; + } +} + +// Defined in extension_set_heavy.cc. +// MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor, +// MessageFactory* factory); + +const MessageLite& ExtensionSet::GetRepeatedMessage(int number, + int index) const { + const Extension* extension = FindOrNull(number); + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE); + return extension->repeated_message_value->Get(index); +} + +MessageLite* ExtensionSet::MutableRepeatedMessage(int number, int index) { + Extension* extension = FindOrNull(number); + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE); + return extension->repeated_message_value->Mutable(index); +} + +MessageLite* ExtensionSet::AddMessage(int number, FieldType type, + const MessageLite& prototype, + const FieldDescriptor* descriptor) { + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); + extension->is_repeated = true; + extension->repeated_message_value = + Arena::CreateMessage<RepeatedPtrField<MessageLite>>(arena_); + } else { + GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE); + } + + // RepeatedPtrField<MessageLite> does not know how to Add() since it cannot + // allocate an abstract object, so we have to be tricky. + MessageLite* result = reinterpret_cast<internal::RepeatedPtrFieldBase*>( + extension->repeated_message_value) + ->AddFromCleared<GenericTypeHandler<MessageLite>>(); + if (result == nullptr) { + result = prototype.New(arena_); + extension->repeated_message_value->AddAllocated(result); + } + return result; +} + +// Defined in extension_set_heavy.cc. +// MessageLite* ExtensionSet::AddMessage(int number, FieldType type, +// const Descriptor* message_type, +// MessageFactory* factory) + +#undef GOOGLE_DCHECK_TYPE + +void ExtensionSet::RemoveLast(int number) { + Extension* extension = FindOrNull(number); + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK(extension->is_repeated); + + switch (cpp_type(extension->type)) { + case WireFormatLite::CPPTYPE_INT32: + extension->repeated_arc_i32_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_INT64: + extension->repeated_arc_i64_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_UINT32: + extension->repeated_arc_ui32_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_UINT64: + extension->repeated_arc_ui64_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_FLOAT: + extension->repeated_float_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_DOUBLE: + extension->repeated_double_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_BOOL: + extension->repeated_bool_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_ENUM: + extension->repeated_enum_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_STRING: + extension->repeated_string_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_MESSAGE: + extension->repeated_message_value->RemoveLast(); + break; + } +} + +MessageLite* ExtensionSet::ReleaseLast(int number) { + Extension* extension = FindOrNull(number); + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK(extension->is_repeated); + GOOGLE_DCHECK(cpp_type(extension->type) == WireFormatLite::CPPTYPE_MESSAGE); + return extension->repeated_message_value->ReleaseLast(); +} + +MessageLite* ExtensionSet::UnsafeArenaReleaseLast(int number) { + Extension* extension = FindOrNull(number); + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK(extension->is_repeated); + GOOGLE_DCHECK(cpp_type(extension->type) == WireFormatLite::CPPTYPE_MESSAGE); + return extension->repeated_message_value->UnsafeArenaReleaseLast(); +} + +void ExtensionSet::SwapElements(int number, int index1, int index2) { + Extension* extension = FindOrNull(number); + GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK(extension->is_repeated); + + switch (cpp_type(extension->type)) { + case WireFormatLite::CPPTYPE_INT32: + extension->repeated_arc_i32_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_INT64: + extension->repeated_arc_i64_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_UINT32: + extension->repeated_arc_ui32_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_UINT64: + extension->repeated_arc_ui64_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_FLOAT: + extension->repeated_float_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_DOUBLE: + extension->repeated_double_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_BOOL: + extension->repeated_bool_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_ENUM: + extension->repeated_enum_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_STRING: + extension->repeated_string_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_MESSAGE: + extension->repeated_message_value->SwapElements(index1, index2); + break; + } +} + +// =================================================================== + +void ExtensionSet::Clear() { + ForEach([](int /* number */, Extension& ext) { ext.Clear(); }); +} + +namespace { +// Computes the size of a std::set_union without constructing the union. +template <typename ItX, typename ItY> +size_t SizeOfUnion(ItX it_xs, ItX end_xs, ItY it_ys, ItY end_ys) { + size_t result = 0; + while (it_xs != end_xs && it_ys != end_ys) { + ++result; + if (it_xs->first < it_ys->first) { + ++it_xs; + } else if (it_xs->first == it_ys->first) { + ++it_xs; + ++it_ys; + } else { + ++it_ys; + } + } + result += std::distance(it_xs, end_xs); + result += std::distance(it_ys, end_ys); + return result; +} +} // namespace + +void ExtensionSet::MergeFrom(const MessageLite* extendee, + const ExtensionSet& other) { + if (PROTOBUF_PREDICT_TRUE(!is_large())) { + if (PROTOBUF_PREDICT_TRUE(!other.is_large())) { + GrowCapacity(SizeOfUnion(flat_begin(), flat_end(), other.flat_begin(), + other.flat_end())); + } else { + GrowCapacity(SizeOfUnion(flat_begin(), flat_end(), + other.map_.large->begin(), + other.map_.large->end())); + } + } + other.ForEach([extendee, this, &other](int number, const Extension& ext) { + this->InternalExtensionMergeFrom(extendee, number, ext, other.arena_); + }); +} + +void ExtensionSet::InternalExtensionMergeFrom(const MessageLite* extendee, + int number, + const Extension& other_extension, + Arena* other_arena) { + if (other_extension.is_repeated) { + Extension* extension; + bool is_new = + MaybeNewExtension(number, other_extension.descriptor, &extension); + if (is_new) { + // Extension did not already exist in set. + extension->type = other_extension.type; + extension->is_packed = other_extension.is_packed; + extension->is_repeated = true; + } else { + GOOGLE_DCHECK_EQ(extension->type, other_extension.type); + GOOGLE_DCHECK_EQ(extension->is_packed, other_extension.is_packed); + GOOGLE_DCHECK(extension->is_repeated); + } + + switch (cpp_type(other_extension.type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE, REPEATED_TYPE) \ + case WireFormatLite::CPPTYPE_##UPPERCASE: \ + if (is_new) { \ + extension->repeated_##LOWERCASE##_value = \ + Arena::CreateMessage<REPEATED_TYPE>(arena_); \ + } \ + extension->repeated_##LOWERCASE##_value->MergeFrom( \ + *other_extension.repeated_##LOWERCASE##_value); \ + break; + + HANDLE_TYPE(INT32, arc_i32, RepeatedField<arc_i32>); + HANDLE_TYPE(INT64, arc_i64, RepeatedField<arc_i64>); + HANDLE_TYPE(UINT32, arc_ui32, RepeatedField<arc_ui32>); + HANDLE_TYPE(UINT64, arc_ui64, RepeatedField<arc_ui64>); + HANDLE_TYPE(FLOAT, float, RepeatedField<float>); + HANDLE_TYPE(DOUBLE, double, RepeatedField<double>); + HANDLE_TYPE(BOOL, bool, RepeatedField<bool>); + HANDLE_TYPE(ENUM, enum, RepeatedField<int>); + HANDLE_TYPE(STRING, string, RepeatedPtrField<TProtoStringType>); +#undef HANDLE_TYPE + + case WireFormatLite::CPPTYPE_MESSAGE: + if (is_new) { + extension->repeated_message_value = + Arena::CreateMessage<RepeatedPtrField<MessageLite>>(arena_); + } + // We can't call RepeatedPtrField<MessageLite>::MergeFrom() because + // it would attempt to allocate new objects. + RepeatedPtrField<MessageLite>* other_repeated_message = + other_extension.repeated_message_value; + for (int i = 0; i < other_repeated_message->size(); i++) { + const MessageLite& other_message = other_repeated_message->Get(i); + MessageLite* target = + reinterpret_cast<internal::RepeatedPtrFieldBase*>( + extension->repeated_message_value) + ->AddFromCleared<GenericTypeHandler<MessageLite>>(); + if (target == nullptr) { + target = other_message.New(arena_); + extension->repeated_message_value->AddAllocated(target); + } + target->CheckTypeAndMergeFrom(other_message); + } + break; + } + } else { + if (!other_extension.is_cleared) { + switch (cpp_type(other_extension.type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \ + case WireFormatLite::CPPTYPE_##UPPERCASE: \ + Set##CAMELCASE(number, other_extension.type, \ + other_extension.LOWERCASE##_value, \ + other_extension.descriptor); \ + break; + + HANDLE_TYPE(INT32, arc_i32, Int32); + HANDLE_TYPE(INT64, arc_i64, Int64); + HANDLE_TYPE(UINT32, arc_ui32, UInt32); + HANDLE_TYPE(UINT64, arc_ui64, UInt64); + 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::CPPTYPE_STRING: + SetString(number, other_extension.type, *other_extension.string_value, + other_extension.descriptor); + break; + case WireFormatLite::CPPTYPE_MESSAGE: { + Extension* extension; + bool is_new = + MaybeNewExtension(number, other_extension.descriptor, &extension); + if (is_new) { + extension->type = other_extension.type; + extension->is_packed = other_extension.is_packed; + extension->is_repeated = false; + if (other_extension.is_lazy) { + extension->is_lazy = true; + extension->lazymessage_value = + other_extension.lazymessage_value->New(arena_); + extension->lazymessage_value->MergeFrom( + GetPrototypeForLazyMessage(extendee, number), + *other_extension.lazymessage_value, arena_); + } else { + extension->is_lazy = false; + extension->message_value = + other_extension.message_value->New(arena_); + extension->message_value->CheckTypeAndMergeFrom( + *other_extension.message_value); + } + } else { + GOOGLE_DCHECK_EQ(extension->type, other_extension.type); + GOOGLE_DCHECK_EQ(extension->is_packed, other_extension.is_packed); + GOOGLE_DCHECK(!extension->is_repeated); + if (other_extension.is_lazy) { + if (extension->is_lazy) { + extension->lazymessage_value->MergeFrom( + GetPrototypeForLazyMessage(extendee, number), + *other_extension.lazymessage_value, arena_); + } else { + extension->message_value->CheckTypeAndMergeFrom( + other_extension.lazymessage_value->GetMessage( + *extension->message_value, other_arena)); + } + } else { + if (extension->is_lazy) { + extension->lazymessage_value + ->MutableMessage(*other_extension.message_value, arena_) + ->CheckTypeAndMergeFrom(*other_extension.message_value); + } else { + extension->message_value->CheckTypeAndMergeFrom( + *other_extension.message_value); + } + } + } + extension->is_cleared = false; + break; + } + } + } + } +} + +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; + + GOOGLE_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 { + // 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()) return false; + } + return true; + } + for (const KeyValue* it = flat_begin(); it != flat_end(); ++it) { + if (!it->second.IsInitialized()) return false; + } + return true; +} + +bool ExtensionSet::FindExtensionInfoFromTag(arc_ui32 tag, + ExtensionFinder* extension_finder, + int* field_number, + ExtensionInfo* extension, + bool* was_packed_on_wire) { + *field_number = WireFormatLite::GetTagFieldNumber(tag); + WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag); + return FindExtensionInfoFromFieldNumber(wire_type, *field_number, + extension_finder, extension, + was_packed_on_wire); +} + +bool ExtensionSet::FindExtensionInfoFromFieldNumber( + int wire_type, int field_number, ExtensionFinder* extension_finder, + ExtensionInfo* extension, bool* was_packed_on_wire) const { + if (!extension_finder->Find(field_number, extension)) { + return false; + } + + WireFormatLite::WireType expected_wire_type = + WireFormatLite::WireTypeForFieldType(real_type(extension->type)); + + // Check if this is a packed field. + *was_packed_on_wire = false; + if (extension->is_repeated && + wire_type == WireFormatLite::WIRETYPE_LENGTH_DELIMITED && + is_packable(expected_wire_type)) { + *was_packed_on_wire = true; + return true; + } + // Otherwise the wire type must match. + return expected_wire_type == wire_type; +} + +bool ExtensionSet::ParseField(arc_ui32 tag, io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper) { + int number; + bool was_packed_on_wire; + ExtensionInfo extension; + if (!FindExtensionInfoFromTag(tag, extension_finder, &number, &extension, + &was_packed_on_wire)) { + return field_skipper->SkipField(input, tag); + } else { + return ParseFieldWithExtensionInfo(number, was_packed_on_wire, extension, + input, field_skipper); + } +} + +const char* ExtensionSet::ParseField(arc_ui64 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<TProtoStringType>(), ptr, ctx); + } + return ParseFieldWithExtensionInfo<TProtoStringType>( + 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, TProtoStringType>(ptr, extendee, + metadata, ctx); +} + +bool ExtensionSet::ParseFieldWithExtensionInfo(int number, + bool was_packed_on_wire, + const ExtensionInfo& extension, + io::CodedInputStream* input, + FieldSkipper* field_skipper) { + // Explicitly not read extension.is_packed, instead check whether the field + // was encoded in packed form on the wire. + if (was_packed_on_wire) { + arc_ui32 size; + if (!input->ReadVarint32(&size)) return false; + io::CodedInputStream::Limit limit = input->PushLimit(size); + + switch (extension.type) { +#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: \ + while (input->BytesUntilLimit() > 0) { \ + CPP_LOWERCASE value; \ + if (!WireFormatLite::ReadPrimitive<CPP_LOWERCASE, \ + WireFormatLite::TYPE_##UPPERCASE>( \ + input, &value)) \ + return false; \ + Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ + extension.is_packed, value, extension.descriptor); \ + } \ + break + + HANDLE_TYPE(INT32, Int32, arc_i32); + HANDLE_TYPE(INT64, Int64, arc_i64); + HANDLE_TYPE(UINT32, UInt32, arc_ui32); + HANDLE_TYPE(UINT64, UInt64, arc_ui64); + HANDLE_TYPE(SINT32, Int32, arc_i32); + HANDLE_TYPE(SINT64, Int64, arc_i64); + HANDLE_TYPE(FIXED32, UInt32, arc_ui32); + HANDLE_TYPE(FIXED64, UInt64, arc_ui64); + HANDLE_TYPE(SFIXED32, Int32, arc_i32); + HANDLE_TYPE(SFIXED64, Int64, arc_i64); + HANDLE_TYPE(FLOAT, Float, float); + HANDLE_TYPE(DOUBLE, Double, double); + HANDLE_TYPE(BOOL, Bool, bool); +#undef HANDLE_TYPE + + case WireFormatLite::TYPE_ENUM: + while (input->BytesUntilLimit() > 0) { + int value; + if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>( + input, &value)) + return false; + if (extension.enum_validity_check.func( + extension.enum_validity_check.arg, value)) { + AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, + value, extension.descriptor); + } else { + // Invalid value. Treat as unknown. + field_skipper->SkipUnknownEnum(number, value); + } + } + break; + + case WireFormatLite::TYPE_STRING: + case WireFormatLite::TYPE_BYTES: + case WireFormatLite::TYPE_GROUP: + case WireFormatLite::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + + input->PopLimit(limit); + } else { + switch (extension.type) { +#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: { \ + CPP_LOWERCASE value; \ + if (!WireFormatLite::ReadPrimitive<CPP_LOWERCASE, \ + WireFormatLite::TYPE_##UPPERCASE>( \ + input, &value)) \ + return false; \ + if (extension.is_repeated) { \ + Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ + extension.is_packed, value, extension.descriptor); \ + } else { \ + Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \ + extension.descriptor); \ + } \ + } break + + HANDLE_TYPE(INT32, Int32, arc_i32); + HANDLE_TYPE(INT64, Int64, arc_i64); + HANDLE_TYPE(UINT32, UInt32, arc_ui32); + HANDLE_TYPE(UINT64, UInt64, arc_ui64); + HANDLE_TYPE(SINT32, Int32, arc_i32); + HANDLE_TYPE(SINT64, Int64, arc_i64); + HANDLE_TYPE(FIXED32, UInt32, arc_ui32); + HANDLE_TYPE(FIXED64, UInt64, arc_ui64); + HANDLE_TYPE(SFIXED32, Int32, arc_i32); + HANDLE_TYPE(SFIXED64, Int64, arc_i64); + HANDLE_TYPE(FLOAT, Float, float); + HANDLE_TYPE(DOUBLE, Double, double); + HANDLE_TYPE(BOOL, Bool, bool); +#undef HANDLE_TYPE + + case WireFormatLite::TYPE_ENUM: { + int value; + if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>( + input, &value)) + return false; + + if (!extension.enum_validity_check.func( + extension.enum_validity_check.arg, value)) { + // Invalid value. Treat as unknown. + field_skipper->SkipUnknownEnum(number, value); + } else if (extension.is_repeated) { + AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value, + extension.descriptor); + } else { + SetEnum(number, WireFormatLite::TYPE_ENUM, value, + extension.descriptor); + } + break; + } + + case WireFormatLite::TYPE_STRING: { + TProtoStringType* value = + extension.is_repeated + ? AddString(number, WireFormatLite::TYPE_STRING, + extension.descriptor) + : MutableString(number, WireFormatLite::TYPE_STRING, + extension.descriptor); + if (!WireFormatLite::ReadString(input, value)) return false; + break; + } + + case WireFormatLite::TYPE_BYTES: { + TProtoStringType* value = + extension.is_repeated + ? AddString(number, WireFormatLite::TYPE_BYTES, + extension.descriptor) + : MutableString(number, WireFormatLite::TYPE_BYTES, + extension.descriptor); + if (!WireFormatLite::ReadBytes(input, value)) return false; + break; + } + + case WireFormatLite::TYPE_GROUP: { + MessageLite* value = + extension.is_repeated + ? AddMessage(number, WireFormatLite::TYPE_GROUP, + *extension.message_info.prototype, + extension.descriptor) + : MutableMessage(number, WireFormatLite::TYPE_GROUP, + *extension.message_info.prototype, + extension.descriptor); + if (!WireFormatLite::ReadGroup(number, input, value)) return false; + break; + } + + case WireFormatLite::TYPE_MESSAGE: { + MessageLite* value = + extension.is_repeated + ? AddMessage(number, WireFormatLite::TYPE_MESSAGE, + *extension.message_info.prototype, + extension.descriptor) + : MutableMessage(number, WireFormatLite::TYPE_MESSAGE, + *extension.message_info.prototype, + extension.descriptor); + if (!WireFormatLite::ReadMessage(input, value)) return false; + break; + } + } + } + + return true; +} + +bool ExtensionSet::ParseField(arc_ui32 tag, io::CodedInputStream* input, + const MessageLite* extendee) { + FieldSkipper skipper; + GeneratedExtensionFinder finder(extendee); + return ParseField(tag, input, &finder, &skipper); +} + +bool ExtensionSet::ParseField(arc_ui32 tag, io::CodedInputStream* input, + const MessageLite* extendee, + io::CodedOutputStream* unknown_fields) { + CodedOutputStreamFieldSkipper skipper(unknown_fields); + GeneratedExtensionFinder finder(extendee); + return ParseField(tag, input, &finder, &skipper); +} + +bool ExtensionSet::ParseMessageSetLite(io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper) { + while (true) { + const arc_ui32 tag = input->ReadTag(); + switch (tag) { + case 0: + return true; + case WireFormatLite::kMessageSetItemStartTag: + if (!ParseMessageSetItemLite(input, extension_finder, field_skipper)) { + return false; + } + break; + default: + if (!ParseField(tag, input, extension_finder, field_skipper)) { + return false; + } + break; + } + } +} + +bool ExtensionSet::ParseMessageSetItemLite(io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper) { + struct MSLite { + bool ParseField(int type_id, io::CodedInputStream* input) { + return me->ParseField( + WireFormatLite::WIRETYPE_LENGTH_DELIMITED + 8 * type_id, input, + extension_finder, field_skipper); + } + + bool SkipField(arc_ui32 tag, io::CodedInputStream* input) { + return field_skipper->SkipField(input, tag); + } + + ExtensionSet* me; + ExtensionFinder* extension_finder; + FieldSkipper* field_skipper; + }; + + return ParseMessageSetItemImpl(input, + MSLite{this, extension_finder, field_skipper}); +} + +bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, + const MessageLite* extendee, + TProtoStringType* unknown_fields) { + io::StringOutputStream zcis(unknown_fields); + io::CodedOutputStream output(&zcis); + CodedOutputStreamFieldSkipper skipper(&output); + GeneratedExtensionFinder finder(extendee); + return ParseMessageSetLite(input, &finder, &skipper); +} + +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, arc_i32); + HANDLE_TYPE(INT64, arc_i64); + HANDLE_TYPE(UINT32, arc_ui32); + HANDLE_TYPE(UINT64, arc_ui64); + 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, arc_i32); + HANDLE_TYPE(INT64, Int64, arc_i64); + HANDLE_TYPE(UINT32, UInt32, arc_ui32); + HANDLE_TYPE(UINT64, UInt64, arc_ui64); + HANDLE_TYPE(SINT32, SInt32, arc_i32); + HANDLE_TYPE(SINT64, SInt64, arc_i64); + 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, arc_ui32); + HANDLE_TYPE(FIXED64, Fixed64, arc_ui64); + HANDLE_TYPE(SFIXED32, SFixed32, arc_i32); + HANDLE_TYPE(SFIXED64, SFixed64, arc_i64); + 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: + GOOGLE_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, arc_i32); + HANDLE_TYPE(INT64, Int64, arc_i64); + HANDLE_TYPE(UINT32, UInt32, arc_ui32); + HANDLE_TYPE(UINT64, UInt64, arc_ui64); + HANDLE_TYPE(SINT32, SInt32, arc_i32); + HANDLE_TYPE(SINT64, SInt64, arc_i64); + 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, arc_ui32); + HANDLE_TYPE(FIXED64, Fixed64, arc_ui64); + HANDLE_TYPE(SFIXED32, SFixed32, arc_i32); + HANDLE_TYPE(SFIXED64, SFixed64, arc_i64); + 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, arc_i32_value); + HANDLE_TYPE(INT64, Int64, arc_i64_value); + HANDLE_TYPE(UINT32, UInt32, arc_ui32_value); + HANDLE_TYPE(UINT64, UInt64, arc_ui64_value); + HANDLE_TYPE(SINT32, SInt32, arc_i32_value); + HANDLE_TYPE(SINT64, SInt64, arc_i64_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 { + GOOGLE_DCHECK(is_repeated); + switch (cpp_type(type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ + case WireFormatLite::CPPTYPE_##UPPERCASE: \ + return repeated_##LOWERCASE##_value->size() + + HANDLE_TYPE(INT32, arc_i32); + HANDLE_TYPE(INT64, arc_i64); + HANDLE_TYPE(UINT32, arc_ui32); + HANDLE_TYPE(UINT64, arc_ui64); + 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 + } + + GOOGLE_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, arc_i32); + HANDLE_TYPE(INT64, arc_i64); + HANDLE_TYPE(UINT32, arc_ui32); + HANDLE_TYPE(UINT64, arc_ui64); + 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 { + if (cpp_type(type) == WireFormatLite::CPPTYPE_MESSAGE) { + if (is_repeated) { + for (int i = 0; i < repeated_message_value->size(); i++) { + if (!repeated_message_value->Get(i).IsInitialized()) { + return false; + } + } + } else { + if (!is_cleared) { + if (is_lazy) { + if (!lazymessage_value->IsInitialized()) return false; + } else { + if (!message_value->IsInitialized()) return false; + } + } + } + } + return true; +} + +// 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); + GOOGLE_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, arc_i32); + HANDLE_TYPE(INT64, Int64, arc_i64); + HANDLE_TYPE(UINT32, UInt32, arc_ui32); + HANDLE_TYPE(UINT64, UInt64, arc_ui64); + HANDLE_TYPE(SINT32, SInt32, arc_i32); + HANDLE_TYPE(SINT64, SInt64, arc_i64); + HANDLE_TYPE(FIXED32, Fixed32, arc_ui32); + HANDLE_TYPE(FIXED64, Fixed64, arc_ui64); + HANDLE_TYPE(SFIXED32, SFixed32, arc_i32); + HANDLE_TYPE(SFIXED64, SFixed64, arc_i64); + 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: + GOOGLE_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, arc_i32); + HANDLE_TYPE(INT64, Int64, arc_i64); + HANDLE_TYPE(UINT32, UInt32, arc_ui32); + HANDLE_TYPE(UINT64, UInt64, arc_ui64); + HANDLE_TYPE(SINT32, SInt32, arc_i32); + HANDLE_TYPE(SINT64, SInt64, arc_i64); + HANDLE_TYPE(FIXED32, Fixed32, arc_ui32); + HANDLE_TYPE(FIXED64, Fixed64, arc_ui64); + HANDLE_TYPE(SFIXED32, SFixed32, arc_i32); + HANDLE_TYPE(SFIXED64, SFixed64, arc_i64); + 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 +#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::InternalWrite##CAMELCASE( \ + number, repeated_##LOWERCASE##_value->Get(i), target, stream); \ + } \ + break + + HANDLE_TYPE(GROUP, Group, message); + HANDLE_TYPE(MESSAGE, Message, message); +#undef HANDLE_TYPE + } + } + } 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, arc_i32_value); + HANDLE_TYPE(INT64, Int64, arc_i64_value); + HANDLE_TYPE(UINT32, UInt32, arc_ui32_value); + HANDLE_TYPE(UINT64, UInt64, arc_ui64_value); + HANDLE_TYPE(SINT32, SInt32, arc_i32_value); + HANDLE_TYPE(SINT64, SInt64, arc_i64_value); + HANDLE_TYPE(FIXED32, Fixed32, arc_ui32_value); + HANDLE_TYPE(FIXED64, Fixed64, arc_ui64_value); + HANDLE_TYPE(SFIXED32, SFixed32, arc_i32_value); + HANDLE_TYPE(SFIXED64, SFixed64, arc_i64_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 = stream->EnsureSpace(target); + target = WireFormatLite::InternalWriteMessage(number, *message_value, + 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. + GOOGLE_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, 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; +} + + +} // namespace internal +} // namespace protobuf +} // namespace google + +#include <google/protobuf/port_undef.inc> |