blob: 8c38db2b36e5e6b35f39da921c902dcd75a7ba1d [file] [log] [blame]
Feng Xiaof157a562014-11-14 11:50:31 -08001// 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#include <google/protobuf/compiler/cpp/cpp_helpers.h>
33#include <google/protobuf/io/printer.h>
Jisi Liu885b6122015-02-28 14:51:22 -080034#include <google/protobuf/wire_format.h>
Feng Xiaof157a562014-11-14 11:50:31 -080035#include <google/protobuf/stubs/strutil.h>
36
37namespace google {
38namespace protobuf {
39namespace compiler {
40namespace cpp {
41
42bool IsProto3Field(const FieldDescriptor* field_descriptor) {
43 const FileDescriptor* file_descriptor = field_descriptor->file();
44 return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
45}
46
47void SetMessageVariables(const FieldDescriptor* descriptor,
48 map<string, string>* variables,
49 const Options& options) {
50 SetCommonFieldVariables(descriptor, variables, options);
51 (*variables)["type"] = FieldMessageTypeName(descriptor);
52 (*variables)["stream_writer"] = (*variables)["declared_type"] +
53 (HasFastArraySerialization(descriptor->message_type()->file()) ?
54 "MaybeToArray" :
55 "");
56 (*variables)["full_name"] = descriptor->full_name();
57
58 const FieldDescriptor* key =
59 descriptor->message_type()->FindFieldByName("key");
60 const FieldDescriptor* val =
61 descriptor->message_type()->FindFieldByName("value");
62 (*variables)["key_cpp"] = PrimitiveTypeName(key->cpp_type());
63 switch (val->cpp_type()) {
64 case FieldDescriptor::CPPTYPE_MESSAGE:
65 (*variables)["val_cpp"] = FieldMessageTypeName(val);
66 (*variables)["wrapper"] = "EntryWrapper";
67 break;
68 case FieldDescriptor::CPPTYPE_ENUM:
69 (*variables)["val_cpp"] = ClassName(val->enum_type(), false);
70 (*variables)["wrapper"] = "EnumEntryWrapper";
71 break;
72 default:
73 (*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type());
74 (*variables)["wrapper"] = "EntryWrapper";
75 }
Jisi Liu885b6122015-02-28 14:51:22 -080076 (*variables)["key_wire_type"] =
77 "::google::protobuf::internal::WireFormatLite::TYPE_" +
Feng Xiaof157a562014-11-14 11:50:31 -080078 ToUpper(DeclaredTypeMethodName(key->type()));
Jisi Liu885b6122015-02-28 14:51:22 -080079 (*variables)["val_wire_type"] =
80 "::google::protobuf::internal::WireFormatLite::TYPE_" +
Feng Xiaof157a562014-11-14 11:50:31 -080081 ToUpper(DeclaredTypeMethodName(val->type()));
82 (*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
Jisi Liu885b6122015-02-28 14:51:22 -080083 (*variables)["number"] = SimpleItoa(descriptor->number());
84 (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
85
86 if (HasDescriptorMethods(descriptor->file())) {
87 (*variables)["lite"] = "";
88 } else {
89 (*variables)["lite"] = "Lite";
90 }
Feng Xiaof157a562014-11-14 11:50:31 -080091
92 if (!IsProto3Field(descriptor) &&
93 val->type() == FieldDescriptor::TYPE_ENUM) {
94 const EnumValueDescriptor* default_value = val->default_value_enum();
95 (*variables)["default_enum_value"] = Int32ToString(default_value->number());
96 } else {
97 (*variables)["default_enum_value"] = "0";
98 }
99}
100
101MapFieldGenerator::
102MapFieldGenerator(const FieldDescriptor* descriptor,
103 const Options& options)
104 : descriptor_(descriptor) {
105 SetMessageVariables(descriptor, &variables_, options);
106}
107
108MapFieldGenerator::~MapFieldGenerator() {}
109
110void MapFieldGenerator::
111GeneratePrivateMembers(io::Printer* printer) const {
112 printer->Print(variables_,
Jisi Liu885b6122015-02-28 14:51:22 -0800113 "typedef ::google::protobuf::internal::MapEntryLite<\n"
Feng Xiaof157a562014-11-14 11:50:31 -0800114 " $key_cpp$, $val_cpp$,\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800115 " $key_wire_type$,\n"
116 " $val_wire_type$,\n"
117 " $default_enum_value$ >\n"
Feng Xiaof157a562014-11-14 11:50:31 -0800118 " $map_classname$;\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800119 "::google::protobuf::internal::MapField$lite$<\n"
120 " $key_cpp$, $val_cpp$,\n"
121 " $key_wire_type$,\n"
122 " $val_wire_type$,\n"
123 " $default_enum_value$ > $name$_;\n");
Feng Xiaof157a562014-11-14 11:50:31 -0800124}
125
126void MapFieldGenerator::
127GenerateAccessorDeclarations(io::Printer* printer) const {
128 printer->Print(variables_,
Jisi Liu885b6122015-02-28 14:51:22 -0800129 "const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
Feng Xiaof157a562014-11-14 11:50:31 -0800130 " $name$() const$deprecation$;\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800131 "::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
Feng Xiaof157a562014-11-14 11:50:31 -0800132 " mutable_$name$()$deprecation$;\n");
133}
134
135void MapFieldGenerator::
Jisi Liu885b6122015-02-28 14:51:22 -0800136GenerateInlineAccessorDefinitions(io::Printer* printer,
137 bool is_inline) const {
138 map<string, string> variables(variables_);
139 variables["inline"] = is_inline ? "inline" : "";
140 printer->Print(variables,
141 "$inline$ const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
Feng Xiaof157a562014-11-14 11:50:31 -0800142 "$classname$::$name$() const {\n"
143 " // @@protoc_insertion_point(field_map:$full_name$)\n"
144 " return $name$_.GetMap();\n"
145 "}\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800146 "$inline$ ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
Feng Xiaof157a562014-11-14 11:50:31 -0800147 "$classname$::mutable_$name$() {\n"
148 " // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
149 " return $name$_.MutableMap();\n"
150 "}\n");
151}
152
153void MapFieldGenerator::
154GenerateClearingCode(io::Printer* printer) const {
155 printer->Print(variables_, "$name$_.Clear();\n");
156}
157
158void MapFieldGenerator::
159GenerateMergingCode(io::Printer* printer) const {
160 printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
161}
162
163void MapFieldGenerator::
164GenerateSwappingCode(io::Printer* printer) const {
165 printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
166}
167
168void MapFieldGenerator::
169GenerateConstructorCode(io::Printer* printer) const {
170 if (HasDescriptorMethods(descriptor_->file())) {
171 printer->Print(variables_,
172 "$name$_.SetAssignDescriptorCallback(\n"
173 " protobuf_AssignDescriptorsOnce);\n"
174 "$name$_.SetEntryDescriptor(\n"
175 " &$type$_descriptor_);\n");
176 }
177}
178
179void MapFieldGenerator::
180GenerateMergeFromCodedStream(io::Printer* printer) const {
181 const FieldDescriptor* value_field =
182 descriptor_->message_type()->FindFieldByName("value");
183 printer->Print(variables_,
184 "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n");
185
186 if (IsProto3Field(descriptor_) ||
187 value_field->type() != FieldDescriptor::TYPE_ENUM) {
188 printer->Print(variables_,
189 "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
190 " input, entry.get()));\n");
191 switch (value_field->cpp_type()) {
192 case FieldDescriptor::CPPTYPE_MESSAGE:
193 printer->Print(variables_,
194 "(*mutable_$name$())[entry->key()].Swap("
195 "entry->mutable_value());\n");
196 break;
197 case FieldDescriptor::CPPTYPE_ENUM:
198 printer->Print(variables_,
199 "(*mutable_$name$())[entry->key()] =\n"
200 " static_cast<$val_cpp$>(*entry->mutable_value());\n");
201 break;
202 default:
203 printer->Print(variables_,
204 "(*mutable_$name$())[entry->key()] = *entry->mutable_value();\n");
205 break;
206 }
207 } else {
208 printer->Print(variables_,
209 "{\n"
210 " ::std::string data;\n"
211 " DO_(::google::protobuf::internal::WireFormatLite::ReadString(input, &data));\n"
212 " DO_(entry->ParseFromString(data));\n"
213 " if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
214 " (*mutable_$name$())[entry->key()] =\n"
215 " static_cast<$val_cpp$>(*entry->mutable_value());\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800216 " } else {\n");
217 if (HasDescriptorMethods(descriptor_->file())) {
218 printer->Print(variables_,
219 " mutable_unknown_fields()"
220 "->AddLengthDelimited($number$, data);\n");
221 } else {
222 printer->Print(variables_,
223 " unknown_fields_stream.WriteVarint32($tag$);\n"
224 " unknown_fields_stream.WriteVarint32(data.size());\n"
225 " unknown_fields_stream.WriteString(data);\n");
226 }
227
228
229 printer->Print(variables_,
Feng Xiaof157a562014-11-14 11:50:31 -0800230 " }\n"
231 "}\n");
232 }
Jisi Liu885b6122015-02-28 14:51:22 -0800233
234 // If entry is allocated by arena, its desctructor should be avoided.
235 if (SupportsArenas(descriptor_)) {
236 printer->Print(variables_,
237 "if (entry->GetArena() != NULL) entry.release();\n");
238 }
Feng Xiaof157a562014-11-14 11:50:31 -0800239}
240
241void MapFieldGenerator::
242GenerateSerializeWithCachedSizes(io::Printer* printer) const {
243 printer->Print(variables_,
244 "{\n"
245 " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
246 " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800247 " it = $name$().begin(); it != $name$().end(); ++it) {\n");
248
249 // If entry is allocated by arena, its desctructor should be avoided.
250 if (SupportsArenas(descriptor_)) {
251 printer->Print(variables_,
252 " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
253 " entry.release();\n"
254 " }\n");
255 }
256
257 printer->Print(variables_,
Feng Xiaof157a562014-11-14 11:50:31 -0800258 " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
259 " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
260 " $number$, *entry, output);\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800261 " }\n");
262
263 // If entry is allocated by arena, its desctructor should be avoided.
264 if (SupportsArenas(descriptor_)) {
265 printer->Print(variables_,
266 " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
267 " entry.release();\n"
268 " }\n");
269 }
270
271 printer->Print("}\n");
Feng Xiaof157a562014-11-14 11:50:31 -0800272}
273
274void MapFieldGenerator::
275GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
276 printer->Print(variables_,
277 "{\n"
278 " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
279 " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800280 " it = $name$().begin(); it != $name$().end(); ++it) {\n");
281
282 // If entry is allocated by arena, its desctructor should be avoided.
283 if (SupportsArenas(descriptor_)) {
284 printer->Print(variables_,
285 " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
286 " entry.release();\n"
287 " }\n");
288 }
289
290 printer->Print(variables_,
Feng Xiaof157a562014-11-14 11:50:31 -0800291 " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
292 " target = ::google::protobuf::internal::WireFormatLite::\n"
293 " Write$declared_type$NoVirtualToArray(\n"
294 " $number$, *entry, target);\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800295 " }\n");
296
297 // If entry is allocated by arena, its desctructor should be avoided.
298 if (SupportsArenas(descriptor_)) {
299 printer->Print(variables_,
300 " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
301 " entry.release();\n"
302 " }\n");
303 }
304
305 printer->Print("}\n");
Feng Xiaof157a562014-11-14 11:50:31 -0800306}
307
308void MapFieldGenerator::
309GenerateByteSize(io::Printer* printer) const {
310 printer->Print(variables_,
311 "total_size += $tag_size$ * this->$name$_size();\n"
312 "{\n"
313 " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
314 " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800315 " it = $name$().begin(); it != $name$().end(); ++it) {\n");
316
317 // If entry is allocated by arena, its desctructor should be avoided.
318 if (SupportsArenas(descriptor_)) {
319 printer->Print(variables_,
320 " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
321 " entry.release();\n"
322 " }\n");
323 }
324
325 printer->Print(variables_,
Feng Xiaof157a562014-11-14 11:50:31 -0800326 " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
327 " total_size += ::google::protobuf::internal::WireFormatLite::\n"
328 " $declared_type$SizeNoVirtual(*entry);\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800329 " }\n");
330
331 // If entry is allocated by arena, its desctructor should be avoided.
332 if (SupportsArenas(descriptor_)) {
333 printer->Print(variables_,
334 " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
335 " entry.release();\n"
336 " }\n");
337 }
338
339 printer->Print("}\n");
Feng Xiaof157a562014-11-14 11:50:31 -0800340}
341
342} // namespace cpp
343} // namespace compiler
344} // namespace protobuf
345} // namespace google