diff options
Diffstat (limited to 'src/google/protobuf/extension_set.cc')
-rw-r--r-- | src/google/protobuf/extension_set.cc | 454 |
1 files changed, 409 insertions, 45 deletions
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index cb205c4f..6629ec04 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -32,16 +32,25 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/stubs/hash.h> +#include <google/protobuf/extension_set.h> + #include <tuple> +#include <unordered_map> #include <utility> #include <google/protobuf/stubs/common.h> -#include <google/protobuf/extension_set.h> -#include <google/protobuf/message_lite.h> #include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/wire_format_lite_inl.h> +#include <google/protobuf/io/zero_copy_stream_impl_lite.h> +#include <google/protobuf/message_lite.h> +#include <google/protobuf/metadata_lite.h> #include <google/protobuf/repeated_field.h> +#include <google/protobuf/wire_format_lite_inl.h> #include <google/protobuf/stubs/map_util.h> +#include <google/protobuf/stubs/hash.h> + +#include <google/protobuf/port_def.inc> +#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER +#include <google/protobuf/parse_context.h> +#endif namespace google { namespace protobuf { @@ -77,8 +86,16 @@ inline bool is_packable(WireFormatLite::WireType type) { } // Registry stuff. -typedef hash_map<std::pair<const MessageLite*, int>, - ExtensionInfo> ExtensionRegistry; +struct ExtensionHasher { + std::size_t operator()(const std::pair<const MessageLite*, int>& p) const { + return std::hash<const MessageLite*>{}(p.first) ^ + std::hash<int>{}(p.second); + } +}; + +typedef std::unordered_map<std::pair<const MessageLite*, int>, ExtensionInfo, + ExtensionHasher> + ExtensionRegistry; static const ExtensionRegistry* global_registry = nullptr; @@ -89,7 +106,7 @@ void Register(const MessageLite* containing_type, static auto local_static_registry = OnShutdownDelete(new ExtensionRegistry); global_registry = local_static_registry; if (!InsertIfNotPresent(local_static_registry, - std::make_pair(containing_type, number), info)) { + std::make_pair(containing_type, number), info)) { GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \"" << containing_type->GetTypeName() << "\", field number " << number << "."; @@ -99,8 +116,9 @@ void Register(const MessageLite* containing_type, const ExtensionInfo* FindRegisteredExtension( const MessageLite* containing_type, int number) { return global_registry == nullptr - ? nullptr - : FindOrNull(*global_registry, std::make_pair(containing_type, number)); + ? nullptr + : FindOrNull(*global_registry, + std::make_pair(containing_type, number)); } } // namespace @@ -168,34 +186,50 @@ void ExtensionSet::RegisterMessageExtension(const MessageLite* containing_type, // =================================================================== // Constructors and basic methods. -ExtensionSet::ExtensionSet(::google::protobuf::Arena* arena) +ExtensionSet::ExtensionSet(Arena* arena) : arena_(arena), flat_capacity_(0), flat_size_(0), - map_{flat_capacity_ == 0 ? NULL - : ::google::protobuf::Arena::CreateArray<KeyValue>( - arena_, flat_capacity_)} {} + map_{flat_capacity_ == 0 + ? NULL + : Arena::CreateArray<KeyValue>(arena_, flat_capacity_)} {} ExtensionSet::ExtensionSet() : arena_(NULL), flat_capacity_(0), flat_size_(0), - map_{flat_capacity_ == 0 ? NULL - : ::google::protobuf::Arena::CreateArray<KeyValue>( - arena_, flat_capacity_)} {} + map_{flat_capacity_ == 0 + ? NULL + : Arena::CreateArray<KeyValue>(arena_, flat_capacity_)} {} ExtensionSet::~ExtensionSet() { // Deletes all allocated extensions. if (arena_ == NULL) { ForEach([](int /* number */, Extension& ext) { ext.Free(); }); - if (GOOGLE_PREDICT_FALSE(is_large())) { + if (PROTOBUF_PREDICT_FALSE(is_large())) { delete map_.large; } else { - delete[] map_.flat; + DeleteFlatMap(map_.flat, flat_capacity_); } } } +void ExtensionSet::DeleteFlatMap( + const ExtensionSet::KeyValue* flat, uint16 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* containing_type, // const DescriptorPool* pool, @@ -594,7 +628,7 @@ void ExtensionSet::SetAllocatedMessage(int number, FieldType type, ClearExtension(number); return; } - ::google::protobuf::Arena* message_arena = message->GetArena(); + Arena* message_arena = message->GetArena(); Extension* extension; if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; @@ -746,10 +780,9 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type, // 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<::google::protobuf::internal::RepeatedPtrFieldBase*>( - extension->repeated_message_value) - ->AddFromCleared<GenericTypeHandler<MessageLite> >(); + MessageLite* result = reinterpret_cast<internal::RepeatedPtrFieldBase*>( + extension->repeated_message_value) + ->AddFromCleared<GenericTypeHandler<MessageLite>>(); if (result == NULL) { result = prototype.New(arena_); extension->repeated_message_value->AddAllocated(result); @@ -879,8 +912,8 @@ size_t SizeOfUnion(ItX it_xs, ItX end_xs, ItY it_ys, ItY end_ys) { } // namespace void ExtensionSet::MergeFrom(const ExtensionSet& other) { - if (GOOGLE_PREDICT_TRUE(!is_large())) { - if (GOOGLE_PREDICT_TRUE(!other.is_large())) { + 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 { @@ -945,9 +978,9 @@ void ExtensionSet::InternalExtensionMergeFrom( for (int i = 0; i < other_repeated_message->size(); i++) { const MessageLite& other_message = other_repeated_message->Get(i); MessageLite* target = - reinterpret_cast<::google::protobuf::internal::RepeatedPtrFieldBase*>( + reinterpret_cast<internal::RepeatedPtrFieldBase*>( extension->repeated_message_value) - ->AddFromCleared<GenericTypeHandler<MessageLite> >(); + ->AddFromCleared<GenericTypeHandler<MessageLite>>(); if (target == NULL) { target = other_message.New(arena_); extension->repeated_message_value->AddAllocated(target); @@ -1108,7 +1141,7 @@ void ExtensionSet::SwapExtension(ExtensionSet* other, bool ExtensionSet::IsInitialized() const { // Extensions are never required. However, we need to check that all // embedded messages are initialized. - if (GOOGLE_PREDICT_FALSE(is_large())) { + if (PROTOBUF_PREDICT_FALSE(is_large())) { for (const auto& kv : *map_.large) { if (!kv.second.IsInitialized()) return false; } @@ -1167,6 +1200,212 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, } } +#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER +std::pair<const char*, bool> ExtensionSet::ParseField( + uint64 tag, ParseClosure parent, const char* begin, const char* end, + const MessageLite* containing_type, + internal::InternalMetadataWithArenaLite* metadata, + internal::ParseContext* ctx) { + GeneratedExtensionFinder finder(containing_type); + 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, parent, begin, end, + metadata->mutable_unknown_fields(), ctx); + } + auto ptr = begin; + ParseClosure child; + int depth; + if (was_packed_on_wire) { + switch (extension.type) { +#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: \ + child = { \ + internal::Packed##CPP_CAMELCASE##Parser, \ + MutableRawRepeatedField(number, extension.type, extension.is_packed, \ + extension.descriptor)}; \ + goto length_delim + HANDLE_TYPE(INT32, Int32); + HANDLE_TYPE(INT64, Int64); + HANDLE_TYPE(UINT32, UInt32); + HANDLE_TYPE(UINT64, UInt64); + HANDLE_TYPE(SINT32, SInt32); + HANDLE_TYPE(SINT64, SInt64); + 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 + + case WireFormatLite::TYPE_ENUM: + ctx->extra_parse_data().SetEnumValidatorArg( + extension.enum_validity_check.func, + extension.enum_validity_check.arg, + metadata->mutable_unknown_fields(), tag >> 3); + child = { + internal::PackedValidEnumParserLiteArg, + MutableRawRepeatedField(number, extension.type, extension.is_packed, + extension.descriptor)}; + goto length_delim; + 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 (extension.type) { +#define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: { \ + uint64 value; \ + ptr = Varint::Parse64(ptr, &value); \ + GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true)); \ + 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_VARINT_TYPE(INT32, Int32); + HANDLE_VARINT_TYPE(INT64, Int64); + HANDLE_VARINT_TYPE(UINT32, UInt32); + HANDLE_VARINT_TYPE(UINT64, UInt64); +#undef HANDLE_VARINT_TYPE +#define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE) \ + case WireFormatLite::TYPE_##UPPERCASE: { \ + uint64 val; \ + ptr = Varint::Parse64(ptr, &val); \ + GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true)); \ + auto value = WireFormatLite::ZigZagDecode##SIZE(val); \ + 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_SVARINT_TYPE(SINT32, Int32, 32); + HANDLE_SVARINT_TYPE(SINT64, Int64, 64); +#undef HANDLE_SVARINT_TYPE +#define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE) \ + case WireFormatLite::TYPE_##UPPERCASE: { \ + CPPTYPE value; \ + std::memcpy(&value, ptr, sizeof(CPPTYPE)); \ + ptr += sizeof(CPPTYPE); \ + 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_FIXED_TYPE(FIXED32, UInt32, uint32); + HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64); + HANDLE_FIXED_TYPE(SFIXED32, Int32, int32); + HANDLE_FIXED_TYPE(SFIXED64, Int64, int64); + HANDLE_FIXED_TYPE(FLOAT, Float, float); + HANDLE_FIXED_TYPE(DOUBLE, Double, double); + HANDLE_FIXED_TYPE(BOOL, Bool, bool); +#undef HANDLE_FIXED_TYPE + + case WireFormatLite::TYPE_ENUM: { + uint64 val; + ptr = Varint::Parse64(ptr, &val); + GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true)); + int value = val; + + if (!extension.enum_validity_check.func( + extension.enum_validity_check.arg, value)) { + WriteVarint(number, val, metadata->mutable_unknown_fields()); + } 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_BYTES: + case WireFormatLite::TYPE_STRING: { + string* value = extension.is_repeated + ? AddString(number, WireFormatLite::TYPE_STRING, + extension.descriptor) + : MutableString(number, WireFormatLite::TYPE_STRING, + extension.descriptor); + child = {StringParser, value}; + goto length_delim; + } + + case WireFormatLite::TYPE_GROUP: { + MessageLite* value = + extension.is_repeated + ? AddMessage(number, WireFormatLite::TYPE_GROUP, + *extension.message_prototype, extension.descriptor) + : MutableMessage(number, WireFormatLite::TYPE_GROUP, + *extension.message_prototype, + extension.descriptor); + child = {value->_ParseFunc(), value}; + bool ok = ctx->PrepareGroup(tag, &depth); + GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true)); + ptr = child(ptr, end, ctx); + GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true)); + if (ctx->GroupContinues(depth)) goto group_continues; + break; + } + + case WireFormatLite::TYPE_MESSAGE: { + MessageLite* value = + extension.is_repeated + ? AddMessage(number, WireFormatLite::TYPE_MESSAGE, + *extension.message_prototype, extension.descriptor) + : MutableMessage(number, WireFormatLite::TYPE_MESSAGE, + *extension.message_prototype, + extension.descriptor); + child = {value->_ParseFunc(), value}; + goto length_delim; + } + } + } + + return std::make_pair(ptr, false); + +length_delim: + uint32 size; + ptr = Varint::Parse32Inline(ptr, &size); + GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true)); + if (size > end - ptr) goto len_delim_till_end; + { + auto newend = ptr + size; + bool ok = ctx->ParseExactRange(child, ptr, newend); + GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true)); + ptr = newend; + } + return std::make_pair(ptr, false); +len_delim_till_end: + return std::make_pair(ctx->StoreAndTailCall(ptr, end, parent, child, size), + true); + +group_continues: + ctx->StoreGroup(parent, child, depth); + return std::make_pair(ptr, true); +} +#endif + bool ExtensionSet::ParseFieldWithExtensionInfo( int number, bool was_packed_on_wire, const ExtensionInfo& extension, io::CodedInputStream* input, @@ -1342,20 +1581,65 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, return ParseField(tag, input, &finder, &skipper); } -// Defined in extension_set_heavy.cc. -// bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, -// const MessageLite* containing_type, -// UnknownFieldSet* unknown_fields) +bool ExtensionSet::ParseMessageSetLite(io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper) { + while (true) { + const uint32 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; + } + } +} -// Defined in extension_set_heavy.cc. -// bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, -// const MessageLite* containing_type, -// UnknownFieldSet* unknown_fields); +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(uint32 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* containing_type, + string* unknown_fields) { + io::StringOutputStream zcis(unknown_fields); + io::CodedOutputStream output(&zcis); + CodedOutputStreamFieldSkipper skipper(&output); + GeneratedExtensionFinder finder(containing_type); + return ParseMessageSetLite(input, &finder, &skipper); +} void ExtensionSet::SerializeWithCachedSizes( int start_field_number, int end_field_number, io::CodedOutputStream* output) const { - if (GOOGLE_PREDICT_FALSE(is_large())) { + 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) { @@ -1785,7 +2069,7 @@ bool ExtensionSet::Extension::IsInitialized() const { void ExtensionSet::LazyMessageExtension::UnusedKeyMethod() {} const ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) const { - if (GOOGLE_PREDICT_FALSE(is_large())) { + if (PROTOBUF_PREDICT_FALSE(is_large())) { return FindOrNullInLargeMap(key); } const KeyValue* end = flat_end(); @@ -1808,7 +2092,7 @@ const ExtensionSet::Extension* ExtensionSet::FindOrNullInLargeMap( } ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) { - if (GOOGLE_PREDICT_FALSE(is_large())) { + if (PROTOBUF_PREDICT_FALSE(is_large())) { return FindOrNullInLargeMap(key); } KeyValue* end = flat_end(); @@ -1830,7 +2114,7 @@ ExtensionSet::Extension* ExtensionSet::FindOrNullInLargeMap(int key) { } std::pair<ExtensionSet::Extension*, bool> ExtensionSet::Insert(int key) { - if (GOOGLE_PREDICT_FALSE(is_large())) { + if (PROTOBUF_PREDICT_FALSE(is_large())) { auto maybe = map_.large->insert({key, Extension()}); return {&maybe.first->second, maybe.second}; } @@ -1852,13 +2136,15 @@ std::pair<ExtensionSet::Extension*, bool> ExtensionSet::Insert(int key) { } void ExtensionSet::GrowCapacity(size_t minimum_new_capacity) { - if (GOOGLE_PREDICT_FALSE(is_large())) { + if (PROTOBUF_PREDICT_FALSE(is_large())) { return; // LargeMap does not have a "reserve" method. } if (flat_capacity_ >= minimum_new_capacity) { return; } + const auto old_flat_capacity = flat_capacity_; + do { flat_capacity_ = flat_capacity_ == 0 ? 1 : flat_capacity_ * 4; } while (flat_capacity_ < minimum_new_capacity); @@ -1867,24 +2153,26 @@ void ExtensionSet::GrowCapacity(size_t minimum_new_capacity) { const KeyValue* end = flat_end(); if (flat_capacity_ > kMaximumFlatCapacity) { // Switch to LargeMap - map_.large = ::google::protobuf::Arena::Create<LargeMap>(arena_); + map_.large = Arena::Create<LargeMap>(arena_); LargeMap::iterator hint = map_.large->begin(); for (const KeyValue* it = begin; it != end; ++it) { hint = map_.large->insert(hint, {it->first, it->second}); } flat_size_ = 0; } else { - map_.flat = ::google::protobuf::Arena::CreateArray<KeyValue>(arena_, flat_capacity_); + map_.flat = Arena::CreateArray<KeyValue>(arena_, flat_capacity_); std::copy(begin, end, map_.flat); } - if (arena_ == NULL) delete[] begin; + if (arena_ == nullptr) { + DeleteFlatMap(begin, old_flat_capacity); + } } // static constexpr uint16 ExtensionSet::kMaximumFlatCapacity; void ExtensionSet::Erase(int key) { - if (GOOGLE_PREDICT_FALSE(is_large())) { + if (PROTOBUF_PREDICT_FALSE(is_large())) { map_.large->erase(key); return; } @@ -1911,6 +2199,82 @@ RepeatedStringTypeTraits::GetDefaultRepeatedField() { return instance; } +void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes( + int number, + io::CodedOutputStream* output) const { + if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) { + // Not a valid MessageSet extension, but serialize it the normal way. + SerializeFieldWithCachedSizes(number, output); + return; + } + + if (is_cleared) return; + + // Start group. + output->WriteTag(WireFormatLite::kMessageSetItemStartTag); + + // Write type ID. + WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber, + number, + output); + // Write message. + if (is_lazy) { + lazymessage_value->WriteMessage( + WireFormatLite::kMessageSetMessageNumber, output); + } else { + WireFormatLite::WriteMessageMaybeToArray( + WireFormatLite::kMessageSetMessageNumber, + *message_value, + output); + } + + // End group. + output->WriteTag(WireFormatLite::kMessageSetItemEndTag); +} + +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; +} + +void ExtensionSet::SerializeMessageSetWithCachedSizes( + io::CodedOutputStream* output) const { + ForEach([output](int number, const Extension& ext) { + ext.SerializeMessageSetItemWithCachedSizes(number, output); + }); +} + +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 |