• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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