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