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/descriptor.pb.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,map<string,string> * variables,const Options & options)48 void 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 
62 EnumFieldGenerator::
EnumFieldGenerator(const FieldDescriptor * descriptor,const Options & options)63 EnumFieldGenerator(const FieldDescriptor* descriptor,
64                    const Options& options)
65   : descriptor_(descriptor) {
66   SetEnumVariables(descriptor, &variables_, options);
67 }
68 
~EnumFieldGenerator()69 EnumFieldGenerator::~EnumFieldGenerator() {}
70 
71 void EnumFieldGenerator::
GeneratePrivateMembers(io::Printer * printer) const72 GeneratePrivateMembers(io::Printer* printer) const {
73   printer->Print(variables_, "int $name$_;\n");
74 }
75 
76 void EnumFieldGenerator::
GenerateAccessorDeclarations(io::Printer * printer) const77 GenerateAccessorDeclarations(io::Printer* printer) const {
78   printer->Print(variables_,
79     "inline $type$ $name$() const$deprecation$;\n"
80     "inline void set_$name$($type$ value)$deprecation$;\n");
81 }
82 
83 void EnumFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer * printer) const84 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
85   printer->Print(variables_,
86     "inline $type$ $classname$::$name$() const {\n"
87     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
88     "  return static_cast< $type$ >($name$_);\n"
89     "}\n"
90     "inline void $classname$::set_$name$($type$ value) {\n"
91     "  assert($type$_IsValid(value));\n"
92     "  set_has_$name$();\n"
93     "  $name$_ = value;\n"
94     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
95     "}\n");
96 }
97 
98 void EnumFieldGenerator::
GenerateClearingCode(io::Printer * printer) const99 GenerateClearingCode(io::Printer* printer) const {
100   printer->Print(variables_, "$name$_ = $default$;\n");
101 }
102 
103 void EnumFieldGenerator::
GenerateMergingCode(io::Printer * printer) const104 GenerateMergingCode(io::Printer* printer) const {
105   printer->Print(variables_, "set_$name$(from.$name$());\n");
106 }
107 
108 void EnumFieldGenerator::
GenerateSwappingCode(io::Printer * printer) const109 GenerateSwappingCode(io::Printer* printer) const {
110   printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
111 }
112 
113 void EnumFieldGenerator::
GenerateConstructorCode(io::Printer * printer) const114 GenerateConstructorCode(io::Printer* printer) const {
115   printer->Print(variables_, "$name$_ = $default$;\n");
116 }
117 
118 void EnumFieldGenerator::
GenerateMergeFromCodedStream(io::Printer * printer) const119 GenerateMergeFromCodedStream(io::Printer* printer) const {
120   printer->Print(variables_,
121     "int value;\n"
122     "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
123     "         int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
124     "       input, &value)));\n"
125     "if ($type$_IsValid(value)) {\n"
126     "  set_$name$(static_cast< $type$ >(value));\n");
127   if (UseUnknownFieldSet(descriptor_->file())) {
128     printer->Print(variables_,
129       "} else {\n"
130       "  mutable_unknown_fields()->AddVarint($number$, value);\n");
131   } else {
132     printer->Print(
133       "} else {\n"
134       "  unknown_fields_stream.WriteVarint32(tag);\n"
135       "  unknown_fields_stream.WriteVarint32(value);\n");
136   }
137   printer->Print(variables_,
138     "}\n");
139 }
140 
141 void EnumFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer * printer) const142 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
143   printer->Print(variables_,
144     "::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
145     "  $number$, this->$name$(), output);\n");
146 }
147 
148 void EnumFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const149 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
150   printer->Print(variables_,
151     "target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
152     "  $number$, this->$name$(), target);\n");
153 }
154 
155 void EnumFieldGenerator::
GenerateByteSize(io::Printer * printer) const156 GenerateByteSize(io::Printer* printer) const {
157   printer->Print(variables_,
158     "total_size += $tag_size$ +\n"
159     "  ::google::protobuf::internal::WireFormatLite::EnumSize(this->$name$());\n");
160 }
161 
162 // ===================================================================
163 
164 EnumOneofFieldGenerator::
EnumOneofFieldGenerator(const FieldDescriptor * descriptor,const Options & options)165 EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
166                         const Options& options)
167   : EnumFieldGenerator(descriptor, options) {
168   SetCommonOneofFieldVariables(descriptor, &variables_);
169 }
170 
~EnumOneofFieldGenerator()171 EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
172 
173 void EnumOneofFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer * printer) const174 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
175   printer->Print(variables_,
176     "inline $type$ $classname$::$name$() const {\n"
177     "  if (has_$name$()) {\n"
178     "    return static_cast< $type$ >($oneof_prefix$$name$_);\n"
179     "  }\n"
180     "  return static_cast< $type$ >($default$);\n"
181     "}\n"
182     "inline void $classname$::set_$name$($type$ value) {\n"
183     "  assert($type$_IsValid(value));\n"
184     "  if (!has_$name$()) {\n"
185     "    clear_$oneof_name$();\n"
186     "    set_has_$name$();\n"
187     "  }\n"
188     "  $oneof_prefix$$name$_ = value;\n"
189     "}\n");
190 }
191 
192 void EnumOneofFieldGenerator::
GenerateClearingCode(io::Printer * printer) const193 GenerateClearingCode(io::Printer* printer) const {
194   printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
195 }
196 
197 void EnumOneofFieldGenerator::
GenerateSwappingCode(io::Printer * printer) const198 GenerateSwappingCode(io::Printer* printer) const {
199   // Don't print any swapping code. Swapping the union will swap this field.
200 }
201 
202 void EnumOneofFieldGenerator::
GenerateConstructorCode(io::Printer * printer) const203 GenerateConstructorCode(io::Printer* printer) const {
204   printer->Print(variables_,
205     "  $classname$_default_oneof_instance_->$name$_ = $default$;\n");
206 }
207 
208 // ===================================================================
209 
210 RepeatedEnumFieldGenerator::
RepeatedEnumFieldGenerator(const FieldDescriptor * descriptor,const Options & options)211 RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
212                            const Options& options)
213   : descriptor_(descriptor) {
214   SetEnumVariables(descriptor, &variables_, options);
215 }
216 
~RepeatedEnumFieldGenerator()217 RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
218 
219 void RepeatedEnumFieldGenerator::
GeneratePrivateMembers(io::Printer * printer) const220 GeneratePrivateMembers(io::Printer* printer) const {
221   printer->Print(variables_,
222     "::google::protobuf::RepeatedField<int> $name$_;\n");
223   if (descriptor_->options().packed()
224       && HasGeneratedMethods(descriptor_->file())) {
225     printer->Print(variables_,
226       "mutable int _$name$_cached_byte_size_;\n");
227   }
228 }
229 
230 void RepeatedEnumFieldGenerator::
GenerateAccessorDeclarations(io::Printer * printer) const231 GenerateAccessorDeclarations(io::Printer* printer) const {
232   printer->Print(variables_,
233     "inline $type$ $name$(int index) const$deprecation$;\n"
234     "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
235     "inline void add_$name$($type$ value)$deprecation$;\n");
236   printer->Print(variables_,
237     "inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
238     "inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n");
239 }
240 
241 void RepeatedEnumFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer * printer) const242 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
243   printer->Print(variables_,
244     "inline $type$ $classname$::$name$(int index) const {\n"
245     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
246     "  return static_cast< $type$ >($name$_.Get(index));\n"
247     "}\n"
248     "inline void $classname$::set_$name$(int index, $type$ value) {\n"
249     "  assert($type$_IsValid(value));\n"
250     "  $name$_.Set(index, value);\n"
251     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
252     "}\n"
253     "inline void $classname$::add_$name$($type$ value) {\n"
254     "  assert($type$_IsValid(value));\n"
255     "  $name$_.Add(value);\n"
256     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
257     "}\n");
258   printer->Print(variables_,
259     "inline const ::google::protobuf::RepeatedField<int>&\n"
260     "$classname$::$name$() const {\n"
261     "  // @@protoc_insertion_point(field_list:$full_name$)\n"
262     "  return $name$_;\n"
263     "}\n"
264     "inline ::google::protobuf::RepeatedField<int>*\n"
265     "$classname$::mutable_$name$() {\n"
266     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
267     "  return &$name$_;\n"
268     "}\n");
269 }
270 
271 void RepeatedEnumFieldGenerator::
GenerateClearingCode(io::Printer * printer) const272 GenerateClearingCode(io::Printer* printer) const {
273   printer->Print(variables_, "$name$_.Clear();\n");
274 }
275 
276 void RepeatedEnumFieldGenerator::
GenerateMergingCode(io::Printer * printer) const277 GenerateMergingCode(io::Printer* printer) const {
278   printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
279 }
280 
281 void RepeatedEnumFieldGenerator::
GenerateSwappingCode(io::Printer * printer) const282 GenerateSwappingCode(io::Printer* printer) const {
283   printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
284 }
285 
286 void RepeatedEnumFieldGenerator::
GenerateConstructorCode(io::Printer * printer) const287 GenerateConstructorCode(io::Printer* printer) const {
288   // Not needed for repeated fields.
289 }
290 
291 void RepeatedEnumFieldGenerator::
GenerateMergeFromCodedStream(io::Printer * printer) const292 GenerateMergeFromCodedStream(io::Printer* printer) const {
293   // Don't use ReadRepeatedPrimitive here so that the enum can be validated.
294   printer->Print(variables_,
295     "int value;\n"
296     "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
297     "         int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
298     "       input, &value)));\n"
299     "if ($type$_IsValid(value)) {\n"
300     "  add_$name$(static_cast< $type$ >(value));\n");
301   if (UseUnknownFieldSet(descriptor_->file())) {
302     printer->Print(variables_,
303       "} else {\n"
304       "  mutable_unknown_fields()->AddVarint($number$, value);\n");
305   } else {
306     printer->Print(
307       "} else {\n"
308       "  unknown_fields_stream.WriteVarint32(tag);\n"
309       "  unknown_fields_stream.WriteVarint32(value);\n");
310   }
311   printer->Print("}\n");
312 }
313 
314 void RepeatedEnumFieldGenerator::
GenerateMergeFromCodedStreamWithPacking(io::Printer * printer) const315 GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
316   if (!descriptor_->options().packed()) {
317     // We use a non-inlined implementation in this case, since this path will
318     // rarely be executed.
319     printer->Print(variables_,
320       "DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n"
321       "       input,\n"
322       "       &$type$_IsValid,\n"
323       "       this->mutable_$name$())));\n");
324   } else {
325     printer->Print(variables_,
326       "::google::protobuf::uint32 length;\n"
327       "DO_(input->ReadVarint32(&length));\n"
328       "::google::protobuf::io::CodedInputStream::Limit limit = "
329           "input->PushLimit(length);\n"
330       "while (input->BytesUntilLimit() > 0) {\n"
331       "  int value;\n"
332       "  DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
333       "         int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
334       "       input, &value)));\n"
335       "  if ($type$_IsValid(value)) {\n"
336       "    add_$name$(static_cast< $type$ >(value));\n"
337       "  }\n"
338       "}\n"
339       "input->PopLimit(limit);\n");
340   }
341 }
342 
343 void RepeatedEnumFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer * printer) const344 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
345   if (descriptor_->options().packed()) {
346     // Write the tag and the size.
347     printer->Print(variables_,
348       "if (this->$name$_size() > 0) {\n"
349       "  ::google::protobuf::internal::WireFormatLite::WriteTag(\n"
350       "    $number$,\n"
351       "    ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
352       "    output);\n"
353       "  output->WriteVarint32(_$name$_cached_byte_size_);\n"
354       "}\n");
355   }
356   printer->Print(variables_,
357       "for (int i = 0; i < this->$name$_size(); i++) {\n");
358   if (descriptor_->options().packed()) {
359     printer->Print(variables_,
360       "  ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n"
361       "    this->$name$(i), output);\n");
362   } else {
363     printer->Print(variables_,
364       "  ::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
365       "    $number$, this->$name$(i), output);\n");
366   }
367   printer->Print("}\n");
368 }
369 
370 void RepeatedEnumFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const371 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
372   if (descriptor_->options().packed()) {
373     // Write the tag and the size.
374     printer->Print(variables_,
375       "if (this->$name$_size() > 0) {\n"
376       "  target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
377       "    $number$,\n"
378       "    ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
379       "    target);\n"
380       "  target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray("
381       "    _$name$_cached_byte_size_, target);\n"
382       "}\n");
383   }
384   printer->Print(variables_,
385       "for (int i = 0; i < this->$name$_size(); i++) {\n");
386   if (descriptor_->options().packed()) {
387     printer->Print(variables_,
388       "  target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
389       "    this->$name$(i), target);\n");
390   } else {
391     printer->Print(variables_,
392       "  target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
393       "    $number$, this->$name$(i), target);\n");
394   }
395   printer->Print("}\n");
396 }
397 
398 void RepeatedEnumFieldGenerator::
GenerateByteSize(io::Printer * printer) const399 GenerateByteSize(io::Printer* printer) const {
400   printer->Print(variables_,
401     "{\n"
402     "  int data_size = 0;\n");
403   printer->Indent();
404   printer->Print(variables_,
405       "for (int i = 0; i < this->$name$_size(); i++) {\n"
406       "  data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(\n"
407       "    this->$name$(i));\n"
408       "}\n");
409 
410   if (descriptor_->options().packed()) {
411     printer->Print(variables_,
412       "if (data_size > 0) {\n"
413       "  total_size += $tag_size$ +\n"
414       "    ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
415       "}\n"
416       "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
417       "_$name$_cached_byte_size_ = data_size;\n"
418       "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
419       "total_size += data_size;\n");
420   } else {
421     printer->Print(variables_,
422       "total_size += $tag_size$ * this->$name$_size() + data_size;\n");
423   }
424   printer->Outdent();
425   printer->Print("}\n");
426 }
427 
428 }  // namespace cpp
429 }  // namespace compiler
430 }  // namespace protobuf
431 }  // namespace google
432