// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // http://code.google.com/p/protobuf/ // // 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. // // Contains methods defined in extension_set.h which cannot be part of the // lite library because they use descriptors or reflection. #include #include #include #include #include namespace google { namespace protobuf { namespace internal { void ExtensionSet::AppendToList(const Descriptor* containing_type, const DescriptorPool* pool, vector* output) const { for (map::const_iterator iter = extensions_.begin(); iter != extensions_.end(); ++iter) { bool has = false; if (iter->second.is_repeated) { has = iter->second.GetSize() > 0; } else { has = !iter->second.is_cleared; } if (has) { output->push_back( pool->FindExtensionByNumber(containing_type, iter->first)); } } } inline FieldDescriptor::CppType cpp_type(FieldType type) { return FieldDescriptor::TypeToCppType( static_cast(type)); } #define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \ GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \ : FieldDescriptor::LABEL_OPTIONAL, \ FieldDescriptor::LABEL_##LABEL); \ GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE) const MessageLite& ExtensionSet::GetMessage(int number, const Descriptor* message_type, MessageFactory* factory) const { map::const_iterator iter = extensions_.find(number); if (iter == extensions_.end() || iter->second.is_cleared) { // Not present. Return the default value. return *factory->GetPrototype(message_type); } else { GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE); return *iter->second.message_value; } } MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, const Descriptor* message_type, MessageFactory* factory) { Extension* extension; if (MaybeNewExtension(number, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); extension->is_repeated = false; extension->is_packed = false; const MessageLite* prototype = factory->GetPrototype(message_type); GOOGLE_CHECK(prototype != NULL); extension->message_value = prototype->New(); } else { GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); } extension->is_cleared = false; return extension->message_value; } MessageLite* ExtensionSet::AddMessage(int number, FieldType type, const Descriptor* message_type, MessageFactory* factory) { Extension* extension; if (MaybeNewExtension(number, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); extension->is_repeated = true; extension->repeated_message_value = new RepeatedPtrField(); } else { GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); } // RepeatedPtrField 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 >(); if (result == NULL) { const MessageLite* prototype; if (extension->repeated_message_value->size() == 0) { prototype = factory->GetPrototype(message_type); GOOGLE_CHECK(prototype != NULL); } else { prototype = &extension->repeated_message_value->Get(0); } result = prototype->New(); extension->repeated_message_value->AddAllocated(result); } return result; } bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, const MessageLite* containing_type, UnknownFieldSet* unknown_fields) { UnknownFieldSetFieldSkipper skipper(unknown_fields); return ParseField(tag, input, containing_type, &skipper); } bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, const MessageLite* containing_type, UnknownFieldSet* unknown_fields) { UnknownFieldSetFieldSkipper skipper(unknown_fields); return ParseMessageSet(input, containing_type, &skipper); } int ExtensionSet::SpaceUsedExcludingSelf() const { int total_size = extensions_.size() * sizeof(map::value_type); for (map::const_iterator iter = extensions_.begin(), end = extensions_.end(); iter != end; ++iter) { total_size += iter->second.SpaceUsedExcludingSelf(); } return total_size; } inline int ExtensionSet::RepeatedMessage_SpaceUsedExcludingSelf( RepeatedPtrFieldBase* field) { return field->SpaceUsedExcludingSelf >(); } int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { int total_size = 0; if (is_repeated) { switch (cpp_type(type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ case WireFormatLite::CPPTYPE_##UPPERCASE: \ total_size += sizeof(*repeated_##LOWERCASE##_value) + \ repeated_##LOWERCASE##_value->SpaceUsedExcludingSelf();\ break HANDLE_TYPE( INT32, int32); HANDLE_TYPE( INT64, int64); HANDLE_TYPE( UINT32, uint32); HANDLE_TYPE( UINT64, uint64); HANDLE_TYPE( FLOAT, float); HANDLE_TYPE( DOUBLE, double); HANDLE_TYPE( BOOL, bool); HANDLE_TYPE( ENUM, enum); HANDLE_TYPE( STRING, string); case WireFormatLite::CPPTYPE_MESSAGE: // repeated_message_value is actually a RepeatedPtrField, // but MessageLite has no SpaceUsed(), so we must directly call // RepeatedPtrFieldBase::SpaceUsedExcludingSelf() with a different type // handler. total_size += sizeof(*repeated_message_value) + RepeatedMessage_SpaceUsedExcludingSelf(repeated_message_value); break; } } else { switch (cpp_type(type)) { case WireFormatLite::CPPTYPE_STRING: total_size += sizeof(*string_value) + StringSpaceUsedExcludingSelf(*string_value); break; case WireFormatLite::CPPTYPE_MESSAGE: total_size += down_cast(message_value)->SpaceUsed(); break; default: // No extra storage costs for primitive types. break; } } return total_size; } } // namespace internal } // namespace protobuf } // namespace google