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#include <google/protobuf/wire_format.h>
40
41namespace google {
42namespace protobuf {
43namespace compiler {
44namespace cpp {
45
46namespace {
47
48void SetEnumVariables(const FieldDescriptor* descriptor,
49                      map<string, string>* variables,
50                      const Options& options) {
51  SetCommonFieldVariables(descriptor, variables, options);
52  const EnumValueDescriptor* default_value = descriptor->default_value_enum();
53  (*variables)["type"] = ClassName(descriptor->enum_type(), true);
54  (*variables)["default"] = Int32ToString(default_value->number());
55  (*variables)["full_name"] = descriptor->full_name();
56}
57
58}  // namespace
59
60// ===================================================================
61
62EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
63                                       const Options& options)
64    : FieldGenerator(options), descriptor_(descriptor) {
65  SetEnumVariables(descriptor, &variables_, options);
66}
67
68EnumFieldGenerator::~EnumFieldGenerator() {}
69
70void EnumFieldGenerator::
71GeneratePrivateMembers(io::Printer* printer) const {
72  printer->Print(variables_, "int $name$_;\n");
73}
74
75void EnumFieldGenerator::
76GenerateAccessorDeclarations(io::Printer* printer) const {
77  printer->Print(variables_,
78    "$deprecated_attr$$type$ $name$() const;\n"
79    "$deprecated_attr$void set_$name$($type$ value);\n");
80}
81
82void EnumFieldGenerator::
83GenerateInlineAccessorDefinitions(io::Printer* printer,
84                                  bool is_inline) const {
85  map<string, string> variables(variables_);
86  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    "$inline$ void $classname$::set_$name$($type$ value) {\n");
93  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
94    printer->Print(variables,
95    "  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    "}\n");
102}
103
104void EnumFieldGenerator::
105GenerateClearingCode(io::Printer* printer) const {
106  printer->Print(variables_, "$name$_ = $default$;\n");
107}
108
109void EnumFieldGenerator::
110GenerateMergingCode(io::Printer* printer) const {
111  printer->Print(variables_, "set_$name$(from.$name$());\n");
112}
113
114void EnumFieldGenerator::
115GenerateSwappingCode(io::Printer* printer) const {
116  printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
117}
118
119void EnumFieldGenerator::
120GenerateConstructorCode(io::Printer* printer) const {
121  printer->Print(variables_, "$name$_ = $default$;\n");
122}
123
124void EnumFieldGenerator::
125GenerateMergeFromCodedStream(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    "       input, &value)));\n");
131  if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
132    printer->Print(variables_,
133      "set_$name$(static_cast< $type$ >(value));\n");
134  } else {
135    printer->Print(variables_,
136      "if ($type$_IsValid(value)) {\n"
137      "  set_$name$(static_cast< $type$ >(value));\n");
138    if (UseUnknownFieldSet(descriptor_->file(), options_)) {
139      printer->Print(variables_,
140        "} else {\n"
141        "  mutable_unknown_fields()->AddVarint($number$, value);\n");
142    } else {
143      printer->Print(
144        "} else {\n"
145        "  unknown_fields_stream.WriteVarint32($tag$);\n"
146        "  unknown_fields_stream.WriteVarint32(value);\n",
147        "tag", SimpleItoa(internal::WireFormat::MakeTag(descriptor_)));
148    }
149    printer->Print(variables_,
150      "}\n");
151  }
152}
153
154void EnumFieldGenerator::
155GenerateSerializeWithCachedSizes(io::Printer* printer) const {
156  printer->Print(variables_,
157    "::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
158    "  $number$, this->$name$(), output);\n");
159}
160
161void EnumFieldGenerator::
162GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
163  printer->Print(variables_,
164    "target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
165    "  $number$, this->$name$(), target);\n");
166}
167
168void EnumFieldGenerator::
169GenerateByteSize(io::Printer* printer) const {
170  printer->Print(variables_,
171    "total_size += $tag_size$ +\n"
172    "  ::google::protobuf::internal::WireFormatLite::EnumSize(this->$name$());\n");
173}
174
175// ===================================================================
176
177EnumOneofFieldGenerator::
178EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
179                        const Options& options)
180  : EnumFieldGenerator(descriptor, options) {
181  SetCommonOneofFieldVariables(descriptor, &variables_);
182}
183
184EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
185
186void EnumOneofFieldGenerator::
187GenerateInlineAccessorDefinitions(io::Printer* printer,
188                                  bool is_inline) const {
189  map<string, string> variables(variables_);
190  variables["inline"] = is_inline ? "inline" : "";
191  printer->Print(variables,
192    "$inline$ $type$ $classname$::$name$() const {\n"
193    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
194    "  if (has_$name$()) {\n"
195    "    return static_cast< $type$ >($oneof_prefix$$name$_);\n"
196    "  }\n"
197    "  return static_cast< $type$ >($default$);\n"
198    "}\n"
199    "$inline$ void $classname$::set_$name$($type$ value) {\n");
200  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
201    printer->Print(variables,
202    "  assert($type$_IsValid(value));\n");
203  }
204  printer->Print(variables,
205    "  if (!has_$name$()) {\n"
206    "    clear_$oneof_name$();\n"
207    "    set_has_$name$();\n"
208    "  }\n"
209    "  $oneof_prefix$$name$_ = value;\n"
210    "  // @@protoc_insertion_point(field_set:$full_name$)\n"
211    "}\n");
212}
213
214void EnumOneofFieldGenerator::
215GenerateClearingCode(io::Printer* printer) const {
216  printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
217}
218
219void EnumOneofFieldGenerator::
220GenerateSwappingCode(io::Printer* printer) const {
221  // Don't print any swapping code. Swapping the union will swap this field.
222}
223
224void EnumOneofFieldGenerator::
225GenerateConstructorCode(io::Printer* printer) const {
226  printer->Print(variables_,
227    "  $classname$_default_oneof_instance_->$name$_ = $default$;\n");
228}
229
230// ===================================================================
231
232RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
233    const FieldDescriptor* descriptor, const Options& options)
234    : FieldGenerator(options), descriptor_(descriptor) {
235  SetEnumVariables(descriptor, &variables_, options);
236}
237
238RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
239
240void RepeatedEnumFieldGenerator::
241GeneratePrivateMembers(io::Printer* printer) const {
242  printer->Print(variables_,
243    "::google::protobuf::RepeatedField<int> $name$_;\n");
244  if (descriptor_->is_packed() &&
245      HasGeneratedMethods(descriptor_->file(), options_)) {
246    printer->Print(variables_,
247      "mutable int _$name$_cached_byte_size_;\n");
248  }
249}
250
251void RepeatedEnumFieldGenerator::
252GenerateAccessorDeclarations(io::Printer* printer) const {
253  printer->Print(variables_,
254    "$deprecated_attr$$type$ $name$(int index) const;\n"
255    "$deprecated_attr$void set_$name$(int index, $type$ value);\n"
256    "$deprecated_attr$void add_$name$($type$ value);\n");
257  printer->Print(variables_,
258    "$deprecated_attr$const ::google::protobuf::RepeatedField<int>& $name$() const;\n"
259    "$deprecated_attr$::google::protobuf::RepeatedField<int>* mutable_$name$();\n");
260}
261
262void RepeatedEnumFieldGenerator::
263GenerateInlineAccessorDefinitions(io::Printer* printer,
264                                  bool is_inline) const {
265  map<string, string> variables(variables_);
266  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    "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n");
273  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
274    printer->Print(variables,
275    "  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    "$inline$ void $classname$::add_$name$($type$ value) {\n");
282  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
283    printer->Print(variables,
284    "  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    "}\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    "}\n");
301}
302
303void RepeatedEnumFieldGenerator::
304GenerateClearingCode(io::Printer* printer) const {
305  printer->Print(variables_, "$name$_.Clear();\n");
306}
307
308void RepeatedEnumFieldGenerator::
309GenerateMergingCode(io::Printer* printer) const {
310  printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
311}
312
313void RepeatedEnumFieldGenerator::
314GenerateSwappingCode(io::Printer* printer) const {
315  printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
316}
317
318void RepeatedEnumFieldGenerator::
319GenerateConstructorCode(io::Printer* printer) const {
320  // Not needed for repeated fields.
321}
322
323void RepeatedEnumFieldGenerator::
324GenerateMergeFromCodedStream(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    "       input, &value)));\n");
331  if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
332    printer->Print(variables_,
333      "add_$name$(static_cast< $type$ >(value));\n");
334  } else {
335    printer->Print(variables_,
336      "if ($type$_IsValid(value)) {\n"
337      "  add_$name$(static_cast< $type$ >(value));\n");
338    if (UseUnknownFieldSet(descriptor_->file(), options_)) {
339      printer->Print(variables_,
340        "} else {\n"
341        "  mutable_unknown_fields()->AddVarint($number$, value);\n");
342    } else {
343      printer->Print(
344        "} else {\n"
345        "  unknown_fields_stream.WriteVarint32(tag);\n"
346        "  unknown_fields_stream.WriteVarint32(value);\n");
347    }
348    printer->Print("}\n");
349  }
350}
351
352void RepeatedEnumFieldGenerator::
353GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
354  if (!descriptor_->is_packed()) {
355      // This path is rarely executed, so we use a non-inlined implementation.
356    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        "       this->mutable_$name$())));\n");
365    } else if (UseUnknownFieldSet(descriptor_->file(), options_)) {
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        "       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        "       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      "       input, &value)));\n");
394    if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
395      printer->Print(variables_,
396      "  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      "  } else {\n");
402      if (UseUnknownFieldSet(descriptor_->file(), options_)) {
403        printer->Print(variables_,
404        "    mutable_unknown_fields()->AddVarint($number$, value);\n");
405      } else {
406        printer->Print(variables_,
407        "    unknown_fields_stream.WriteVarint32(tag);\n"
408        "    unknown_fields_stream.WriteVarint32(value);\n");
409      }
410      printer->Print(
411      "  }\n");
412    }
413    printer->Print(variables_,
414      "}\n"
415      "input->PopLimit(limit);\n");
416  }
417}
418
419void RepeatedEnumFieldGenerator::
420GenerateSerializeWithCachedSizes(io::Printer* printer) const {
421  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      "}\n");
431  }
432  printer->Print(variables_,
433      "for (int i = 0; i < this->$name$_size(); i++) {\n");
434  if (descriptor_->is_packed()) {
435    printer->Print(variables_,
436      "  ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n"
437      "    this->$name$(i), output);\n");
438  } else {
439    printer->Print(variables_,
440      "  ::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
441      "    $number$, this->$name$(i), output);\n");
442  }
443  printer->Print("}\n");
444}
445
446void RepeatedEnumFieldGenerator::
447GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
448  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      "}\n");
459  }
460  printer->Print(variables_,
461      "for (int i = 0; i < this->$name$_size(); i++) {\n");
462  if (descriptor_->is_packed()) {
463    printer->Print(variables_,
464      "  target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
465      "    this->$name$(i), target);\n");
466  } else {
467    printer->Print(variables_,
468      "  target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
469      "    $number$, this->$name$(i), target);\n");
470  }
471  printer->Print("}\n");
472}
473
474void RepeatedEnumFieldGenerator::
475GenerateByteSize(io::Printer* printer) const {
476  printer->Print(variables_,
477    "{\n"
478    "  int data_size = 0;\n");
479  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      "}\n");
485
486  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      "total_size += data_size;\n");
496  } else {
497    printer->Print(variables_,
498      "total_size += $tag_size$ * this->$name$_size() + data_size;\n");
499  }
500  printer->Outdent();
501  printer->Print("}\n");
502}
503
504}  // namespace cpp
505}  // namespace compiler
506}  // namespace protobuf
507}  // namespace google
508