• 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 
33 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
34 #include <google/protobuf/io/printer.h>
35 #include <google/protobuf/wire_format.h>
36 #include <google/protobuf/stubs/strutil.h>
37 
38 
39 namespace google {
40 namespace protobuf {
41 namespace compiler {
42 namespace cpp {
43 
IsProto3Field(const FieldDescriptor * field_descriptor)44 bool IsProto3Field(const FieldDescriptor* field_descriptor) {
45   const FileDescriptor* file_descriptor = field_descriptor->file();
46   return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
47 }
48 
SetMessageVariables(const FieldDescriptor * descriptor,std::map<std::string,std::string> * variables,const Options & options)49 void SetMessageVariables(const FieldDescriptor* descriptor,
50                          std::map<std::string, std::string>* variables,
51                          const Options& options) {
52   SetCommonFieldVariables(descriptor, variables, options);
53   (*variables)["type"] = ClassName(descriptor->message_type(), false);
54   (*variables)["full_name"] = descriptor->full_name();
55 
56   const FieldDescriptor* key =
57       descriptor->message_type()->FindFieldByName("key");
58   const FieldDescriptor* val =
59       descriptor->message_type()->FindFieldByName("value");
60   (*variables)["key_cpp"] = PrimitiveTypeName(options, key->cpp_type());
61   switch (val->cpp_type()) {
62     case FieldDescriptor::CPPTYPE_MESSAGE:
63       (*variables)["val_cpp"] = FieldMessageTypeName(val, options);
64       break;
65     case FieldDescriptor::CPPTYPE_ENUM:
66       (*variables)["val_cpp"] = ClassName(val->enum_type(), true);
67       break;
68     default:
69       (*variables)["val_cpp"] = PrimitiveTypeName(options, val->cpp_type());
70   }
71   (*variables)["key_wire_type"] =
72       "TYPE_" + ToUpper(DeclaredTypeMethodName(key->type()));
73   (*variables)["val_wire_type"] =
74       "TYPE_" + ToUpper(DeclaredTypeMethodName(val->type()));
75   (*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
76   (*variables)["number"] = StrCat(descriptor->number());
77   (*variables)["tag"] = StrCat(internal::WireFormat::MakeTag(descriptor));
78 
79   if (HasDescriptorMethods(descriptor->file(), options)) {
80     (*variables)["lite"] = "";
81   } else {
82     (*variables)["lite"] = "Lite";
83   }
84 }
85 
MapFieldGenerator(const FieldDescriptor * descriptor,const Options & options)86 MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
87                                      const Options& options)
88     : FieldGenerator(descriptor, options) {
89   SetMessageVariables(descriptor, &variables_, options);
90 }
91 
~MapFieldGenerator()92 MapFieldGenerator::~MapFieldGenerator() {}
93 
GeneratePrivateMembers(io::Printer * printer) const94 void MapFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
95   Formatter format(printer, variables_);
96   format(
97       "::$proto_ns$::internal::MapField$lite$<\n"
98       "    $map_classname$,\n"
99       "    $key_cpp$, $val_cpp$,\n"
100       "    ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n"
101       "    ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> "
102       "$name$_;\n");
103 }
104 
GenerateAccessorDeclarations(io::Printer * printer) const105 void MapFieldGenerator::GenerateAccessorDeclarations(
106     io::Printer* printer) const {
107   Formatter format(printer, variables_);
108   format(
109       "private:\n"
110       "const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
111       "    ${1$_internal_$name$$}$() const;\n"
112       "::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
113       "    ${1$_internal_mutable_$name$$}$();\n"
114       "public:\n"
115       "$deprecated_attr$const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
116       "    ${1$$name$$}$() const;\n"
117       "$deprecated_attr$::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
118       "    ${1$mutable_$name$$}$();\n",
119       descriptor_);
120 }
121 
GenerateInlineAccessorDefinitions(io::Printer * printer) const122 void MapFieldGenerator::GenerateInlineAccessorDefinitions(
123     io::Printer* printer) const {
124   Formatter format(printer, variables_);
125   format(
126       "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
127       "$classname$::_internal_$name$() const {\n"
128       "  return $name$_.GetMap();\n"
129       "}\n"
130       "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
131       "$classname$::$name$() const {\n"
132       "$annotate_accessor$"
133       "  // @@protoc_insertion_point(field_map:$full_name$)\n"
134       "  return _internal_$name$();\n"
135       "}\n"
136       "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
137       "$classname$::_internal_mutable_$name$() {\n"
138       "  return $name$_.MutableMap();\n"
139       "}\n"
140       "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
141       "$classname$::mutable_$name$() {\n"
142       "$annotate_accessor$"
143       "  // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
144       "  return _internal_mutable_$name$();\n"
145       "}\n");
146 }
147 
GenerateClearingCode(io::Printer * printer) const148 void MapFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
149   Formatter format(printer, variables_);
150   format("$name$_.Clear();\n");
151 }
152 
GenerateMergingCode(io::Printer * printer) const153 void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
154   Formatter format(printer, variables_);
155   format("$name$_.MergeFrom(from.$name$_);\n");
156 }
157 
GenerateSwappingCode(io::Printer * printer) const158 void MapFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
159   Formatter format(printer, variables_);
160   format("$name$_.Swap(&other->$name$_);\n");
161 }
162 
GenerateCopyConstructorCode(io::Printer * printer) const163 void MapFieldGenerator::GenerateCopyConstructorCode(
164     io::Printer* printer) const {
165   GenerateConstructorCode(printer);
166   GenerateMergingCode(printer);
167 }
168 
GenerateSerializationLoop(const Formatter & format,bool string_key,bool string_value,bool is_deterministic)169 static void GenerateSerializationLoop(const Formatter& format, bool string_key,
170                                       bool string_value,
171                                       bool is_deterministic) {
172   std::string ptr;
173   if (is_deterministic) {
174     format("for (size_type i = 0; i < n; i++) {\n");
175     ptr = string_key ? "items[static_cast<ptrdiff_t>(i)]"
176                      : "items[static_cast<ptrdiff_t>(i)].second";
177   } else {
178     format(
179         "for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
180         "    it = this->_internal_$name$().begin();\n"
181         "    it != this->_internal_$name$().end(); ++it) {\n");
182     ptr = "it";
183   }
184   format.Indent();
185 
186   format(
187       "target = $map_classname$::Funcs::InternalSerialize($number$, "
188       "$1$->first, $1$->second, target, stream);\n",
189       ptr);
190 
191   if (string_key || string_value) {
192     // ptr is either an actual pointer or an iterator, either way we can
193     // create a pointer by taking the address after de-referencing it.
194     format("Utf8Check::Check(&(*$1$));\n", ptr);
195   }
196 
197   format.Outdent();
198   format("}\n");
199 }
200 
GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const201 void MapFieldGenerator::GenerateSerializeWithCachedSizesToArray(
202     io::Printer* printer) const {
203   Formatter format(printer, variables_);
204   format("if (!this->_internal_$name$().empty()) {\n");
205   format.Indent();
206   const FieldDescriptor* key_field =
207       descriptor_->message_type()->FindFieldByName("key");
208   const FieldDescriptor* value_field =
209       descriptor_->message_type()->FindFieldByName("value");
210   const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING;
211   const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING;
212 
213   format(
214       "typedef ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_pointer\n"
215       "    ConstPtr;\n");
216   if (string_key) {
217     format(
218         "typedef ConstPtr SortItem;\n"
219         "typedef ::$proto_ns$::internal::"
220         "CompareByDerefFirst<SortItem> Less;\n");
221   } else {
222     format(
223         "typedef ::$proto_ns$::internal::SortItem< $key_cpp$, ConstPtr > "
224         "SortItem;\n"
225         "typedef ::$proto_ns$::internal::CompareByFirstField<SortItem> "
226         "Less;\n");
227   }
228   bool utf8_check = string_key || string_value;
229   if (utf8_check) {
230     format(
231         "struct Utf8Check {\n"
232         "  static void Check(ConstPtr p) {\n");
233     format.Indent();
234     format.Indent();
235     if (string_key) {
236       GenerateUtf8CheckCodeForString(
237           key_field, options_, false,
238           "p->first.data(), static_cast<int>(p->first.length()),\n", format);
239     }
240     if (string_value) {
241       GenerateUtf8CheckCodeForString(
242           value_field, options_, false,
243           "p->second.data(), static_cast<int>(p->second.length()),\n", format);
244     }
245     format.Outdent();
246     format.Outdent();
247     format(
248         "  }\n"
249         "};\n");
250   }
251 
252   format(
253       "\n"
254       "if (stream->IsSerializationDeterministic() &&\n"
255       "    this->_internal_$name$().size() > 1) {\n"
256       "  ::std::unique_ptr<SortItem[]> items(\n"
257       "      new SortItem[this->_internal_$name$().size()]);\n"
258       "  typedef ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::size_type "
259       "size_type;\n"
260       "  size_type n = 0;\n"
261       "  for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
262       "      it = this->_internal_$name$().begin();\n"
263       "      it != this->_internal_$name$().end(); ++it, ++n) {\n"
264       "    items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);\n"
265       "  }\n"
266       "  ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n");
267   format.Indent();
268   GenerateSerializationLoop(format, string_key, string_value, true);
269   format.Outdent();
270   format("} else {\n");
271   format.Indent();
272   GenerateSerializationLoop(format, string_key, string_value, false);
273   format.Outdent();
274   format("}\n");
275   format.Outdent();
276   format("}\n");
277 }
278 
GenerateByteSize(io::Printer * printer) const279 void MapFieldGenerator::GenerateByteSize(io::Printer* printer) const {
280   Formatter format(printer, variables_);
281   format(
282       "total_size += $tag_size$ *\n"
283       "    "
284       "::$proto_ns$::internal::FromIntSize(this->_internal_$name$_size());\n"
285       "for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
286       "    it = this->_internal_$name$().begin();\n"
287       "    it != this->_internal_$name$().end(); ++it) {\n"
288       "  total_size += $map_classname$::Funcs::ByteSizeLong(it->first, "
289       "it->second);\n"
290       "}\n");
291 }
292 
293 }  // namespace cpp
294 }  // namespace compiler
295 }  // namespace protobuf
296 }  // namespace google
297