Line data Source code
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 : // Author: kenton@google.com (Kenton Varda)
32 : // Based on original Protocol Buffers design by
33 : // Sanjay Ghemawat, Jeff Dean, and others.
34 :
35 : #include <google/protobuf/compiler/cpp/cpp_enum_field.h>
36 : #include <google/protobuf/compiler/cpp/cpp_helpers.h>
37 : #include <google/protobuf/io/printer.h>
38 : #include <google/protobuf/stubs/strutil.h>
39 :
40 : namespace google {
41 : namespace protobuf {
42 : namespace compiler {
43 : namespace cpp {
44 :
45 : namespace {
46 :
47 388 : void SetEnumVariables(const FieldDescriptor* descriptor,
48 : map<string, string>* variables,
49 : const Options& options) {
50 97 : SetCommonFieldVariables(descriptor, variables, options);
51 194 : const EnumValueDescriptor* default_value = descriptor->default_value_enum();
52 291 : (*variables)["type"] = ClassName(descriptor->enum_type(), true);
53 291 : (*variables)["default"] = Int32ToString(default_value->number());
54 194 : (*variables)["full_name"] = descriptor->full_name();
55 97 : }
56 :
57 : } // namespace
58 :
59 : // ===================================================================
60 :
61 67 : EnumFieldGenerator::
62 : EnumFieldGenerator(const FieldDescriptor* descriptor,
63 : const Options& options)
64 134 : : descriptor_(descriptor) {
65 67 : SetEnumVariables(descriptor, &variables_, options);
66 67 : }
67 :
68 191 : EnumFieldGenerator::~EnumFieldGenerator() {}
69 :
70 65 : void EnumFieldGenerator::
71 : GeneratePrivateMembers(io::Printer* printer) const {
72 65 : printer->Print(variables_, "int $name$_;\n");
73 65 : }
74 :
75 55 : void EnumFieldGenerator::
76 : GenerateAccessorDeclarations(io::Printer* printer) const {
77 : printer->Print(variables_,
78 : "$type$ $name$() const$deprecation$;\n"
79 55 : "void set_$name$($type$ value)$deprecation$;\n");
80 55 : }
81 :
82 90 : void EnumFieldGenerator::
83 : GenerateInlineAccessorDefinitions(io::Printer* printer,
84 : bool is_inline) const {
85 90 : map<string, string> variables(variables_);
86 180 : variables["inline"] = is_inline ? "inline" : "";
87 : printer->Print(variables,
88 : "$inline$ $type$ $classname$::$name$() const {\n"
89 : " // @@protoc_insertion_point(field_get:$full_name$)\n"
90 : " return static_cast< $type$ >($name$_);\n"
91 : "}\n"
92 90 : "$inline$ void $classname$::set_$name$($type$ value) {\n");
93 180 : if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
94 : printer->Print(variables,
95 48 : " assert($type$_IsValid(value));\n");
96 : }
97 : printer->Print(variables,
98 : " $set_hasbit$\n"
99 : " $name$_ = value;\n"
100 : " // @@protoc_insertion_point(field_set:$full_name$)\n"
101 90 : "}\n");
102 90 : }
103 :
104 126 : void EnumFieldGenerator::
105 : GenerateClearingCode(io::Printer* printer) const {
106 126 : printer->Print(variables_, "$name$_ = $default$;\n");
107 126 : }
108 :
109 55 : void EnumFieldGenerator::
110 : GenerateMergingCode(io::Printer* printer) const {
111 55 : printer->Print(variables_, "set_$name$(from.$name$());\n");
112 55 : }
113 :
114 45 : void EnumFieldGenerator::
115 : GenerateSwappingCode(io::Printer* printer) const {
116 45 : printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
117 45 : }
118 :
119 45 : void EnumFieldGenerator::
120 : GenerateConstructorCode(io::Printer* printer) const {
121 45 : printer->Print(variables_, "$name$_ = $default$;\n");
122 45 : }
123 :
124 55 : void EnumFieldGenerator::
125 : GenerateMergeFromCodedStream(io::Printer* printer) const {
126 : printer->Print(variables_,
127 : "int value;\n"
128 : "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
129 : " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
130 55 : " input, &value)));\n");
131 138 : if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
132 : printer->Print(variables_,
133 27 : "set_$name$(static_cast< $type$ >(value));\n");
134 : } else {
135 : printer->Print(variables_,
136 : "if ($type$_IsValid(value)) {\n"
137 28 : " set_$name$(static_cast< $type$ >(value));\n");
138 84 : if (UseUnknownFieldSet(descriptor_->file())) {
139 : printer->Print(variables_,
140 : "} else {\n"
141 22 : " mutable_unknown_fields()->AddVarint($number$, value);\n");
142 : } else {
143 : printer->Print(
144 : "} else {\n"
145 : " unknown_fields_stream.WriteVarint32(tag);\n"
146 6 : " unknown_fields_stream.WriteVarint32(value);\n");
147 : }
148 : printer->Print(variables_,
149 28 : "}\n");
150 : }
151 55 : }
152 :
153 55 : void EnumFieldGenerator::
154 : GenerateSerializeWithCachedSizes(io::Printer* printer) const {
155 : printer->Print(variables_,
156 : "::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
157 55 : " $number$, this->$name$(), output);\n");
158 55 : }
159 :
160 49 : void EnumFieldGenerator::
161 : GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
162 : printer->Print(variables_,
163 : "target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
164 49 : " $number$, this->$name$(), target);\n");
165 49 : }
166 :
167 55 : void EnumFieldGenerator::
168 : GenerateByteSize(io::Printer* printer) const {
169 : printer->Print(variables_,
170 : "total_size += $tag_size$ +\n"
171 55 : " ::google::protobuf::internal::WireFormatLite::EnumSize(this->$name$());\n");
172 55 : }
173 :
174 : // ===================================================================
175 :
176 10 : EnumOneofFieldGenerator::
177 : EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
178 : const Options& options)
179 10 : : EnumFieldGenerator(descriptor, options) {
180 10 : SetCommonOneofFieldVariables(descriptor, &variables_);
181 10 : }
182 :
183 20 : EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
184 :
185 20 : void EnumOneofFieldGenerator::
186 : GenerateInlineAccessorDefinitions(io::Printer* printer,
187 : bool is_inline) const {
188 20 : map<string, string> variables(variables_);
189 40 : variables["inline"] = is_inline ? "inline" : "";
190 : printer->Print(variables,
191 : "$inline$ $type$ $classname$::$name$() const {\n"
192 : " // @@protoc_insertion_point(field_get:$full_name$)\n"
193 : " if (has_$name$()) {\n"
194 : " return static_cast< $type$ >($oneof_prefix$$name$_);\n"
195 : " }\n"
196 : " return static_cast< $type$ >($default$);\n"
197 : "}\n"
198 20 : "$inline$ void $classname$::set_$name$($type$ value) {\n");
199 40 : if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
200 : printer->Print(variables,
201 8 : " assert($type$_IsValid(value));\n");
202 : }
203 : printer->Print(variables,
204 : " if (!has_$name$()) {\n"
205 : " clear_$oneof_name$();\n"
206 : " set_has_$name$();\n"
207 : " }\n"
208 : " $oneof_prefix$$name$_ = value;\n"
209 : " // @@protoc_insertion_point(field_set:$full_name$)\n"
210 20 : "}\n");
211 20 : }
212 :
213 20 : void EnumOneofFieldGenerator::
214 : GenerateClearingCode(io::Printer* printer) const {
215 20 : printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
216 20 : }
217 :
218 10 : void EnumOneofFieldGenerator::
219 : GenerateSwappingCode(io::Printer* printer) const {
220 : // Don't print any swapping code. Swapping the union will swap this field.
221 10 : }
222 :
223 10 : void EnumOneofFieldGenerator::
224 : GenerateConstructorCode(io::Printer* printer) const {
225 : printer->Print(variables_,
226 10 : " $classname$_default_oneof_instance_->$name$_ = $default$;\n");
227 10 : }
228 :
229 : // ===================================================================
230 :
231 30 : RepeatedEnumFieldGenerator::
232 : RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
233 : const Options& options)
234 60 : : descriptor_(descriptor) {
235 30 : SetEnumVariables(descriptor, &variables_, options);
236 30 : }
237 :
238 90 : RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
239 :
240 30 : void RepeatedEnumFieldGenerator::
241 : GeneratePrivateMembers(io::Printer* printer) const {
242 : printer->Print(variables_,
243 30 : "::google::protobuf::RepeatedField<int> $name$_;\n");
244 75 : if (descriptor_->is_packed()
245 60 : && HasGeneratedMethods(descriptor_->file())) {
246 : printer->Print(variables_,
247 15 : "mutable int _$name$_cached_byte_size_;\n");
248 : }
249 30 : }
250 :
251 30 : void RepeatedEnumFieldGenerator::
252 : GenerateAccessorDeclarations(io::Printer* printer) const {
253 : printer->Print(variables_,
254 : "$type$ $name$(int index) const$deprecation$;\n"
255 : "void set_$name$(int index, $type$ value)$deprecation$;\n"
256 30 : "void add_$name$($type$ value)$deprecation$;\n");
257 : printer->Print(variables_,
258 : "const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
259 30 : "::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n");
260 30 : }
261 :
262 60 : void RepeatedEnumFieldGenerator::
263 : GenerateInlineAccessorDefinitions(io::Printer* printer,
264 : bool is_inline) const {
265 60 : map<string, string> variables(variables_);
266 120 : variables["inline"] = is_inline ? "inline" : "";
267 : printer->Print(variables,
268 : "$inline$ $type$ $classname$::$name$(int index) const {\n"
269 : " // @@protoc_insertion_point(field_get:$full_name$)\n"
270 : " return static_cast< $type$ >($name$_.Get(index));\n"
271 : "}\n"
272 60 : "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n");
273 180 : if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
274 : printer->Print(variables,
275 34 : " assert($type$_IsValid(value));\n");
276 : }
277 : printer->Print(variables,
278 : " $name$_.Set(index, value);\n"
279 : " // @@protoc_insertion_point(field_set:$full_name$)\n"
280 : "}\n"
281 60 : "$inline$ void $classname$::add_$name$($type$ value) {\n");
282 180 : if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
283 : printer->Print(variables,
284 34 : " assert($type$_IsValid(value));\n");
285 : }
286 : printer->Print(variables,
287 : " $name$_.Add(value);\n"
288 : " // @@protoc_insertion_point(field_add:$full_name$)\n"
289 60 : "}\n");
290 : printer->Print(variables,
291 : "$inline$ const ::google::protobuf::RepeatedField<int>&\n"
292 : "$classname$::$name$() const {\n"
293 : " // @@protoc_insertion_point(field_list:$full_name$)\n"
294 : " return $name$_;\n"
295 : "}\n"
296 : "$inline$ ::google::protobuf::RepeatedField<int>*\n"
297 : "$classname$::mutable_$name$() {\n"
298 : " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
299 : " return &$name$_;\n"
300 60 : "}\n");
301 60 : }
302 :
303 90 : void RepeatedEnumFieldGenerator::
304 : GenerateClearingCode(io::Printer* printer) const {
305 90 : printer->Print(variables_, "$name$_.Clear();\n");
306 90 : }
307 :
308 30 : void RepeatedEnumFieldGenerator::
309 : GenerateMergingCode(io::Printer* printer) const {
310 30 : printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
311 30 : }
312 :
313 30 : void RepeatedEnumFieldGenerator::
314 : GenerateSwappingCode(io::Printer* printer) const {
315 30 : printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
316 30 : }
317 :
318 30 : void RepeatedEnumFieldGenerator::
319 : GenerateConstructorCode(io::Printer* printer) const {
320 : // Not needed for repeated fields.
321 30 : }
322 :
323 30 : void RepeatedEnumFieldGenerator::
324 : GenerateMergeFromCodedStream(io::Printer* printer) const {
325 : // Don't use ReadRepeatedPrimitive here so that the enum can be validated.
326 : printer->Print(variables_,
327 : "int value;\n"
328 : "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
329 : " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
330 30 : " input, &value)));\n");
331 77 : if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
332 : printer->Print(variables_,
333 13 : "add_$name$(static_cast< $type$ >(value));\n");
334 : } else {
335 : printer->Print(variables_,
336 : "if ($type$_IsValid(value)) {\n"
337 17 : " add_$name$(static_cast< $type$ >(value));\n");
338 51 : if (UseUnknownFieldSet(descriptor_->file())) {
339 : printer->Print(variables_,
340 : "} else {\n"
341 13 : " mutable_unknown_fields()->AddVarint($number$, value);\n");
342 : } else {
343 : printer->Print(
344 : "} else {\n"
345 : " unknown_fields_stream.WriteVarint32(tag);\n"
346 4 : " unknown_fields_stream.WriteVarint32(value);\n");
347 : }
348 17 : printer->Print("}\n");
349 : }
350 30 : }
351 :
352 30 : void RepeatedEnumFieldGenerator::
353 : GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
354 63 : if (!descriptor_->is_packed()) {
355 : // This path is rarely executed, so we use a non-inlined implementation.
356 45 : if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
357 : printer->Print(variables_,
358 : "DO_((::google::protobuf::internal::"
359 : "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
360 : " input,\n"
361 : " $number$,\n"
362 : " NULL,\n"
363 : " NULL,\n"
364 1 : " this->mutable_$name$())));\n");
365 28 : } else if (UseUnknownFieldSet(descriptor_->file())) {
366 : printer->Print(variables_,
367 : "DO_((::google::protobuf::internal::WireFormat::ReadPackedEnumPreserveUnknowns(\n"
368 : " input,\n"
369 : " $number$,\n"
370 : " $type$_IsValid,\n"
371 : " mutable_unknown_fields(),\n"
372 11 : " this->mutable_$name$())));\n");
373 : } else {
374 : printer->Print(variables_,
375 : "DO_((::google::protobuf::internal::"
376 : "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
377 : " input,\n"
378 : " $number$,\n"
379 : " $type$_IsValid,\n"
380 : " &unknown_fields_stream,\n"
381 3 : " this->mutable_$name$())));\n");
382 : }
383 : } else {
384 : printer->Print(variables_,
385 : "::google::protobuf::uint32 length;\n"
386 : "DO_(input->ReadVarint32(&length));\n"
387 : "::google::protobuf::io::CodedInputStream::Limit limit = "
388 : "input->PushLimit(length);\n"
389 : "while (input->BytesUntilLimit() > 0) {\n"
390 : " int value;\n"
391 : " DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
392 : " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
393 15 : " input, &value)));\n");
394 45 : if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
395 : printer->Print(variables_,
396 12 : " add_$name$(static_cast< $type$ >(value));\n");
397 : } else {
398 : printer->Print(variables_,
399 : " if ($type$_IsValid(value)) {\n"
400 : " add_$name$(static_cast< $type$ >(value));\n"
401 3 : " } else {\n");
402 9 : if (UseUnknownFieldSet(descriptor_->file())) {
403 : printer->Print(variables_,
404 2 : " mutable_unknown_fields()->AddVarint($number$, value);\n");
405 : } else {
406 : printer->Print(variables_,
407 : " unknown_fields_stream.WriteVarint32(tag);\n"
408 1 : " unknown_fields_stream.WriteVarint32(value);\n");
409 : }
410 : printer->Print(
411 3 : " }\n");
412 : }
413 : printer->Print(variables_,
414 : "}\n"
415 15 : "input->PopLimit(limit);\n");
416 : }
417 30 : }
418 :
419 30 : void RepeatedEnumFieldGenerator::
420 : GenerateSerializeWithCachedSizes(io::Printer* printer) const {
421 30 : if (descriptor_->is_packed()) {
422 : // Write the tag and the size.
423 : printer->Print(variables_,
424 : "if (this->$name$_size() > 0) {\n"
425 : " ::google::protobuf::internal::WireFormatLite::WriteTag(\n"
426 : " $number$,\n"
427 : " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
428 : " output);\n"
429 : " output->WriteVarint32(_$name$_cached_byte_size_);\n"
430 15 : "}\n");
431 : }
432 : printer->Print(variables_,
433 30 : "for (int i = 0; i < this->$name$_size(); i++) {\n");
434 30 : if (descriptor_->is_packed()) {
435 : printer->Print(variables_,
436 : " ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n"
437 15 : " this->$name$(i), output);\n");
438 : } else {
439 : printer->Print(variables_,
440 : " ::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
441 15 : " $number$, this->$name$(i), output);\n");
442 : }
443 30 : printer->Print("}\n");
444 30 : }
445 :
446 26 : void RepeatedEnumFieldGenerator::
447 : GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
448 26 : if (descriptor_->is_packed()) {
449 : // Write the tag and the size.
450 : printer->Print(variables_,
451 : "if (this->$name$_size() > 0) {\n"
452 : " target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
453 : " $number$,\n"
454 : " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
455 : " target);\n"
456 : " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray("
457 : " _$name$_cached_byte_size_, target);\n"
458 14 : "}\n");
459 : }
460 : printer->Print(variables_,
461 26 : "for (int i = 0; i < this->$name$_size(); i++) {\n");
462 26 : if (descriptor_->is_packed()) {
463 : printer->Print(variables_,
464 : " target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
465 14 : " this->$name$(i), target);\n");
466 : } else {
467 : printer->Print(variables_,
468 : " target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
469 12 : " $number$, this->$name$(i), target);\n");
470 : }
471 26 : printer->Print("}\n");
472 26 : }
473 :
474 30 : void RepeatedEnumFieldGenerator::
475 : GenerateByteSize(io::Printer* printer) const {
476 : printer->Print(variables_,
477 : "{\n"
478 30 : " int data_size = 0;\n");
479 30 : printer->Indent();
480 : printer->Print(variables_,
481 : "for (int i = 0; i < this->$name$_size(); i++) {\n"
482 : " data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(\n"
483 : " this->$name$(i));\n"
484 30 : "}\n");
485 :
486 30 : if (descriptor_->is_packed()) {
487 : printer->Print(variables_,
488 : "if (data_size > 0) {\n"
489 : " total_size += $tag_size$ +\n"
490 : " ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
491 : "}\n"
492 : "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
493 : "_$name$_cached_byte_size_ = data_size;\n"
494 : "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
495 15 : "total_size += data_size;\n");
496 : } else {
497 : printer->Print(variables_,
498 15 : "total_size += $tag_size$ * this->$name$_size() + data_size;\n");
499 : }
500 30 : printer->Outdent();
501 30 : printer->Print("}\n");
502 30 : }
503 :
504 : } // namespace cpp
505 : } // namespace compiler
506 : } // namespace protobuf
507 : } // namespace google
|