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