1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://code.google.com/p/protobuf/
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/descriptor.pb.h>
39#include <google/protobuf/stubs/strutil.h>
40
41namespace google {
42namespace protobuf {
43namespace compiler {
44namespace cpp {
45
46namespace {
47
48void SetEnumVariables(const FieldDescriptor* descriptor,
49                      map<string, string>* variables) {
50  SetCommonFieldVariables(descriptor, variables);
51  const EnumValueDescriptor* default_value = descriptor->default_value_enum();
52  (*variables)["type"] = ClassName(descriptor->enum_type(), true);
53  (*variables)["default"] = SimpleItoa(default_value->number());
54}
55
56}  // namespace
57
58// ===================================================================
59
60EnumFieldGenerator::
61EnumFieldGenerator(const FieldDescriptor* descriptor)
62  : descriptor_(descriptor) {
63  SetEnumVariables(descriptor, &variables_);
64}
65
66EnumFieldGenerator::~EnumFieldGenerator() {}
67
68void EnumFieldGenerator::
69GeneratePrivateMembers(io::Printer* printer) const {
70  printer->Print(variables_, "int $name$_;\n");
71}
72
73void EnumFieldGenerator::
74GenerateAccessorDeclarations(io::Printer* printer) const {
75  printer->Print(variables_,
76    "inline $type$ $name$() const$deprecation$;\n"
77    "inline void set_$name$($type$ value)$deprecation$;\n");
78}
79
80void EnumFieldGenerator::
81GenerateInlineAccessorDefinitions(io::Printer* printer) const {
82  printer->Print(variables_,
83    "inline $type$ $classname$::$name$() const {\n"
84    "  return static_cast< $type$ >($name$_);\n"
85    "}\n"
86    "inline void $classname$::set_$name$($type$ value) {\n"
87    "  GOOGLE_DCHECK($type$_IsValid(value));\n"
88    "  _set_bit($index$);\n"
89    "  $name$_ = value;\n"
90    "}\n");
91}
92
93void EnumFieldGenerator::
94GenerateClearingCode(io::Printer* printer) const {
95  printer->Print(variables_, "$name$_ = $default$;\n");
96}
97
98void EnumFieldGenerator::
99GenerateMergingCode(io::Printer* printer) const {
100  printer->Print(variables_, "set_$name$(from.$name$());\n");
101}
102
103void EnumFieldGenerator::
104GenerateSwappingCode(io::Printer* printer) const {
105  printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
106}
107
108void EnumFieldGenerator::
109GenerateConstructorCode(io::Printer* printer) const {
110  printer->Print(variables_, "$name$_ = $default$;\n");
111}
112
113void EnumFieldGenerator::
114GenerateMergeFromCodedStream(io::Printer* printer) const {
115  printer->Print(variables_,
116    "int value;\n"
117    "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
118    "         int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
119    "       input, &value)));\n"
120    "if ($type$_IsValid(value)) {\n"
121    "  set_$name$(static_cast< $type$ >(value));\n");
122  if (HasUnknownFields(descriptor_->file())) {
123    printer->Print(variables_,
124      "} else {\n"
125      "  mutable_unknown_fields()->AddVarint($number$, value);\n");
126  }
127  printer->Print(variables_,
128    "}\n");
129}
130
131void EnumFieldGenerator::
132GenerateSerializeWithCachedSizes(io::Printer* printer) const {
133  printer->Print(variables_,
134    "::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
135    "  $number$, this->$name$(), output);\n");
136}
137
138void EnumFieldGenerator::
139GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
140  printer->Print(variables_,
141    "target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
142    "  $number$, this->$name$(), target);\n");
143}
144
145void EnumFieldGenerator::
146GenerateByteSize(io::Printer* printer) const {
147  printer->Print(variables_,
148    "total_size += $tag_size$ +\n"
149    "  ::google::protobuf::internal::WireFormatLite::EnumSize(this->$name$());\n");
150}
151
152// ===================================================================
153
154RepeatedEnumFieldGenerator::
155RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor)
156  : descriptor_(descriptor) {
157  SetEnumVariables(descriptor, &variables_);
158}
159
160RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
161
162void RepeatedEnumFieldGenerator::
163GeneratePrivateMembers(io::Printer* printer) const {
164  printer->Print(variables_,
165    "::google::protobuf::RepeatedField<int> $name$_;\n");
166  if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
167    printer->Print(variables_,
168      "mutable int _$name$_cached_byte_size_;\n");
169  }
170}
171
172void RepeatedEnumFieldGenerator::
173GenerateAccessorDeclarations(io::Printer* printer) const {
174  printer->Print(variables_,
175    "inline $type$ $name$(int index) const$deprecation$;\n"
176    "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
177    "inline void add_$name$($type$ value)$deprecation$;\n");
178  printer->Print(variables_,
179    "inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
180    "inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n");
181}
182
183void RepeatedEnumFieldGenerator::
184GenerateInlineAccessorDefinitions(io::Printer* printer) const {
185  printer->Print(variables_,
186    "inline $type$ $classname$::$name$(int index) const {\n"
187    "  return static_cast< $type$ >($name$_.Get(index));\n"
188    "}\n"
189    "inline void $classname$::set_$name$(int index, $type$ value) {\n"
190    "  GOOGLE_DCHECK($type$_IsValid(value));\n"
191    "  $name$_.Set(index, value);\n"
192    "}\n"
193    "inline void $classname$::add_$name$($type$ value) {\n"
194    "  GOOGLE_DCHECK($type$_IsValid(value));\n"
195    "  $name$_.Add(value);\n"
196    "}\n");
197  printer->Print(variables_,
198    "inline const ::google::protobuf::RepeatedField<int>&\n"
199    "$classname$::$name$() const {\n"
200    "  return $name$_;\n"
201    "}\n"
202    "inline ::google::protobuf::RepeatedField<int>*\n"
203    "$classname$::mutable_$name$() {\n"
204    "  return &$name$_;\n"
205    "}\n");
206}
207
208void RepeatedEnumFieldGenerator::
209GenerateClearingCode(io::Printer* printer) const {
210  printer->Print(variables_, "$name$_.Clear();\n");
211}
212
213void RepeatedEnumFieldGenerator::
214GenerateMergingCode(io::Printer* printer) const {
215  printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
216}
217
218void RepeatedEnumFieldGenerator::
219GenerateSwappingCode(io::Printer* printer) const {
220  printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
221}
222
223void RepeatedEnumFieldGenerator::
224GenerateConstructorCode(io::Printer* printer) const {
225  // Not needed for repeated fields.
226}
227
228void RepeatedEnumFieldGenerator::
229GenerateMergeFromCodedStream(io::Printer* printer) const {
230  // Don't use ReadRepeatedPrimitive here so that the enum can be validated.
231  printer->Print(variables_,
232    "int value;\n"
233    "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
234    "         int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
235    "       input, &value)));\n"
236    "if ($type$_IsValid(value)) {\n"
237    "  add_$name$(static_cast< $type$ >(value));\n");
238  if (HasUnknownFields(descriptor_->file())) {
239    printer->Print(variables_,
240      "} else {\n"
241      "  mutable_unknown_fields()->AddVarint($number$, value);\n");
242  }
243  printer->Print("}\n");
244}
245
246void RepeatedEnumFieldGenerator::
247GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
248  if (!descriptor_->options().packed()) {
249    // We use a non-inlined implementation in this case, since this path will
250    // rarely be executed.
251    printer->Print(variables_,
252      "DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n"
253      "       input,\n"
254      "       &$type$_IsValid,\n"
255      "       this->mutable_$name$())));\n");
256  } else {
257    printer->Print(variables_,
258      "::google::protobuf::uint32 length;\n"
259      "DO_(input->ReadVarint32(&length));\n"
260      "::google::protobuf::io::CodedInputStream::Limit limit = "
261          "input->PushLimit(length);\n"
262      "while (input->BytesUntilLimit() > 0) {\n"
263      "  int value;\n"
264      "  DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
265      "         int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
266      "       input, &value)));\n"
267      "  if ($type$_IsValid(value)) {\n"
268      "    add_$name$(static_cast< $type$ >(value));\n"
269      "  }\n"
270      "}\n"
271      "input->PopLimit(limit);\n");
272  }
273}
274
275void RepeatedEnumFieldGenerator::
276GenerateSerializeWithCachedSizes(io::Printer* printer) const {
277  if (descriptor_->options().packed()) {
278    // Write the tag and the size.
279    printer->Print(variables_,
280      "if (this->$name$_size() > 0) {\n"
281      "  ::google::protobuf::internal::WireFormatLite::WriteTag(\n"
282      "    $number$,\n"
283      "    ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
284      "    output);\n"
285      "  output->WriteVarint32(_$name$_cached_byte_size_);\n"
286      "}\n");
287  }
288  printer->Print(variables_,
289      "for (int i = 0; i < this->$name$_size(); i++) {\n");
290  if (descriptor_->options().packed()) {
291    printer->Print(variables_,
292      "  ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n"
293      "    this->$name$(i), output);\n");
294  } else {
295    printer->Print(variables_,
296      "  ::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
297      "    $number$, this->$name$(i), output);\n");
298  }
299  printer->Print("}\n");
300}
301
302void RepeatedEnumFieldGenerator::
303GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
304  if (descriptor_->options().packed()) {
305    // Write the tag and the size.
306    printer->Print(variables_,
307      "if (this->$name$_size() > 0) {\n"
308      "  target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
309      "    $number$,\n"
310      "    ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
311      "    target);\n"
312      "  target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray("
313      "    _$name$_cached_byte_size_, target);\n"
314      "}\n");
315  }
316  printer->Print(variables_,
317      "for (int i = 0; i < this->$name$_size(); i++) {\n");
318  if (descriptor_->options().packed()) {
319    printer->Print(variables_,
320      "  target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
321      "    this->$name$(i), target);\n");
322  } else {
323    printer->Print(variables_,
324      "  target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
325      "    $number$, this->$name$(i), target);\n");
326  }
327  printer->Print("}\n");
328}
329
330void RepeatedEnumFieldGenerator::
331GenerateByteSize(io::Printer* printer) const {
332  printer->Print(variables_,
333    "{\n"
334    "  int data_size = 0;\n");
335  printer->Indent();
336  printer->Print(variables_,
337      "for (int i = 0; i < this->$name$_size(); i++) {\n"
338      "  data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(\n"
339      "    this->$name$(i));\n"
340      "}\n");
341
342  if (descriptor_->options().packed()) {
343    printer->Print(variables_,
344      "if (data_size > 0) {\n"
345      "  total_size += $tag_size$ +\n"
346      "    ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
347      "}\n"
348      "_$name$_cached_byte_size_ = data_size;\n"
349      "total_size += data_size;\n");
350  } else {
351    printer->Print(variables_,
352      "total_size += $tag_size$ * this->$name$_size() + data_size;\n");
353  }
354  printer->Outdent();
355  printer->Print("}\n");
356}
357
358}  // namespace cpp
359}  // namespace compiler
360}  // namespace protobuf
361}  // namespace google
362