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/wire_format.h>
39 #include <google/protobuf/stubs/strutil.h>
40
41 namespace google {
42 namespace protobuf {
43 namespace compiler {
44 namespace cpp {
45
46 namespace {
47
SetEnumVariables(const FieldDescriptor * descriptor,std::map<std::string,std::string> * variables,const Options & options)48 void SetEnumVariables(const FieldDescriptor* descriptor,
49 std::map<std::string, std::string>* variables,
50 const Options& options) {
51 SetCommonFieldVariables(descriptor, variables, options);
52 const EnumValueDescriptor* default_value = descriptor->default_value_enum();
53 (*variables)["type"] = QualifiedClassName(descriptor->enum_type(), options);
54 (*variables)["default"] = Int32ToString(default_value->number());
55 (*variables)["full_name"] = descriptor->full_name();
56 }
57
58 } // namespace
59
60 // ===================================================================
61
EnumFieldGenerator(const FieldDescriptor * descriptor,const Options & options)62 EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
63 const Options& options)
64 : FieldGenerator(descriptor, options) {
65 SetEnumVariables(descriptor, &variables_, options);
66 }
67
~EnumFieldGenerator()68 EnumFieldGenerator::~EnumFieldGenerator() {}
69
GeneratePrivateMembers(io::Printer * printer) const70 void EnumFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
71 Formatter format(printer, variables_);
72 format("int $name$_;\n");
73 }
74
GenerateAccessorDeclarations(io::Printer * printer) const75 void EnumFieldGenerator::GenerateAccessorDeclarations(
76 io::Printer* printer) const {
77 Formatter format(printer, variables_);
78 format(
79 "$deprecated_attr$$type$ ${1$$name$$}$() const;\n"
80 "$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n",
81 descriptor_);
82 }
83
GenerateInlineAccessorDefinitions(io::Printer * printer) const84 void EnumFieldGenerator::GenerateInlineAccessorDefinitions(
85 io::Printer* printer) const {
86 Formatter format(printer, variables_);
87 format(
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 "inline void $classname$::set_$name$($type$ value) {\n");
93 if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
94 format(" assert($type$_IsValid(value));\n");
95 }
96 format(
97 " $set_hasbit$\n"
98 " $name$_ = value;\n"
99 " // @@protoc_insertion_point(field_set:$full_name$)\n"
100 "}\n");
101 }
102
GenerateClearingCode(io::Printer * printer) const103 void EnumFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
104 Formatter format(printer, variables_);
105 format("$name$_ = $default$;\n");
106 }
107
GenerateMergingCode(io::Printer * printer) const108 void EnumFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
109 Formatter format(printer, variables_);
110 format("set_$name$(from.$name$());\n");
111 }
112
GenerateSwappingCode(io::Printer * printer) const113 void EnumFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
114 Formatter format(printer, variables_);
115 format("swap($name$_, other->$name$_);\n");
116 }
117
GenerateConstructorCode(io::Printer * printer) const118 void EnumFieldGenerator::GenerateConstructorCode(io::Printer* printer) const {
119 Formatter format(printer, variables_);
120 format("$name$_ = $default$;\n");
121 }
122
GenerateCopyConstructorCode(io::Printer * printer) const123 void EnumFieldGenerator::GenerateCopyConstructorCode(
124 io::Printer* printer) const {
125 Formatter format(printer, variables_);
126 format("$name$_ = from.$name$_;\n");
127 }
128
GenerateMergeFromCodedStream(io::Printer * printer) const129 void EnumFieldGenerator::GenerateMergeFromCodedStream(
130 io::Printer* printer) const {
131 Formatter format(printer, variables_);
132 format(
133 "int value = 0;\n"
134 "DO_((::$proto_ns$::internal::WireFormatLite::ReadPrimitive<\n"
135 " int, ::$proto_ns$::internal::WireFormatLite::TYPE_ENUM>(\n"
136 " input, &value)));\n");
137 if (HasPreservingUnknownEnumSemantics(descriptor_)) {
138 format("set_$name$(static_cast< $type$ >(value));\n");
139 } else {
140 format(
141 "if ($type$_IsValid(value)) {\n"
142 " set_$name$(static_cast< $type$ >(value));\n");
143 if (UseUnknownFieldSet(descriptor_->file(), options_)) {
144 format(
145 "} else {\n"
146 " mutable_unknown_fields()->AddVarint(\n"
147 " $number$, static_cast<$uint64$>(value));\n");
148 } else {
149 format(
150 "} else {\n"
151 " unknown_fields_stream.WriteVarint32($1$u);\n"
152 " unknown_fields_stream.WriteVarint32(\n"
153 " static_cast<$uint32$>(value));\n",
154 internal::WireFormat::MakeTag(descriptor_));
155 }
156 format("}\n");
157 }
158 }
159
GenerateSerializeWithCachedSizes(io::Printer * printer) const160 void EnumFieldGenerator::GenerateSerializeWithCachedSizes(
161 io::Printer* printer) const {
162 Formatter format(printer, variables_);
163 format(
164 "::$proto_ns$::internal::WireFormatLite::WriteEnum(\n"
165 " $number$, this->$name$(), output);\n");
166 }
167
GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const168 void EnumFieldGenerator::GenerateSerializeWithCachedSizesToArray(
169 io::Printer* printer) const {
170 Formatter format(printer, variables_);
171 format(
172 "target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n"
173 " $number$, this->$name$(), target);\n");
174 }
175
GenerateByteSize(io::Printer * printer) const176 void EnumFieldGenerator::GenerateByteSize(io::Printer* printer) const {
177 Formatter format(printer, variables_);
178 format(
179 "total_size += $tag_size$ +\n"
180 " ::$proto_ns$::internal::WireFormatLite::EnumSize(this->$name$());\n");
181 }
182
183 // ===================================================================
184
EnumOneofFieldGenerator(const FieldDescriptor * descriptor,const Options & options)185 EnumOneofFieldGenerator::EnumOneofFieldGenerator(
186 const FieldDescriptor* descriptor, const Options& options)
187 : EnumFieldGenerator(descriptor, options) {
188 SetCommonOneofFieldVariables(descriptor, &variables_);
189 }
190
~EnumOneofFieldGenerator()191 EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
192
GenerateInlineAccessorDefinitions(io::Printer * printer) const193 void EnumOneofFieldGenerator::GenerateInlineAccessorDefinitions(
194 io::Printer* printer) const {
195 Formatter format(printer, variables_);
196 format(
197 "inline $type$ $classname$::$name$() const {\n"
198 " // @@protoc_insertion_point(field_get:$full_name$)\n"
199 " if (has_$name$()) {\n"
200 " return static_cast< $type$ >($field_member$);\n"
201 " }\n"
202 " return static_cast< $type$ >($default$);\n"
203 "}\n"
204 "inline void $classname$::set_$name$($type$ value) {\n");
205 if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
206 format(" assert($type$_IsValid(value));\n");
207 }
208 format(
209 " if (!has_$name$()) {\n"
210 " clear_$oneof_name$();\n"
211 " set_has_$name$();\n"
212 " }\n"
213 " $field_member$ = value;\n"
214 " // @@protoc_insertion_point(field_set:$full_name$)\n"
215 "}\n");
216 }
217
GenerateClearingCode(io::Printer * printer) const218 void EnumOneofFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
219 Formatter format(printer, variables_);
220 format("$field_member$ = $default$;\n");
221 }
222
GenerateSwappingCode(io::Printer * printer) const223 void EnumOneofFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
224 // Don't print any swapping code. Swapping the union will swap this field.
225 }
226
GenerateConstructorCode(io::Printer * printer) const227 void EnumOneofFieldGenerator::GenerateConstructorCode(
228 io::Printer* printer) const {
229 Formatter format(printer, variables_);
230 format("$ns$::_$classname$_default_instance_.$name$_ = $default$;\n");
231 }
232
233 // ===================================================================
234
RepeatedEnumFieldGenerator(const FieldDescriptor * descriptor,const Options & options)235 RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
236 const FieldDescriptor* descriptor, const Options& options)
237 : FieldGenerator(descriptor, options) {
238 SetEnumVariables(descriptor, &variables_, options);
239 }
240
~RepeatedEnumFieldGenerator()241 RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
242
GeneratePrivateMembers(io::Printer * printer) const243 void RepeatedEnumFieldGenerator::GeneratePrivateMembers(
244 io::Printer* printer) const {
245 Formatter format(printer, variables_);
246 format("::$proto_ns$::RepeatedField<int> $name$_;\n");
247 if (descriptor_->is_packed() &&
248 HasGeneratedMethods(descriptor_->file(), options_)) {
249 format("mutable std::atomic<int> _$name$_cached_byte_size_;\n");
250 }
251 }
252
GenerateAccessorDeclarations(io::Printer * printer) const253 void RepeatedEnumFieldGenerator::GenerateAccessorDeclarations(
254 io::Printer* printer) const {
255 Formatter format(printer, variables_);
256 format(
257 "$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n"
258 "$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n"
259 "$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n"
260 "$deprecated_attr$const ::$proto_ns$::RepeatedField<int>& "
261 "${1$$name$$}$() const;\n"
262 "$deprecated_attr$::$proto_ns$::RepeatedField<int>* "
263 "${1$mutable_$name$$}$();\n",
264 descriptor_);
265 }
266
GenerateInlineAccessorDefinitions(io::Printer * printer) const267 void RepeatedEnumFieldGenerator::GenerateInlineAccessorDefinitions(
268 io::Printer* printer) const {
269 Formatter format(printer, variables_);
270 format(
271 "inline $type$ $classname$::$name$(int index) const {\n"
272 " // @@protoc_insertion_point(field_get:$full_name$)\n"
273 " return static_cast< $type$ >($name$_.Get(index));\n"
274 "}\n"
275 "inline void $classname$::set_$name$(int index, $type$ value) {\n");
276 if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
277 format(" assert($type$_IsValid(value));\n");
278 }
279 format(
280 " $name$_.Set(index, value);\n"
281 " // @@protoc_insertion_point(field_set:$full_name$)\n"
282 "}\n"
283 "inline void $classname$::add_$name$($type$ value) {\n");
284 if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
285 format(" assert($type$_IsValid(value));\n");
286 }
287 format(
288 " $name$_.Add(value);\n"
289 " // @@protoc_insertion_point(field_add:$full_name$)\n"
290 "}\n"
291 "inline const ::$proto_ns$::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 ::$proto_ns$::RepeatedField<int>*\n"
297 "$classname$::mutable_$name$() {\n"
298 " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
299 " return &$name$_;\n"
300 "}\n");
301 }
302
GenerateClearingCode(io::Printer * printer) const303 void RepeatedEnumFieldGenerator::GenerateClearingCode(
304 io::Printer* printer) const {
305 Formatter format(printer, variables_);
306 format("$name$_.Clear();\n");
307 }
308
GenerateMergingCode(io::Printer * printer) const309 void RepeatedEnumFieldGenerator::GenerateMergingCode(
310 io::Printer* printer) const {
311 Formatter format(printer, variables_);
312 format("$name$_.MergeFrom(from.$name$_);\n");
313 }
314
GenerateSwappingCode(io::Printer * printer) const315 void RepeatedEnumFieldGenerator::GenerateSwappingCode(
316 io::Printer* printer) const {
317 Formatter format(printer, variables_);
318 format("$name$_.InternalSwap(&other->$name$_);\n");
319 }
320
GenerateConstructorCode(io::Printer * printer) const321 void RepeatedEnumFieldGenerator::GenerateConstructorCode(
322 io::Printer* printer) const {
323 // Not needed for repeated fields.
324 }
325
GenerateMergeFromCodedStream(io::Printer * printer) const326 void RepeatedEnumFieldGenerator::GenerateMergeFromCodedStream(
327 io::Printer* printer) const {
328 Formatter format(printer, variables_);
329 // Don't use ReadRepeatedPrimitive here so that the enum can be validated.
330 format(
331 "int value = 0;\n"
332 "DO_((::$proto_ns$::internal::WireFormatLite::ReadPrimitive<\n"
333 " int, ::$proto_ns$::internal::WireFormatLite::TYPE_ENUM>(\n"
334 " input, &value)));\n");
335 if (HasPreservingUnknownEnumSemantics(descriptor_)) {
336 format("add_$name$(static_cast< $type$ >(value));\n");
337 } else {
338 format(
339 "if ($type$_IsValid(value)) {\n"
340 " add_$name$(static_cast< $type$ >(value));\n");
341 if (UseUnknownFieldSet(descriptor_->file(), options_)) {
342 format(
343 "} else {\n"
344 " mutable_unknown_fields()->AddVarint(\n"
345 " $number$, static_cast<$uint64$>(value));\n");
346 } else {
347 format(
348 "} else {\n"
349 " unknown_fields_stream.WriteVarint32(tag);\n"
350 " unknown_fields_stream.WriteVarint32(\n"
351 " static_cast<$uint32$>(value));\n");
352 }
353 format("}\n");
354 }
355 }
356
GenerateMergeFromCodedStreamWithPacking(io::Printer * printer) const357 void RepeatedEnumFieldGenerator::GenerateMergeFromCodedStreamWithPacking(
358 io::Printer* printer) const {
359 Formatter format(printer, variables_);
360 if (!descriptor_->is_packed()) {
361 // This path is rarely executed, so we use a non-inlined implementation.
362 if (HasPreservingUnknownEnumSemantics(descriptor_)) {
363 format(
364 "DO_((::$proto_ns$::internal::"
365 "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
366 " input,\n"
367 " $number$,\n"
368 " nullptr,\n"
369 " nullptr,\n"
370 " this->mutable_$name$())));\n");
371 } else if (UseUnknownFieldSet(descriptor_->file(), options_)) {
372 format(
373 "DO_((::$proto_ns$::internal::WireFormat::"
374 "ReadPackedEnumPreserveUnknowns(\n"
375 " input,\n"
376 " $number$,\n"
377 " $type$_IsValid,\n"
378 " mutable_unknown_fields(),\n"
379 " this->mutable_$name$())));\n");
380 } else {
381 format(
382 "DO_((::$proto_ns$::internal::"
383 "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
384 " input,\n"
385 " $number$,\n"
386 " $type$_IsValid,\n"
387 " &unknown_fields_stream,\n"
388 " this->mutable_$name$())));\n");
389 }
390 } else {
391 format(
392 "$uint32$ length;\n"
393 "DO_(input->ReadVarint32(&length));\n"
394 "::$proto_ns$::io::CodedInputStream::Limit limit = "
395 "input->PushLimit(static_cast<int>(length));\n"
396 "while (input->BytesUntilLimit() > 0) {\n"
397 " int value = 0;\n"
398 " DO_((::$proto_ns$::internal::WireFormatLite::ReadPrimitive<\n"
399 " int, ::$proto_ns$::internal::WireFormatLite::TYPE_ENUM>(\n"
400 " input, &value)));\n");
401 if (HasPreservingUnknownEnumSemantics(descriptor_)) {
402 format(" add_$name$(static_cast< $type$ >(value));\n");
403 } else {
404 format(
405 " if ($type$_IsValid(value)) {\n"
406 " add_$name$(static_cast< $type$ >(value));\n"
407 " } else {\n");
408 if (UseUnknownFieldSet(descriptor_->file(), options_)) {
409 format(
410 " mutable_unknown_fields()->AddVarint(\n"
411 " $number$, static_cast<$uint64$>(value));\n");
412 } else {
413 format(
414 " unknown_fields_stream.WriteVarint32(tag);\n"
415 " unknown_fields_stream.WriteVarint32(\n"
416 " static_cast<$uint32$>(value));\n");
417 }
418 format(" }\n");
419 }
420 format(
421 "}\n"
422 "input->PopLimit(limit);\n");
423 }
424 }
425
GenerateSerializeWithCachedSizes(io::Printer * printer) const426 void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizes(
427 io::Printer* printer) const {
428 Formatter format(printer, variables_);
429 if (descriptor_->is_packed()) {
430 // Write the tag and the size.
431 format(
432 "if (this->$name$_size() > 0) {\n"
433 " ::$proto_ns$::internal::WireFormatLite::WriteTag(\n"
434 " $number$,\n"
435 " "
436 "::$proto_ns$::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
437 " output);\n"
438 " output->WriteVarint32(_$name$_cached_byte_size_.load(\n"
439 " std::memory_order_relaxed));\n"
440 "}\n");
441 }
442 format("for (int i = 0, n = this->$name$_size(); i < n; i++) {\n");
443 if (descriptor_->is_packed()) {
444 format(
445 " ::$proto_ns$::internal::WireFormatLite::WriteEnumNoTag(\n"
446 " this->$name$(i), output);\n");
447 } else {
448 format(
449 " ::$proto_ns$::internal::WireFormatLite::WriteEnum(\n"
450 " $number$, this->$name$(i), output);\n");
451 }
452 format("}\n");
453 }
454
GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const455 void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizesToArray(
456 io::Printer* printer) const {
457 Formatter format(printer, variables_);
458 if (descriptor_->is_packed()) {
459 // Write the tag and the size.
460 format(
461 "if (this->$name$_size() > 0) {\n"
462 " target = ::$proto_ns$::internal::WireFormatLite::WriteTagToArray(\n"
463 " $number$,\n"
464 " "
465 "::$proto_ns$::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
466 " target);\n"
467 " target = ::$proto_ns$::io::CodedOutputStream::WriteVarint32ToArray("
468 " _$name$_cached_byte_size_.load(std::memory_order_relaxed),\n"
469 " target);\n"
470 " target = "
471 "::$proto_ns$::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
472 " this->$name$_, target);\n"
473 "}\n");
474 } else {
475 format(
476 "target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n"
477 " $number$, this->$name$_, target);\n");
478 }
479 }
480
GenerateByteSize(io::Printer * printer) const481 void RepeatedEnumFieldGenerator::GenerateByteSize(io::Printer* printer) const {
482 Formatter format(printer, variables_);
483 format(
484 "{\n"
485 " size_t data_size = 0;\n"
486 " unsigned int count = static_cast<unsigned int>(this->$name$_size());");
487 format.Indent();
488 format(
489 "for (unsigned int i = 0; i < count; i++) {\n"
490 " data_size += ::$proto_ns$::internal::WireFormatLite::EnumSize(\n"
491 " this->$name$(static_cast<int>(i)));\n"
492 "}\n");
493
494 if (descriptor_->is_packed()) {
495 format(
496 "if (data_size > 0) {\n"
497 " total_size += $tag_size$ +\n"
498 " ::$proto_ns$::internal::WireFormatLite::Int32Size(\n"
499 " static_cast<$int32$>(data_size));\n"
500 "}\n"
501 "int cached_size = ::$proto_ns$::internal::ToCachedSize(data_size);\n"
502 "_$name$_cached_byte_size_.store(cached_size,\n"
503 " std::memory_order_relaxed);\n"
504 "total_size += data_size;\n");
505 } else {
506 format("total_size += ($tag_size$UL * count) + data_size;\n");
507 }
508 format.Outdent();
509 format("}\n");
510 }
511
512 } // namespace cpp
513 } // namespace compiler
514 } // namespace protobuf
515 } // namespace google
516