• 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   if (!IsProto3Field(descriptor) && val->type() == FieldDescriptor::TYPE_ENUM) {
86     const EnumValueDescriptor* default_value = val->default_value_enum();
87     (*variables)["default_enum_value"] = Int32ToString(default_value->number());
88   } else {
89     (*variables)["default_enum_value"] = "0";
90   }
91 }
92 
MapFieldGenerator(const FieldDescriptor * descriptor,const Options & options)93 MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
94                                      const Options& options)
95     : FieldGenerator(descriptor, options) {
96   SetMessageVariables(descriptor, &variables_, options);
97 }
98 
~MapFieldGenerator()99 MapFieldGenerator::~MapFieldGenerator() {}
100 
GeneratePrivateMembers(io::Printer * printer) const101 void MapFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
102   Formatter format(printer, variables_);
103   format(
104       "::$proto_ns$::internal::MapField$lite$<\n"
105       "    $map_classname$,\n"
106       "    $key_cpp$, $val_cpp$,\n"
107       "    ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n"
108       "    ::$proto_ns$::internal::WireFormatLite::$val_wire_type$,\n"
109       "    $default_enum_value$ > $name$_;\n");
110 }
111 
GenerateAccessorDeclarations(io::Printer * printer) const112 void MapFieldGenerator::GenerateAccessorDeclarations(
113     io::Printer* printer) const {
114   Formatter format(printer, variables_);
115   format(
116       "private:\n"
117       "const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
118       "    ${1$_internal_$name$$}$() const;\n"
119       "::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
120       "    ${1$_internal_mutable_$name$$}$();\n"
121       "public:\n"
122       "$deprecated_attr$const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
123       "    ${1$$name$$}$() const;\n"
124       "$deprecated_attr$::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
125       "    ${1$mutable_$name$$}$();\n",
126       descriptor_);
127 }
128 
GenerateInlineAccessorDefinitions(io::Printer * printer) const129 void MapFieldGenerator::GenerateInlineAccessorDefinitions(
130     io::Printer* printer) const {
131   Formatter format(printer, variables_);
132   format(
133       "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
134       "$classname$::_internal_$name$() const {\n"
135       "  return $name$_.GetMap();\n"
136       "}\n"
137       "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
138       "$classname$::$name$() const {\n"
139       "$annotate_accessor$"
140       "  // @@protoc_insertion_point(field_map:$full_name$)\n"
141       "  return _internal_$name$();\n"
142       "}\n"
143       "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
144       "$classname$::_internal_mutable_$name$() {\n"
145       "  return $name$_.MutableMap();\n"
146       "}\n"
147       "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
148       "$classname$::mutable_$name$() {\n"
149       "$annotate_accessor$"
150       "  // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
151       "  return _internal_mutable_$name$();\n"
152       "}\n");
153 }
154 
GenerateClearingCode(io::Printer * printer) const155 void MapFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
156   Formatter format(printer, variables_);
157   format("$name$_.Clear();\n");
158 }
159 
GenerateMergingCode(io::Printer * printer) const160 void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
161   Formatter format(printer, variables_);
162   format("$name$_.MergeFrom(from.$name$_);\n");
163 }
164 
GenerateSwappingCode(io::Printer * printer) const165 void MapFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
166   Formatter format(printer, variables_);
167   format("$name$_.Swap(&other->$name$_);\n");
168 }
169 
GenerateCopyConstructorCode(io::Printer * printer) const170 void MapFieldGenerator::GenerateCopyConstructorCode(
171     io::Printer* printer) const {
172   GenerateConstructorCode(printer);
173   GenerateMergingCode(printer);
174 }
175 
GenerateSerializationLoop(const Formatter & format,bool string_key,bool string_value,bool is_deterministic)176 static void GenerateSerializationLoop(const Formatter& format, bool string_key,
177                                       bool string_value,
178                                       bool is_deterministic) {
179   std::string ptr;
180   if (is_deterministic) {
181     format("for (size_type i = 0; i < n; i++) {\n");
182     ptr = string_key ? "items[static_cast<ptrdiff_t>(i)]"
183                      : "items[static_cast<ptrdiff_t>(i)].second";
184   } else {
185     format(
186         "for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
187         "    it = this->_internal_$name$().begin();\n"
188         "    it != this->_internal_$name$().end(); ++it) {\n");
189     ptr = "it";
190   }
191   format.Indent();
192 
193   format(
194       "target = $map_classname$::Funcs::InternalSerialize($number$, "
195       "$1$->first, $1$->second, target, stream);\n",
196       ptr);
197 
198   if (string_key || string_value) {
199     // ptr is either an actual pointer or an iterator, either way we can
200     // create a pointer by taking the address after de-referencing it.
201     format("Utf8Check::Check(&(*$1$));\n", ptr);
202   }
203 
204   format.Outdent();
205   format("}\n");
206 }
207 
GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const208 void MapFieldGenerator::GenerateSerializeWithCachedSizesToArray(
209     io::Printer* printer) const {
210   Formatter format(printer, variables_);
211   format("if (!this->_internal_$name$().empty()) {\n");
212   format.Indent();
213   const FieldDescriptor* key_field =
214       descriptor_->message_type()->FindFieldByName("key");
215   const FieldDescriptor* value_field =
216       descriptor_->message_type()->FindFieldByName("value");
217   const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING;
218   const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING;
219 
220   format(
221       "typedef ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_pointer\n"
222       "    ConstPtr;\n");
223   if (string_key) {
224     format(
225         "typedef ConstPtr SortItem;\n"
226         "typedef ::$proto_ns$::internal::"
227         "CompareByDerefFirst<SortItem> Less;\n");
228   } else {
229     format(
230         "typedef ::$proto_ns$::internal::SortItem< $key_cpp$, ConstPtr > "
231         "SortItem;\n"
232         "typedef ::$proto_ns$::internal::CompareByFirstField<SortItem> "
233         "Less;\n");
234   }
235   bool utf8_check = string_key || string_value;
236   if (utf8_check) {
237     format(
238         "struct Utf8Check {\n"
239         "  static void Check(ConstPtr p) {\n");
240     format.Indent();
241     format.Indent();
242     if (string_key) {
243       GenerateUtf8CheckCodeForString(
244           key_field, options_, false,
245           "p->first.data(), static_cast<int>(p->first.length()),\n", format);
246     }
247     if (string_value) {
248       GenerateUtf8CheckCodeForString(
249           value_field, options_, false,
250           "p->second.data(), static_cast<int>(p->second.length()),\n", format);
251     }
252     format.Outdent();
253     format.Outdent();
254     format(
255         "  }\n"
256         "};\n");
257   }
258 
259   format(
260       "\n"
261       "if (stream->IsSerializationDeterministic() &&\n"
262       "    this->_internal_$name$().size() > 1) {\n"
263       "  ::std::unique_ptr<SortItem[]> items(\n"
264       "      new SortItem[this->_internal_$name$().size()]);\n"
265       "  typedef ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::size_type "
266       "size_type;\n"
267       "  size_type n = 0;\n"
268       "  for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
269       "      it = this->_internal_$name$().begin();\n"
270       "      it != this->_internal_$name$().end(); ++it, ++n) {\n"
271       "    items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);\n"
272       "  }\n"
273       "  ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n");
274   format.Indent();
275   GenerateSerializationLoop(format, string_key, string_value, true);
276   format.Outdent();
277   format("} else {\n");
278   format.Indent();
279   GenerateSerializationLoop(format, string_key, string_value, false);
280   format.Outdent();
281   format("}\n");
282   format.Outdent();
283   format("}\n");
284 }
285 
GenerateByteSize(io::Printer * printer) const286 void MapFieldGenerator::GenerateByteSize(io::Printer* printer) const {
287   Formatter format(printer, variables_);
288   format(
289       "total_size += $tag_size$ *\n"
290       "    "
291       "::$proto_ns$::internal::FromIntSize(this->_internal_$name$_size());\n"
292       "for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
293       "    it = this->_internal_$name$().begin();\n"
294       "    it != this->_internal_$name$().end(); ++it) {\n"
295       "  total_size += $map_classname$::Funcs::ByteSizeLong(it->first, "
296       "it->second);\n"
297       "}\n");
298 }
299 
300 }  // namespace cpp
301 }  // namespace compiler
302 }  // namespace protobuf
303 }  // namespace google
304