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
37 #include <google/protobuf/io/printer.h>
38 #include <google/protobuf/wire_format.h>
39 #include <google/protobuf/stubs/strutil.h>
40 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
41
42 namespace google {
43 namespace protobuf {
44 namespace compiler {
45 namespace cpp {
46
47 namespace {
48
SetEnumVariables(const FieldDescriptor * descriptor,std::map<std::string,std::string> * variables,const Options & options)49 void SetEnumVariables(const FieldDescriptor* descriptor,
50 std::map<std::string, std::string>* variables,
51 const Options& options) {
52 SetCommonFieldVariables(descriptor, variables, options);
53 const EnumValueDescriptor* default_value = descriptor->default_value_enum();
54 (*variables)["type"] = QualifiedClassName(descriptor->enum_type(), options);
55 (*variables)["default"] = Int32ToString(default_value->number());
56 (*variables)["full_name"] = descriptor->full_name();
57 (*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(descriptor);
58 (*variables)["cached_byte_size_field"] =
59 MakeVarintCachedSizeFieldName(descriptor);
60 }
61
62 } // namespace
63
64 // ===================================================================
65
EnumFieldGenerator(const FieldDescriptor * descriptor,const Options & options)66 EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
67 const Options& options)
68 : FieldGenerator(descriptor, options) {
69 SetEnumVariables(descriptor, &variables_, options);
70 }
71
~EnumFieldGenerator()72 EnumFieldGenerator::~EnumFieldGenerator() {}
73
GeneratePrivateMembers(io::Printer * printer) const74 void EnumFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
75 Formatter format(printer, variables_);
76 format("int $name$_;\n");
77 }
78
GenerateAccessorDeclarations(io::Printer * printer) const79 void EnumFieldGenerator::GenerateAccessorDeclarations(
80 io::Printer* printer) const {
81 Formatter format(printer, variables_);
82 format(
83 "$deprecated_attr$$type$ ${1$$name$$}$() const;\n"
84 "$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n"
85 "private:\n"
86 "$type$ ${1$_internal_$name$$}$() const;\n"
87 "void ${1$_internal_set_$name$$}$($type$ value);\n"
88 "public:\n",
89 descriptor_);
90 }
91
GenerateInlineAccessorDefinitions(io::Printer * printer) const92 void EnumFieldGenerator::GenerateInlineAccessorDefinitions(
93 io::Printer* printer) const {
94 Formatter format(printer, variables_);
95 format(
96 "inline $type$ $classname$::_internal_$name$() const {\n"
97 " return static_cast< $type$ >($field$);\n"
98 "}\n"
99 "inline $type$ $classname$::$name$() const {\n"
100 "$annotate_get$"
101 " // @@protoc_insertion_point(field_get:$full_name$)\n"
102 " return _internal_$name$();\n"
103 "}\n"
104 "inline void $classname$::_internal_set_$name$($type$ value) {\n");
105 if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
106 format(" assert($type$_IsValid(value));\n");
107 }
108 format(
109 " $set_hasbit$\n"
110 " $field$ = value;\n"
111 "}\n"
112 "inline void $classname$::set_$name$($type$ value) {\n"
113 " _internal_set_$name$(value);\n"
114 "$annotate_set$"
115 " // @@protoc_insertion_point(field_set:$full_name$)\n"
116 "}\n");
117 }
118
GenerateClearingCode(io::Printer * printer) const119 void EnumFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
120 Formatter format(printer, variables_);
121 format("$field$ = $default$;\n");
122 }
123
GenerateMergingCode(io::Printer * printer) const124 void EnumFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
125 Formatter format(printer, variables_);
126 format("_internal_set_$name$(from._internal_$name$());\n");
127 }
128
GenerateSwappingCode(io::Printer * printer) const129 void EnumFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
130 Formatter format(printer, variables_);
131 format("swap($field$, other->$field$);\n");
132 }
133
GenerateConstructorCode(io::Printer * printer) const134 void EnumFieldGenerator::GenerateConstructorCode(io::Printer* printer) const {
135 Formatter format(printer, variables_);
136 format("$field$ = $default$;\n");
137 }
138
GenerateCopyConstructorCode(io::Printer * printer) const139 void EnumFieldGenerator::GenerateCopyConstructorCode(
140 io::Printer* printer) const {
141 Formatter format(printer, variables_);
142 format("$field$ = from.$field$;\n");
143 }
144
GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const145 void EnumFieldGenerator::GenerateSerializeWithCachedSizesToArray(
146 io::Printer* printer) const {
147 Formatter format(printer, variables_);
148 format(
149 "target = stream->EnsureSpace(target);\n"
150 "target = ::_pbi::WireFormatLite::WriteEnumToArray(\n"
151 " $number$, this->_internal_$name$(), target);\n");
152 }
153
GenerateByteSize(io::Printer * printer) const154 void EnumFieldGenerator::GenerateByteSize(io::Printer* printer) const {
155 Formatter format(printer, variables_);
156 format(
157 "total_size += $tag_size$ +\n"
158 " ::_pbi::WireFormatLite::EnumSize(this->_internal_$name$());\n");
159 }
160
GenerateConstinitInitializer(io::Printer * printer) const161 void EnumFieldGenerator::GenerateConstinitInitializer(
162 io::Printer* printer) const {
163 Formatter format(printer, variables_);
164 format("$name$_($default$)\n");
165 }
166
167 // ===================================================================
168
EnumOneofFieldGenerator(const FieldDescriptor * descriptor,const Options & options)169 EnumOneofFieldGenerator::EnumOneofFieldGenerator(
170 const FieldDescriptor* descriptor, const Options& options)
171 : EnumFieldGenerator(descriptor, options) {
172 SetCommonOneofFieldVariables(descriptor, &variables_);
173 }
174
~EnumOneofFieldGenerator()175 EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
176
GenerateInlineAccessorDefinitions(io::Printer * printer) const177 void EnumOneofFieldGenerator::GenerateInlineAccessorDefinitions(
178 io::Printer* printer) const {
179 Formatter format(printer, variables_);
180 format(
181 "inline $type$ $classname$::_internal_$name$() const {\n"
182 " if (_internal_has_$name$()) {\n"
183 " return static_cast< $type$ >($field$);\n"
184 " }\n"
185 " return static_cast< $type$ >($default$);\n"
186 "}\n"
187 "inline $type$ $classname$::$name$() const {\n"
188 "$annotate_get$"
189 " // @@protoc_insertion_point(field_get:$full_name$)\n"
190 " return _internal_$name$();\n"
191 "}\n"
192 "inline void $classname$::_internal_set_$name$($type$ value) {\n");
193 if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
194 format(" assert($type$_IsValid(value));\n");
195 }
196 format(
197 " if (!_internal_has_$name$()) {\n"
198 " clear_$oneof_name$();\n"
199 " set_has_$name$();\n"
200 " }\n"
201 " $field$ = value;\n"
202 "}\n"
203 "inline void $classname$::set_$name$($type$ value) {\n"
204 " _internal_set_$name$(value);\n"
205 "$annotate_set$"
206 " // @@protoc_insertion_point(field_set:$full_name$)\n"
207 "}\n");
208 }
209
GenerateClearingCode(io::Printer * printer) const210 void EnumOneofFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
211 Formatter format(printer, variables_);
212 format("$field$ = $default$;\n");
213 }
214
GenerateSwappingCode(io::Printer * printer) const215 void EnumOneofFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
216 // Don't print any swapping code. Swapping the union will swap this field.
217 }
218
GenerateConstructorCode(io::Printer * printer) const219 void EnumOneofFieldGenerator::GenerateConstructorCode(
220 io::Printer* printer) const {
221 Formatter format(printer, variables_);
222 format("$ns$::_$classname$_default_instance_.$field$ = $default$;\n");
223 }
224
225 // ===================================================================
226
RepeatedEnumFieldGenerator(const FieldDescriptor * descriptor,const Options & options)227 RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
228 const FieldDescriptor* descriptor, const Options& options)
229 : FieldGenerator(descriptor, options) {
230 SetEnumVariables(descriptor, &variables_, options);
231 }
232
~RepeatedEnumFieldGenerator()233 RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
234
GeneratePrivateMembers(io::Printer * printer) const235 void RepeatedEnumFieldGenerator::GeneratePrivateMembers(
236 io::Printer* printer) const {
237 Formatter format(printer, variables_);
238 format("::$proto_ns$::RepeatedField<int> $name$_;\n");
239 if (descriptor_->is_packed() &&
240 HasGeneratedMethods(descriptor_->file(), options_)) {
241 format("mutable std::atomic<int> $cached_byte_size_name$;\n");
242 }
243 }
244
GenerateAccessorDeclarations(io::Printer * printer) const245 void RepeatedEnumFieldGenerator::GenerateAccessorDeclarations(
246 io::Printer* printer) const {
247 Formatter format(printer, variables_);
248 format(
249 "private:\n"
250 "$type$ ${1$_internal_$name$$}$(int index) const;\n"
251 "void ${1$_internal_add_$name$$}$($type$ value);\n"
252 "::$proto_ns$::RepeatedField<int>* "
253 "${1$_internal_mutable_$name$$}$();\n"
254 "public:\n"
255 "$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n"
256 "$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n"
257 "$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n"
258 "$deprecated_attr$const ::$proto_ns$::RepeatedField<int>& "
259 "${1$$name$$}$() const;\n"
260 "$deprecated_attr$::$proto_ns$::RepeatedField<int>* "
261 "${1$mutable_$name$$}$();\n",
262 descriptor_);
263 }
264
GenerateInlineAccessorDefinitions(io::Printer * printer) const265 void RepeatedEnumFieldGenerator::GenerateInlineAccessorDefinitions(
266 io::Printer* printer) const {
267 Formatter format(printer, variables_);
268 format(
269 "inline $type$ $classname$::_internal_$name$(int index) const {\n"
270 " return static_cast< $type$ >($field$.Get(index));\n"
271 "}\n"
272 "inline $type$ $classname$::$name$(int index) const {\n"
273 "$annotate_get$"
274 " // @@protoc_insertion_point(field_get:$full_name$)\n"
275 " return _internal_$name$(index);\n"
276 "}\n"
277 "inline void $classname$::set_$name$(int index, $type$ value) {\n");
278 if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
279 format(" assert($type$_IsValid(value));\n");
280 }
281 format(
282 " $field$.Set(index, value);\n"
283 "$annotate_set$"
284 " // @@protoc_insertion_point(field_set:$full_name$)\n"
285 "}\n"
286 "inline void $classname$::_internal_add_$name$($type$ value) {\n");
287 if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
288 format(" assert($type$_IsValid(value));\n");
289 }
290 format(
291 " $field$.Add(value);\n"
292 "}\n"
293 "inline void $classname$::add_$name$($type$ value) {\n"
294 " _internal_add_$name$(value);\n"
295 "$annotate_add$"
296 " // @@protoc_insertion_point(field_add:$full_name$)\n"
297 "}\n"
298 "inline const ::$proto_ns$::RepeatedField<int>&\n"
299 "$classname$::$name$() const {\n"
300 "$annotate_list$"
301 " // @@protoc_insertion_point(field_list:$full_name$)\n"
302 " return $field$;\n"
303 "}\n"
304 "inline ::$proto_ns$::RepeatedField<int>*\n"
305 "$classname$::_internal_mutable_$name$() {\n"
306 " return &$field$;\n"
307 "}\n"
308 "inline ::$proto_ns$::RepeatedField<int>*\n"
309 "$classname$::mutable_$name$() {\n"
310 "$annotate_mutable_list$"
311 " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
312 " return _internal_mutable_$name$();\n"
313 "}\n");
314 }
315
GenerateClearingCode(io::Printer * printer) const316 void RepeatedEnumFieldGenerator::GenerateClearingCode(
317 io::Printer* printer) const {
318 Formatter format(printer, variables_);
319 format("$field$.Clear();\n");
320 }
321
GenerateMergingCode(io::Printer * printer) const322 void RepeatedEnumFieldGenerator::GenerateMergingCode(
323 io::Printer* printer) const {
324 Formatter format(printer, variables_);
325 format("$field$.MergeFrom(from.$field$);\n");
326 }
327
GenerateSwappingCode(io::Printer * printer) const328 void RepeatedEnumFieldGenerator::GenerateSwappingCode(
329 io::Printer* printer) const {
330 Formatter format(printer, variables_);
331 format("$field$.InternalSwap(&other->$field$);\n");
332 }
333
GenerateConstructorCode(io::Printer * printer) const334 void RepeatedEnumFieldGenerator::GenerateConstructorCode(
335 io::Printer* printer) const {
336 // Not needed for repeated fields.
337 }
338
GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const339 void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizesToArray(
340 io::Printer* printer) const {
341 Formatter format(printer, variables_);
342 if (descriptor_->is_packed()) {
343 // Write the tag and the size.
344 format(
345 "{\n"
346 " int byte_size = "
347 "$cached_byte_size_field$.load(std::memory_order_relaxed);\n"
348 " if (byte_size > 0) {\n"
349 " target = stream->WriteEnumPacked(\n"
350 " $number$, $field$, byte_size, target);\n"
351 " }\n"
352 "}\n");
353 } else {
354 format(
355 "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n"
356 " target = stream->EnsureSpace(target);\n"
357 " target = ::_pbi::WireFormatLite::WriteEnumToArray(\n"
358 " $number$, this->_internal_$name$(i), target);\n"
359 "}\n");
360 }
361 }
362
GenerateByteSize(io::Printer * printer) const363 void RepeatedEnumFieldGenerator::GenerateByteSize(io::Printer* printer) const {
364 Formatter format(printer, variables_);
365 format(
366 "{\n"
367 " size_t data_size = 0;\n"
368 " unsigned int count = static_cast<unsigned "
369 "int>(this->_internal_$name$_size());");
370 format.Indent();
371 format(
372 "for (unsigned int i = 0; i < count; i++) {\n"
373 " data_size += ::_pbi::WireFormatLite::EnumSize(\n"
374 " this->_internal_$name$(static_cast<int>(i)));\n"
375 "}\n");
376
377 if (descriptor_->is_packed()) {
378 format(
379 "if (data_size > 0) {\n"
380 " total_size += $tag_size$ +\n"
381 " "
382 "::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n"
383 "}\n"
384 "int cached_size = ::_pbi::ToCachedSize(data_size);\n"
385 "$cached_byte_size_field$.store(cached_size,\n"
386 " std::memory_order_relaxed);\n"
387 "total_size += data_size;\n");
388 } else {
389 format("total_size += ($tag_size$UL * count) + data_size;\n");
390 }
391 format.Outdent();
392 format("}\n");
393 }
394
GenerateConstinitInitializer(io::Printer * printer) const395 void RepeatedEnumFieldGenerator::GenerateConstinitInitializer(
396 io::Printer* printer) const {
397 Formatter format(printer, variables_);
398 format("$name$_()");
399 if (descriptor_->is_packed() &&
400 HasGeneratedMethods(descriptor_->file(), options_)) {
401 format("\n, $cached_byte_size_name$(0)");
402 }
403 }
404
405 } // namespace cpp
406 } // namespace compiler
407 } // namespace protobuf
408 } // namespace google
409