Index: third_party/protobuf/src/google/protobuf/extension_set_heavy.cc |
=================================================================== |
--- third_party/protobuf/src/google/protobuf/extension_set_heavy.cc (revision 216642) |
+++ third_party/protobuf/src/google/protobuf/extension_set_heavy.cc (working copy) |
@@ -35,17 +35,20 @@ |
// Contains methods defined in extension_set.h which cannot be part of the |
// lite library because they use descriptors or reflection. |
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h> |
+#include <google/protobuf/descriptor.h> |
#include <google/protobuf/extension_set.h> |
-#include <google/protobuf/descriptor.h> |
#include <google/protobuf/message.h> |
#include <google/protobuf/repeated_field.h> |
#include <google/protobuf/wire_format.h> |
#include <google/protobuf/wire_format_lite_inl.h> |
namespace google { |
+ |
namespace protobuf { |
namespace internal { |
+ |
// Implementation of ExtensionFinder which finds extensions in a given |
// DescriptorPool, using the given MessageFactory to construct sub-objects. |
// This class is implemented in extension_set_heavy.cc. |
@@ -103,6 +106,11 @@ |
static_cast<FieldDescriptor::Type>(type)); |
} |
+inline WireFormatLite::FieldType field_type(FieldType type) { |
+ GOOGLE_DCHECK(type > 0 && type <= WireFormatLite::MAX_FIELD_TYPE); |
+ return static_cast<WireFormatLite::FieldType>(type); |
+} |
+ |
#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \ |
GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \ |
: FieldDescriptor::LABEL_OPTIONAL, \ |
@@ -118,7 +126,12 @@ |
return *factory->GetPrototype(message_type); |
} else { |
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE); |
- return *iter->second.message_value; |
+ if (iter->second.is_lazy) { |
+ return iter->second.lazymessage_value->GetMessage( |
+ *factory->GetPrototype(message_type)); |
+ } else { |
+ return *iter->second.message_value; |
+ } |
} |
} |
@@ -132,15 +145,43 @@ |
extension->is_packed = false; |
const MessageLite* prototype = |
factory->GetPrototype(descriptor->message_type()); |
- GOOGLE_CHECK(prototype != NULL); |
+ extension->is_lazy = false; |
extension->message_value = prototype->New(); |
+ extension->is_cleared = false; |
+ return extension->message_value; |
} else { |
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); |
+ extension->is_cleared = false; |
+ if (extension->is_lazy) { |
+ return extension->lazymessage_value->MutableMessage( |
+ *factory->GetPrototype(descriptor->message_type())); |
+ } else { |
+ return extension->message_value; |
+ } |
} |
- extension->is_cleared = false; |
- return extension->message_value; |
} |
+MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor, |
+ MessageFactory* factory) { |
+ map<int, Extension>::iterator iter = extensions_.find(descriptor->number()); |
+ if (iter == extensions_.end()) { |
+ // Not present. Return NULL. |
+ return NULL; |
+ } else { |
+ GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE); |
+ MessageLite* ret = NULL; |
+ if (iter->second.is_lazy) { |
+ ret = iter->second.lazymessage_value->ReleaseMessage( |
+ *factory->GetPrototype(descriptor->message_type())); |
+ delete iter->second.lazymessage_value; |
+ } else { |
+ ret = iter->second.message_value; |
+ } |
+ extensions_.erase(descriptor->number()); |
+ return ret; |
+ } |
+} |
+ |
MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, |
MessageFactory* factory) { |
Extension* extension; |
@@ -157,7 +198,7 @@ |
// RepeatedPtrField<Message> does not know how to Add() since it cannot |
// allocate an abstract object, so we have to be tricky. |
MessageLite* result = extension->repeated_message_value |
- ->AddFromCleared<internal::GenericTypeHandler<MessageLite> >(); |
+ ->AddFromCleared<GenericTypeHandler<MessageLite> >(); |
if (result == NULL) { |
const MessageLite* prototype; |
if (extension->repeated_message_value->size() == 0) { |
@@ -286,7 +327,11 @@ |
StringSpaceUsedExcludingSelf(*string_value); |
break; |
case FieldDescriptor::CPPTYPE_MESSAGE: |
- total_size += down_cast<Message*>(message_value)->SpaceUsed(); |
+ if (is_lazy) { |
+ total_size += lazymessage_value->SpaceUsed(); |
+ } else { |
+ total_size += down_cast<Message*>(message_value)->SpaceUsed(); |
+ } |
break; |
default: |
// No extra storage costs for primitive types. |
@@ -419,8 +464,15 @@ |
HANDLE_TYPE( BYTES, Bytes, *string_value); |
HANDLE_TYPE( ENUM, Enum, enum_value); |
HANDLE_TYPE( GROUP, Group, *message_value); |
- HANDLE_TYPE( MESSAGE, Message, *message_value); |
#undef HANDLE_TYPE |
+ case FieldDescriptor::TYPE_MESSAGE: |
+ if (is_lazy) { |
+ target = lazymessage_value->WriteMessageToArray(number, target); |
+ } else { |
+ target = WireFormatLite::WriteMessageToArray( |
+ number, *message_value, target); |
+ } |
+ break; |
} |
} |
return target; |
@@ -444,14 +496,217 @@ |
target = WireFormatLite::WriteUInt32ToArray( |
WireFormatLite::kMessageSetTypeIdNumber, number, target); |
// Write message. |
- target = WireFormatLite::WriteMessageToArray( |
- WireFormatLite::kMessageSetMessageNumber, *message_value, target); |
+ if (is_lazy) { |
+ target = lazymessage_value->WriteMessageToArray( |
+ WireFormatLite::kMessageSetMessageNumber, target); |
+ } else { |
+ target = WireFormatLite::WriteMessageToArray( |
+ WireFormatLite::kMessageSetMessageNumber, *message_value, target); |
+ } |
// End group. |
target = io::CodedOutputStream::WriteTagToArray( |
WireFormatLite::kMessageSetItemEndTag, target); |
return target; |
} |
+ |
+bool ExtensionSet::ParseFieldMaybeLazily( |
+ uint32 tag, io::CodedInputStream* input, |
+ ExtensionFinder* extension_finder, |
+ FieldSkipper* field_skipper) { |
+ return ParseField(tag, input, extension_finder, field_skipper); |
+} |
+ |
+bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, |
+ ExtensionFinder* extension_finder, |
+ FieldSkipper* field_skipper) { |
+ while (true) { |
+ uint32 tag = input->ReadTag(); |
+ switch (tag) { |
+ case 0: |
+ return true; |
+ case WireFormatLite::kMessageSetItemStartTag: |
+ if (!ParseMessageSetItem(input, extension_finder, field_skipper)) { |
+ return false; |
+ } |
+ break; |
+ default: |
+ if (!ParseField(tag, input, extension_finder, field_skipper)) { |
+ return false; |
+ } |
+ break; |
+ } |
+ } |
+} |
+ |
+bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, |
+ const MessageLite* containing_type, |
+ UnknownFieldSet* unknown_fields) { |
+ FieldSkipper skipper(unknown_fields); |
+ GeneratedExtensionFinder finder(containing_type); |
+ return ParseMessageSet(input, &finder, &skipper); |
+} |
+ |
+bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input, |
+ ExtensionFinder* extension_finder, |
+ FieldSkipper* field_skipper) { |
+ // TODO(kenton): It would be nice to share code between this and |
+ // WireFormatLite::ParseAndMergeMessageSetItem(), but I think the |
+ // differences would be hard to factor out. |
+ |
+ // This method parses a group which should contain two fields: |
+ // required int32 type_id = 2; |
+ // required data message = 3; |
+ |
+ // Once we see a type_id, we'll construct a fake tag for this extension |
+ // which is the tag it would have had under the proto2 extensions wire |
+ // format. |
+ uint32 fake_tag = 0; |
+ |
+ // If we see message data before the type_id, we'll append it to this so |
+ // we can parse it later. |
+ string message_data; |
+ |
+ while (true) { |
+ uint32 tag = input->ReadTag(); |
+ if (tag == 0) return false; |
+ |
+ switch (tag) { |
+ case WireFormatLite::kMessageSetTypeIdTag: { |
+ uint32 type_id; |
+ if (!input->ReadVarint32(&type_id)) return false; |
+ fake_tag = WireFormatLite::MakeTag(type_id, |
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED); |
+ |
+ if (!message_data.empty()) { |
+ // We saw some message data before the type_id. Have to parse it |
+ // now. |
+ io::CodedInputStream sub_input( |
+ reinterpret_cast<const uint8*>(message_data.data()), |
+ message_data.size()); |
+ if (!ParseFieldMaybeLazily(fake_tag, &sub_input, |
+ extension_finder, field_skipper)) { |
+ return false; |
+ } |
+ message_data.clear(); |
+ } |
+ |
+ break; |
+ } |
+ |
+ case WireFormatLite::kMessageSetMessageTag: { |
+ if (fake_tag == 0) { |
+ // We haven't seen a type_id yet. Append this data to message_data. |
+ string temp; |
+ uint32 length; |
+ if (!input->ReadVarint32(&length)) return false; |
+ if (!input->ReadString(&temp, length)) return false; |
+ io::StringOutputStream output_stream(&message_data); |
+ io::CodedOutputStream coded_output(&output_stream); |
+ coded_output.WriteVarint32(length); |
+ coded_output.WriteString(temp); |
+ } else { |
+ // Already saw type_id, so we can parse this directly. |
+ if (!ParseFieldMaybeLazily(fake_tag, input, |
+ extension_finder, field_skipper)) { |
+ return false; |
+ } |
+ } |
+ |
+ break; |
+ } |
+ |
+ case WireFormatLite::kMessageSetItemEndTag: { |
+ return true; |
+ } |
+ |
+ default: { |
+ if (!field_skipper->SkipField(input, tag)) return false; |
+ } |
+ } |
+ } |
+} |
+ |
+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); |
+} |
+ |
+int 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; |
+ |
+ int our_size = WireFormatLite::kMessageSetItemTagsSize; |
+ |
+ // type_id |
+ our_size += io::CodedOutputStream::VarintSize32(number); |
+ |
+ // message |
+ int message_size = 0; |
+ if (is_lazy) { |
+ message_size = lazymessage_value->ByteSize(); |
+ } else { |
+ message_size = message_value->ByteSize(); |
+ } |
+ |
+ our_size += io::CodedOutputStream::VarintSize32(message_size); |
+ our_size += message_size; |
+ |
+ return our_size; |
+} |
+ |
+void ExtensionSet::SerializeMessageSetWithCachedSizes( |
+ io::CodedOutputStream* output) const { |
+ map<int, Extension>::const_iterator iter; |
+ for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) { |
+ iter->second.SerializeMessageSetItemWithCachedSizes(iter->first, output); |
+ } |
+} |
+ |
+int ExtensionSet::MessageSetByteSize() const { |
+ int total_size = 0; |
+ |
+ for (map<int, Extension>::const_iterator iter = extensions_.begin(); |
+ iter != extensions_.end(); ++iter) { |
+ total_size += iter->second.MessageSetItemByteSize(iter->first); |
+ } |
+ |
+ return total_size; |
+} |
+ |
} // namespace internal |
} // namespace protobuf |
} // namespace google |