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