• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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