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