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