• 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