extension_set_heavy.cc revision fbaaef999ba563838ebd00874ed8a1c01fbf286d
1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// http://code.google.com/p/protobuf/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31// Author: kenton@google.com (Kenton Varda) 32// Based on original Protocol Buffers design by 33// Sanjay Ghemawat, Jeff Dean, and others. 34// 35// Contains methods defined in extension_set.h which cannot be part of the 36// lite library because they use descriptors or reflection. 37 38#include <google/protobuf/extension_set.h> 39#include <google/protobuf/descriptor.h> 40#include <google/protobuf/message.h> 41#include <google/protobuf/repeated_field.h> 42#include <google/protobuf/wire_format.h> 43 44namespace google { 45namespace protobuf { 46namespace internal { 47 48void ExtensionSet::AppendToList(const Descriptor* containing_type, 49 const DescriptorPool* pool, 50 vector<const FieldDescriptor*>* output) const { 51 for (map<int, Extension>::const_iterator iter = extensions_.begin(); 52 iter != extensions_.end(); ++iter) { 53 bool has = false; 54 if (iter->second.is_repeated) { 55 has = iter->second.GetSize() > 0; 56 } else { 57 has = !iter->second.is_cleared; 58 } 59 60 if (has) { 61 output->push_back( 62 pool->FindExtensionByNumber(containing_type, iter->first)); 63 } 64 } 65} 66 67inline FieldDescriptor::CppType cpp_type(FieldType type) { 68 return FieldDescriptor::TypeToCppType( 69 static_cast<FieldDescriptor::Type>(type)); 70} 71 72#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \ 73 GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \ 74 : FieldDescriptor::LABEL_OPTIONAL, \ 75 FieldDescriptor::LABEL_##LABEL); \ 76 GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE) 77 78const MessageLite& ExtensionSet::GetMessage(int number, 79 const Descriptor* message_type, 80 MessageFactory* factory) const { 81 map<int, Extension>::const_iterator iter = extensions_.find(number); 82 if (iter == extensions_.end() || iter->second.is_cleared) { 83 // Not present. Return the default value. 84 return *factory->GetPrototype(message_type); 85 } else { 86 GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE); 87 return *iter->second.message_value; 88 } 89} 90 91MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, 92 const Descriptor* message_type, 93 MessageFactory* factory) { 94 Extension* extension; 95 if (MaybeNewExtension(number, &extension)) { 96 extension->type = type; 97 GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); 98 extension->is_repeated = false; 99 extension->is_packed = false; 100 const MessageLite* prototype = factory->GetPrototype(message_type); 101 GOOGLE_CHECK(prototype != NULL); 102 extension->message_value = prototype->New(); 103 } else { 104 GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); 105 } 106 extension->is_cleared = false; 107 return extension->message_value; 108} 109 110MessageLite* ExtensionSet::AddMessage(int number, FieldType type, 111 const Descriptor* message_type, 112 MessageFactory* factory) { 113 Extension* extension; 114 if (MaybeNewExtension(number, &extension)) { 115 extension->type = type; 116 GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); 117 extension->is_repeated = true; 118 extension->repeated_message_value = 119 new RepeatedPtrField<MessageLite>(); 120 } else { 121 GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); 122 } 123 124 // RepeatedPtrField<Message> does not know how to Add() since it cannot 125 // allocate an abstract object, so we have to be tricky. 126 MessageLite* result = extension->repeated_message_value 127 ->AddFromCleared<internal::GenericTypeHandler<MessageLite> >(); 128 if (result == NULL) { 129 const MessageLite* prototype; 130 if (extension->repeated_message_value->size() == 0) { 131 prototype = factory->GetPrototype(message_type); 132 GOOGLE_CHECK(prototype != NULL); 133 } else { 134 prototype = &extension->repeated_message_value->Get(0); 135 } 136 result = prototype->New(); 137 extension->repeated_message_value->AddAllocated(result); 138 } 139 return result; 140} 141 142bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, 143 const MessageLite* containing_type, 144 UnknownFieldSet* unknown_fields) { 145 UnknownFieldSetFieldSkipper skipper(unknown_fields); 146 return ParseField(tag, input, containing_type, &skipper); 147} 148 149bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, 150 const MessageLite* containing_type, 151 UnknownFieldSet* unknown_fields) { 152 UnknownFieldSetFieldSkipper skipper(unknown_fields); 153 return ParseMessageSet(input, containing_type, &skipper); 154} 155 156int ExtensionSet::SpaceUsedExcludingSelf() const { 157 int total_size = 158 extensions_.size() * sizeof(map<int, Extension>::value_type); 159 for (map<int, Extension>::const_iterator iter = extensions_.begin(), 160 end = extensions_.end(); 161 iter != end; 162 ++iter) { 163 total_size += iter->second.SpaceUsedExcludingSelf(); 164 } 165 return total_size; 166} 167 168inline int ExtensionSet::RepeatedMessage_SpaceUsedExcludingSelf( 169 RepeatedPtrFieldBase* field) { 170 return field->SpaceUsedExcludingSelf<GenericTypeHandler<Message> >(); 171} 172 173int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { 174 int total_size = 0; 175 if (is_repeated) { 176 switch (cpp_type(type)) { 177#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ 178 case WireFormatLite::CPPTYPE_##UPPERCASE: \ 179 total_size += sizeof(*repeated_##LOWERCASE##_value) + \ 180 repeated_##LOWERCASE##_value->SpaceUsedExcludingSelf();\ 181 break 182 183 HANDLE_TYPE( INT32, int32); 184 HANDLE_TYPE( INT64, int64); 185 HANDLE_TYPE( UINT32, uint32); 186 HANDLE_TYPE( UINT64, uint64); 187 HANDLE_TYPE( FLOAT, float); 188 HANDLE_TYPE( DOUBLE, double); 189 HANDLE_TYPE( BOOL, bool); 190 HANDLE_TYPE( ENUM, enum); 191 HANDLE_TYPE( STRING, string); 192 193 case WireFormatLite::CPPTYPE_MESSAGE: 194 // repeated_message_value is actually a RepeatedPtrField<MessageLite>, 195 // but MessageLite has no SpaceUsed(), so we must directly call 196 // RepeatedPtrFieldBase::SpaceUsedExcludingSelf() with a different type 197 // handler. 198 total_size += sizeof(*repeated_message_value) + 199 RepeatedMessage_SpaceUsedExcludingSelf(repeated_message_value); 200 break; 201 } 202 } else { 203 switch (cpp_type(type)) { 204 case WireFormatLite::CPPTYPE_STRING: 205 total_size += sizeof(*string_value) + 206 StringSpaceUsedExcludingSelf(*string_value); 207 break; 208 case WireFormatLite::CPPTYPE_MESSAGE: 209 total_size += down_cast<Message*>(message_value)->SpaceUsed(); 210 break; 211 default: 212 // No extra storage costs for primitive types. 213 break; 214 } 215 } 216 return total_size; 217} 218 219} // namespace internal 220} // namespace protobuf 221} // namespace google 222