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/map_field.h>
32
33#include <google/protobuf/io/printer.h>
34#include <google/protobuf/wire_format.h>
35#include <google/protobuf/stubs/strutil.h>
36#include <google/protobuf/compiler/cpp/helpers.h>
37
38
39namespace google {
40namespace protobuf {
41namespace compiler {
42namespace cpp {
43
44bool IsProto3Field(const FieldDescriptor* field_descriptor) {
45 const FileDescriptor* file_descriptor = field_descriptor->file();
46 return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
47}
48
49void 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: descriptor->message_type(), qualified: false);
54 (*variables)["full_name"] = descriptor->full_name();
55
56 const FieldDescriptor* key = descriptor->message_type()->map_key();
57 const FieldDescriptor* val = descriptor->message_type()->map_value();
58 (*variables)["key_cpp"] = PrimitiveTypeName(options, type: key->cpp_type());
59 switch (val->cpp_type()) {
60 case FieldDescriptor::CPPTYPE_MESSAGE:
61 (*variables)["val_cpp"] = FieldMessageTypeName(field: val, options);
62 break;
63 case FieldDescriptor::CPPTYPE_ENUM:
64 (*variables)["val_cpp"] = ClassName(descriptor: val->enum_type(), qualified: true);
65 break;
66 default:
67 (*variables)["val_cpp"] = PrimitiveTypeName(options, type: val->cpp_type());
68 }
69 (*variables)["key_wire_type"] =
70 "TYPE_" + ToUpper(s: DeclaredTypeMethodName(type: key->type()));
71 (*variables)["val_wire_type"] =
72 "TYPE_" + ToUpper(s: DeclaredTypeMethodName(type: val->type()));
73 (*variables)["map_classname"] = ClassName(descriptor: descriptor->message_type(), qualified: false);
74 (*variables)["number"] = StrCat(a: descriptor->number());
75 (*variables)["tag"] = StrCat(a: internal::WireFormat::MakeTag(field: descriptor));
76
77 if (HasDescriptorMethods(file: descriptor->file(), options)) {
78 (*variables)["lite"] = "";
79 } else {
80 (*variables)["lite"] = "Lite";
81 }
82}
83
84MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
85 const Options& options,
86 MessageSCCAnalyzer* scc_analyzer)
87 : FieldGenerator(descriptor, options),
88 has_required_fields_(
89 scc_analyzer->HasRequiredFields(descriptor: descriptor->message_type())) {
90 SetMessageVariables(descriptor, variables: &variables_, options);
91}
92
93MapFieldGenerator::~MapFieldGenerator() {}
94
95void MapFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
96 Formatter format(printer, variables_);
97 format(
98 "::$proto_ns$::internal::MapField$lite$<\n"
99 " $map_classname$,\n"
100 " $key_cpp$, $val_cpp$,\n"
101 " ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n"
102 " ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> "
103 "$name$_;\n");
104}
105
106void MapFieldGenerator::GenerateAccessorDeclarations(
107 io::Printer* printer) const {
108 Formatter format(printer, variables_);
109 format(
110 "private:\n"
111 "const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
112 " ${1$_internal_$name$$}$() const;\n"
113 "::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
114 " ${1$_internal_mutable_$name$$}$();\n"
115 "public:\n"
116 "$deprecated_attr$const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
117 " ${1$$name$$}$() const;\n"
118 "$deprecated_attr$::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
119 " ${1$mutable_$name$$}$();\n",
120 descriptor_);
121}
122
123void MapFieldGenerator::GenerateInlineAccessorDefinitions(
124 io::Printer* printer) const {
125 Formatter format(printer, variables_);
126 format(
127 "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
128 "$classname$::_internal_$name$() const {\n"
129 " return $field$.GetMap();\n"
130 "}\n"
131 "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
132 "$classname$::$name$() const {\n"
133 "$annotate_get$"
134 " // @@protoc_insertion_point(field_map:$full_name$)\n"
135 " return _internal_$name$();\n"
136 "}\n"
137 "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
138 "$classname$::_internal_mutable_$name$() {\n"
139 "$maybe_prepare_split_message$"
140 " return $field$.MutableMap();\n"
141 "}\n"
142 "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
143 "$classname$::mutable_$name$() {\n"
144 "$annotate_mutable$"
145 " // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
146 " return _internal_mutable_$name$();\n"
147 "}\n");
148}
149
150void MapFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
151 Formatter format(printer, variables_);
152 format("$field$.Clear();\n");
153}
154
155void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
156 Formatter format(printer, variables_);
157 format("_this->$field$.MergeFrom(from.$field$);\n");
158}
159
160void MapFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
161 Formatter format(printer, variables_);
162 format("$field$.InternalSwap(&other->$field$);\n");
163}
164
165void MapFieldGenerator::GenerateCopyConstructorCode(
166 io::Printer* printer) const {
167 GenerateConstructorCode(printer);
168 GenerateMergingCode(printer);
169}
170
171static void GenerateSerializationLoop(Formatter& format, bool string_key,
172 bool string_value,
173 bool is_deterministic) {
174 if (is_deterministic) {
175 format(
176 "for (const auto& entry : "
177 "::_pbi::MapSorter$1$<MapType>(map_field)) {\n",
178 (string_key ? "Ptr" : "Flat"));
179 } else {
180 format("for (const auto& entry : map_field) {\n");
181 }
182 {
183 auto loop_scope = format.ScopedIndent();
184 format(
185 "target = WireHelper::InternalSerialize($number$, "
186 "entry.first, entry.second, target, stream);\n");
187
188 if (string_key || string_value) {
189 format("check_utf8(entry);\n");
190 }
191 }
192 format("}\n");
193}
194
195void MapFieldGenerator::GenerateSerializeWithCachedSizesToArray(
196 io::Printer* printer) const {
197 Formatter format(printer, variables_);
198 format("if (!this->_internal_$name$().empty()) {\n");
199 format.Indent();
200 const FieldDescriptor* key_field = descriptor_->message_type()->map_key();
201 const FieldDescriptor* value_field = descriptor_->message_type()->map_value();
202 const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING;
203 const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING;
204
205 format(
206 "using MapType = ::_pb::Map<$key_cpp$, $val_cpp$>;\n"
207 "using WireHelper = $map_classname$::Funcs;\n"
208 "const auto& map_field = this->_internal_$name$();\n");
209 bool utf8_check = string_key || string_value;
210 if (utf8_check) {
211 format("auto check_utf8 = [](const MapType::value_type& entry) {\n");
212 {
213 auto check_scope = format.ScopedIndent();
214 // p may be unused when GetUtf8CheckMode evaluates to kNone,
215 // thus disabling the validation.
216 format("(void)entry;\n");
217 if (string_key) {
218 GenerateUtf8CheckCodeForString(
219 field: key_field, options: options_, for_parse: false,
220 parameters: "entry.first.data(), static_cast<int>(entry.first.length()),\n",
221 format);
222 }
223 if (string_value) {
224 GenerateUtf8CheckCodeForString(
225 field: value_field, options: options_, for_parse: false,
226 parameters: "entry.second.data(), static_cast<int>(entry.second.length()),\n",
227 format);
228 }
229 }
230 format("};\n");
231 }
232
233 format(
234 "\n"
235 "if (stream->IsSerializationDeterministic() && "
236 "map_field.size() > 1) {\n");
237 {
238 auto deterministic_scope = format.ScopedIndent();
239 GenerateSerializationLoop(format, string_key, string_value, is_deterministic: true);
240 }
241 format("} else {\n");
242 {
243 auto map_order_scope = format.ScopedIndent();
244 GenerateSerializationLoop(format, string_key, string_value, is_deterministic: false);
245 }
246 format("}\n");
247 format.Outdent();
248 format("}\n");
249}
250
251void MapFieldGenerator::GenerateByteSize(io::Printer* printer) const {
252 Formatter format(printer, variables_);
253 format(
254 "total_size += $tag_size$ *\n"
255 " "
256 "::$proto_ns$::internal::FromIntSize(this->_internal_$name$_size());\n"
257 "for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
258 " it = this->_internal_$name$().begin();\n"
259 " it != this->_internal_$name$().end(); ++it) {\n"
260 " total_size += $map_classname$::Funcs::ByteSizeLong(it->first, "
261 "it->second);\n"
262 "}\n");
263}
264
265void MapFieldGenerator::GenerateIsInitialized(io::Printer* printer) const {
266 if (!has_required_fields_) return;
267
268 Formatter format(printer, variables_);
269 format(
270 "if (!::$proto_ns$::internal::AllAreInitialized($field$)) return "
271 "false;\n");
272}
273
274void MapFieldGenerator::GenerateConstexprAggregateInitializer(
275 io::Printer* printer) const {
276 Formatter format(printer, variables_);
277 if (HasDescriptorMethods(file: descriptor_->file(), options: options_)) {
278 format("/*decltype($field$)*/{::_pbi::ConstantInitialized()}");
279 } else {
280 format("/*decltype($field$)*/{}");
281 }
282}
283
284void MapFieldGenerator::GenerateCopyAggregateInitializer(
285 io::Printer* printer) const {
286 Formatter format(printer, variables_);
287 // MapField has no move constructor, which prevents explicit aggregate
288 // initialization pre-C++17.
289 format("/*decltype($field$)*/{}");
290}
291
292void MapFieldGenerator::GenerateAggregateInitializer(
293 io::Printer* printer) const {
294 Formatter format(printer, variables_);
295 if (ShouldSplit(field: descriptor_, options: options_)) {
296 format(
297 "/*decltype($classname$::Split::$name$_)*/"
298 "{::_pbi::ArenaInitialized(), arena}");
299 return;
300 }
301 // MapField has no move constructor.
302 format("/*decltype($field$)*/{::_pbi::ArenaInitialized(), arena}");
303}
304
305void MapFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
306 GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
307
308 Formatter format(printer, variables_);
309 if (ShouldSplit(field: descriptor_, options: options_)) {
310 format("$cached_split_ptr$->$name$_.Destruct();\n");
311 format("$cached_split_ptr$->$name$_.~MapField$lite$();\n");
312 return;
313 }
314 format("$field$.Destruct();\n");
315 format("$field$.~MapField$lite$();\n");
316}
317
318void MapFieldGenerator::GenerateArenaDestructorCode(
319 io::Printer* printer) const {
320 if (NeedsArenaDestructor() == ArenaDtorNeeds::kNone) {
321 return;
322 }
323
324 Formatter format(printer, variables_);
325 // _this is the object being destructed (we are inside a static method here).
326 format("_this->$field$.Destruct();\n");
327}
328
329ArenaDtorNeeds MapFieldGenerator::NeedsArenaDestructor() const {
330 return HasDescriptorMethods(file: descriptor_->file(), options: options_)
331 ? ArenaDtorNeeds::kRequired
332 : ArenaDtorNeeds::kNone;
333}
334
335} // namespace cpp
336} // namespace compiler
337} // namespace protobuf
338} // namespace google
339