Line data Source code
1 : // Protocol Buffers - Google's data interchange format
2 : // Copyright 2008 Google Inc. All rights reserved.
3 : // https://developers.google.com/protocol-buffers/
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 : #include <google/protobuf/compiler/cpp/cpp_map_field.h>
32 : #include <google/protobuf/compiler/cpp/cpp_helpers.h>
33 : #include <google/protobuf/io/printer.h>
34 : #include <google/protobuf/wire_format.h>
35 : #include <google/protobuf/stubs/strutil.h>
36 :
37 : namespace google {
38 : namespace protobuf {
39 : namespace compiler {
40 : namespace cpp {
41 :
42 246 : bool IsProto3Field(const FieldDescriptor* field_descriptor) {
43 246 : const FileDescriptor* file_descriptor = field_descriptor->file();
44 246 : return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
45 : }
46 :
47 984 : void SetMessageVariables(const FieldDescriptor* descriptor,
48 : map<string, string>* variables,
49 : const Options& options) {
50 123 : SetCommonFieldVariables(descriptor, variables, options);
51 369 : (*variables)["type"] = FieldMessageTypeName(descriptor);
52 492 : (*variables)["stream_writer"] = (*variables)["declared_type"] +
53 123 : (HasFastArraySerialization(descriptor->message_type()->file()) ?
54 : "MaybeToArray" :
55 : "");
56 246 : (*variables)["full_name"] = descriptor->full_name();
57 :
58 246 : const FieldDescriptor* key =
59 369 : descriptor->message_type()->FindFieldByName("key");
60 314 : const FieldDescriptor* val =
61 369 : descriptor->message_type()->FindFieldByName("value");
62 369 : (*variables)["key_cpp"] = PrimitiveTypeName(key->cpp_type());
63 246 : switch (val->cpp_type()) {
64 : case FieldDescriptor::CPPTYPE_MESSAGE:
65 102 : (*variables)["val_cpp"] = FieldMessageTypeName(val);
66 68 : (*variables)["wrapper"] = "EntryWrapper";
67 34 : break;
68 : case FieldDescriptor::CPPTYPE_ENUM:
69 36 : (*variables)["val_cpp"] = ClassName(val->enum_type(), false);
70 24 : (*variables)["wrapper"] = "EnumEntryWrapper";
71 12 : break;
72 : default:
73 154 : (*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type());
74 154 : (*variables)["wrapper"] = "EntryWrapper";
75 : }
76 246 : (*variables)["key_wire_type"] =
77 492 : "::google::protobuf::internal::WireFormatLite::TYPE_" +
78 : ToUpper(DeclaredTypeMethodName(key->type()));
79 246 : (*variables)["val_wire_type"] =
80 492 : "::google::protobuf::internal::WireFormatLite::TYPE_" +
81 : ToUpper(DeclaredTypeMethodName(val->type()));
82 369 : (*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
83 369 : (*variables)["number"] = SimpleItoa(descriptor->number());
84 369 : (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
85 :
86 246 : if (HasDescriptorMethods(descriptor->file())) {
87 162 : (*variables)["lite"] = "";
88 : } else {
89 84 : (*variables)["lite"] = "Lite";
90 : }
91 :
92 169 : if (!IsProto3Field(descriptor) &&
93 46 : val->type() == FieldDescriptor::TYPE_ENUM) {
94 10 : const EnumValueDescriptor* default_value = val->default_value_enum();
95 30 : (*variables)["default_enum_value"] = Int32ToString(default_value->number());
96 : } else {
97 226 : (*variables)["default_enum_value"] = "0";
98 : }
99 123 : }
100 :
101 123 : MapFieldGenerator::
102 : MapFieldGenerator(const FieldDescriptor* descriptor,
103 : const Options& options)
104 : : descriptor_(descriptor),
105 246 : dependent_field_(options.proto_h && IsFieldDependent(descriptor)) {
106 123 : SetMessageVariables(descriptor, &variables_, options);
107 123 : }
108 :
109 369 : MapFieldGenerator::~MapFieldGenerator() {}
110 :
111 123 : void MapFieldGenerator::
112 : GeneratePrivateMembers(io::Printer* printer) const {
113 : printer->Print(variables_,
114 : "typedef ::google::protobuf::internal::MapEntryLite<\n"
115 : " $key_cpp$, $val_cpp$,\n"
116 : " $key_wire_type$,\n"
117 : " $val_wire_type$,\n"
118 : " $default_enum_value$ >\n"
119 : " $map_classname$;\n"
120 : "::google::protobuf::internal::MapField$lite$<\n"
121 : " $key_cpp$, $val_cpp$,\n"
122 : " $key_wire_type$,\n"
123 : " $val_wire_type$,\n"
124 123 : " $default_enum_value$ > $name$_;\n");
125 123 : }
126 :
127 123 : void MapFieldGenerator::
128 : GenerateAccessorDeclarations(io::Printer* printer) const {
129 : printer->Print(variables_,
130 : "const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
131 : " $name$() const$deprecation$;\n"
132 : "::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
133 123 : " mutable_$name$()$deprecation$;\n");
134 123 : }
135 :
136 246 : void MapFieldGenerator::
137 : GenerateInlineAccessorDefinitions(io::Printer* printer,
138 : bool is_inline) const {
139 246 : map<string, string> variables(variables_);
140 492 : variables["inline"] = is_inline ? "inline" : "";
141 : printer->Print(variables,
142 : "$inline$ const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
143 : "$classname$::$name$() const {\n"
144 : " // @@protoc_insertion_point(field_map:$full_name$)\n"
145 : " return $name$_.GetMap();\n"
146 : "}\n"
147 : "$inline$ ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
148 : "$classname$::mutable_$name$() {\n"
149 : " // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
150 : " return $name$_.MutableMap();\n"
151 246 : "}\n");
152 246 : }
153 :
154 369 : void MapFieldGenerator::
155 : GenerateClearingCode(io::Printer* printer) const {
156 369 : map<string, string> variables(variables_);
157 1107 : variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : "";
158 369 : printer->Print(variables, "$this_message$$name$_.Clear();\n");
159 369 : }
160 :
161 123 : void MapFieldGenerator::
162 : GenerateMergingCode(io::Printer* printer) const {
163 123 : printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
164 123 : }
165 :
166 123 : void MapFieldGenerator::
167 : GenerateSwappingCode(io::Printer* printer) const {
168 123 : printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
169 123 : }
170 :
171 123 : void MapFieldGenerator::
172 : GenerateConstructorCode(io::Printer* printer) const {
173 246 : if (HasDescriptorMethods(descriptor_->file())) {
174 : printer->Print(variables_,
175 : "$name$_.SetAssignDescriptorCallback(\n"
176 : " protobuf_AssignDescriptorsOnce);\n"
177 : "$name$_.SetEntryDescriptor(\n"
178 81 : " &$type$_descriptor_);\n");
179 : }
180 123 : }
181 :
182 123 : void MapFieldGenerator::
183 : GenerateMergeFromCodedStream(io::Printer* printer) const {
184 282 : const FieldDescriptor* value_field =
185 379 : descriptor_->message_type()->FindFieldByName("value");
186 : printer->Print(variables_,
187 123 : "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n");
188 :
189 169 : if (IsProto3Field(descriptor_) ||
190 46 : value_field->type() != FieldDescriptor::TYPE_ENUM) {
191 : printer->Print(variables_,
192 : "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
193 113 : " input, entry.get()));\n");
194 226 : switch (value_field->cpp_type()) {
195 : case FieldDescriptor::CPPTYPE_MESSAGE:
196 : printer->Print(variables_,
197 : "(*mutable_$name$())[entry->key()].Swap("
198 34 : "entry->mutable_value());\n");
199 34 : break;
200 : case FieldDescriptor::CPPTYPE_ENUM:
201 : printer->Print(variables_,
202 : "(*mutable_$name$())[entry->key()] =\n"
203 2 : " static_cast<$val_cpp$>(*entry->mutable_value());\n");
204 2 : break;
205 : default:
206 : printer->Print(variables_,
207 77 : "(*mutable_$name$())[entry->key()] = *entry->mutable_value();\n");
208 77 : break;
209 : }
210 : } else {
211 : printer->Print(variables_,
212 : "{\n"
213 : " ::std::string data;\n"
214 : " DO_(::google::protobuf::internal::WireFormatLite::ReadString(input, &data));\n"
215 : " DO_(entry->ParseFromString(data));\n"
216 : " if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
217 : " (*mutable_$name$())[entry->key()] =\n"
218 : " static_cast<$val_cpp$>(*entry->mutable_value());\n"
219 10 : " } else {\n");
220 30 : if (HasDescriptorMethods(descriptor_->file())) {
221 : printer->Print(variables_,
222 : " mutable_unknown_fields()"
223 4 : "->AddLengthDelimited($number$, data);\n");
224 : } else {
225 : printer->Print(variables_,
226 : " unknown_fields_stream.WriteVarint32($tag$);\n"
227 : " unknown_fields_stream.WriteVarint32(data.size());\n"
228 6 : " unknown_fields_stream.WriteString(data);\n");
229 : }
230 :
231 :
232 : printer->Print(variables_,
233 : " }\n"
234 10 : "}\n");
235 : }
236 :
237 123 : const FieldDescriptor* key_field =
238 369 : descriptor_->message_type()->FindFieldByName("key");
239 123 : if (key_field->type() == FieldDescriptor::TYPE_STRING) {
240 : GenerateUtf8CheckCodeForString(
241 : key_field, true, variables_,
242 15 : "entry->key().data(), entry->key().length(),\n", printer);
243 : }
244 123 : if (value_field->type() == FieldDescriptor::TYPE_STRING) {
245 : GenerateUtf8CheckCodeForString(
246 : value_field, true, variables_,
247 : "entry->mutable_value()->data(),\n"
248 8 : "entry->mutable_value()->length(),\n", printer);
249 : }
250 :
251 : // If entry is allocated by arena, its desctructor should be avoided.
252 246 : if (SupportsArenas(descriptor_)) {
253 : printer->Print(variables_,
254 85 : "if (entry->GetArena() != NULL) entry.release();\n");
255 : }
256 123 : }
257 :
258 123 : void MapFieldGenerator::
259 : GenerateSerializeWithCachedSizes(io::Printer* printer) const {
260 : printer->Print(variables_,
261 : "{\n"
262 : " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
263 : " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
264 : " it = this->$name$().begin();\n"
265 123 : " it != this->$name$().end(); ++it) {\n");
266 :
267 : // If entry is allocated by arena, its desctructor should be avoided.
268 492 : if (SupportsArenas(descriptor_)) {
269 : printer->Print(variables_,
270 : " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
271 : " entry.release();\n"
272 85 : " }\n");
273 : }
274 :
275 : printer->Print(variables_,
276 : " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
277 : " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
278 123 : " $number$, *entry, output);\n");
279 :
280 123 : printer->Indent();
281 123 : printer->Indent();
282 :
283 123 : const FieldDescriptor* key_field =
284 369 : descriptor_->message_type()->FindFieldByName("key");
285 123 : const FieldDescriptor* value_field =
286 369 : descriptor_->message_type()->FindFieldByName("value");
287 123 : if (key_field->type() == FieldDescriptor::TYPE_STRING) {
288 : GenerateUtf8CheckCodeForString(
289 : key_field, false, variables_,
290 15 : "it->first.data(), it->first.length(),\n", printer);
291 : }
292 123 : if (value_field->type() == FieldDescriptor::TYPE_STRING) {
293 : GenerateUtf8CheckCodeForString(
294 : value_field, false, variables_,
295 8 : "it->second.data(), it->second.length(),\n", printer);
296 : }
297 :
298 123 : printer->Outdent();
299 123 : printer->Outdent();
300 :
301 : printer->Print(
302 123 : " }\n");
303 :
304 : // If entry is allocated by arena, its desctructor should be avoided.
305 246 : if (SupportsArenas(descriptor_)) {
306 : printer->Print(variables_,
307 : " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
308 : " entry.release();\n"
309 85 : " }\n");
310 : }
311 :
312 123 : printer->Print("}\n");
313 123 : }
314 :
315 81 : void MapFieldGenerator::
316 : GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
317 : printer->Print(variables_,
318 : "{\n"
319 : " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
320 : " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
321 : " it = this->$name$().begin();\n"
322 81 : " it != this->$name$().end(); ++it) {\n");
323 :
324 : // If entry is allocated by arena, its desctructor should be avoided.
325 324 : if (SupportsArenas(descriptor_)) {
326 : printer->Print(variables_,
327 : " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
328 : " entry.release();\n"
329 43 : " }\n");
330 : }
331 :
332 : printer->Print(variables_,
333 : " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
334 : " target = ::google::protobuf::internal::WireFormatLite::\n"
335 : " Write$declared_type$NoVirtualToArray(\n"
336 81 : " $number$, *entry, target);\n");
337 :
338 81 : printer->Indent();
339 81 : printer->Indent();
340 :
341 81 : const FieldDescriptor* key_field =
342 243 : descriptor_->message_type()->FindFieldByName("key");
343 81 : const FieldDescriptor* value_field =
344 243 : descriptor_->message_type()->FindFieldByName("value");
345 81 : if (key_field->type() == FieldDescriptor::TYPE_STRING) {
346 : GenerateUtf8CheckCodeForString(
347 : key_field, false, variables_,
348 13 : "it->first.data(), it->first.length(),\n", printer);
349 : }
350 81 : if (value_field->type() == FieldDescriptor::TYPE_STRING) {
351 : GenerateUtf8CheckCodeForString(
352 : value_field, false, variables_,
353 6 : "it->second.data(), it->second.length(),\n", printer);
354 : }
355 :
356 81 : printer->Outdent();
357 81 : printer->Outdent();
358 : printer->Print(
359 81 : " }\n");
360 :
361 : // If entry is allocated by arena, its desctructor should be avoided.
362 162 : if (SupportsArenas(descriptor_)) {
363 : printer->Print(variables_,
364 : " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
365 : " entry.release();\n"
366 43 : " }\n");
367 : }
368 :
369 81 : printer->Print("}\n");
370 81 : }
371 :
372 123 : void MapFieldGenerator::
373 : GenerateByteSize(io::Printer* printer) const {
374 : printer->Print(variables_,
375 : "total_size += $tag_size$ * this->$name$_size();\n"
376 : "{\n"
377 : " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
378 : " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
379 : " it = this->$name$().begin();\n"
380 123 : " it != this->$name$().end(); ++it) {\n");
381 :
382 : // If entry is allocated by arena, its desctructor should be avoided.
383 246 : if (SupportsArenas(descriptor_)) {
384 : printer->Print(variables_,
385 : " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
386 : " entry.release();\n"
387 85 : " }\n");
388 : }
389 :
390 : printer->Print(variables_,
391 : " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
392 : " total_size += ::google::protobuf::internal::WireFormatLite::\n"
393 : " $declared_type$SizeNoVirtual(*entry);\n"
394 123 : " }\n");
395 :
396 : // If entry is allocated by arena, its desctructor should be avoided.
397 246 : if (SupportsArenas(descriptor_)) {
398 : printer->Print(variables_,
399 : " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
400 : " entry.release();\n"
401 85 : " }\n");
402 : }
403 :
404 123 : printer->Print("}\n");
405 123 : }
406 :
407 : } // namespace cpp
408 : } // namespace compiler
409 : } // namespace protobuf
410 : } // namespace google
|