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