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/primitive_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/helpers.h>
41
42namespace google {
43namespace protobuf {
44namespace compiler {
45namespace cpp {
46
47using internal::WireFormatLite;
48
49namespace {
50
51// For encodings with fixed sizes, returns that size in bytes. Otherwise
52// returns -1.
53int FixedSize(FieldDescriptor::Type type) {
54 switch (type) {
55 case FieldDescriptor::TYPE_INT32:
56 return -1;
57 case FieldDescriptor::TYPE_INT64:
58 return -1;
59 case FieldDescriptor::TYPE_UINT32:
60 return -1;
61 case FieldDescriptor::TYPE_UINT64:
62 return -1;
63 case FieldDescriptor::TYPE_SINT32:
64 return -1;
65 case FieldDescriptor::TYPE_SINT64:
66 return -1;
67 case FieldDescriptor::TYPE_FIXED32:
68 return WireFormatLite::kFixed32Size;
69 case FieldDescriptor::TYPE_FIXED64:
70 return WireFormatLite::kFixed64Size;
71 case FieldDescriptor::TYPE_SFIXED32:
72 return WireFormatLite::kSFixed32Size;
73 case FieldDescriptor::TYPE_SFIXED64:
74 return WireFormatLite::kSFixed64Size;
75 case FieldDescriptor::TYPE_FLOAT:
76 return WireFormatLite::kFloatSize;
77 case FieldDescriptor::TYPE_DOUBLE:
78 return WireFormatLite::kDoubleSize;
79
80 case FieldDescriptor::TYPE_BOOL:
81 return WireFormatLite::kBoolSize;
82 case FieldDescriptor::TYPE_ENUM:
83 return -1;
84
85 case FieldDescriptor::TYPE_STRING:
86 return -1;
87 case FieldDescriptor::TYPE_BYTES:
88 return -1;
89 case FieldDescriptor::TYPE_GROUP:
90 return -1;
91 case FieldDescriptor::TYPE_MESSAGE:
92 return -1;
93
94 // No default because we want the compiler to complain if any new
95 // types are added.
96 }
97 GOOGLE_LOG(FATAL) << "Can't get here.";
98 return -1;
99}
100
101void SetPrimitiveVariables(const FieldDescriptor* descriptor,
102 std::map<std::string, std::string>* variables,
103 const Options& options) {
104 SetCommonFieldVariables(descriptor, variables, options);
105 (*variables)["type"] = PrimitiveTypeName(options, type: descriptor->cpp_type());
106 (*variables)["default"] = DefaultValue(options, field: descriptor);
107 (*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(field: descriptor);
108 bool cold = ShouldSplit(field: descriptor, options);
109 (*variables)["cached_byte_size_field"] =
110 MakeVarintCachedSizeFieldName(field: descriptor, split: cold);
111 (*variables)["tag"] = StrCat(a: internal::WireFormat::MakeTag(field: descriptor));
112 int fixed_size = FixedSize(type: descriptor->type());
113 if (fixed_size != -1) {
114 (*variables)["fixed_size"] = StrCat(a: fixed_size);
115 }
116 (*variables)["wire_format_field_type"] = FieldDescriptorProto_Type_Name(
117 enum_t_value: static_cast<FieldDescriptorProto_Type>(descriptor->type()));
118 (*variables)["full_name"] = descriptor->full_name();
119}
120
121} // namespace
122
123// ===================================================================
124
125PrimitiveFieldGenerator::PrimitiveFieldGenerator(
126 const FieldDescriptor* descriptor, const Options& options)
127 : FieldGenerator(descriptor, options) {
128 SetPrimitiveVariables(descriptor, variables: &variables_, options);
129}
130
131PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
132
133void PrimitiveFieldGenerator::GeneratePrivateMembers(
134 io::Printer* printer) const {
135 Formatter format(printer, variables_);
136 format("$type$ $name$_;\n");
137}
138
139void PrimitiveFieldGenerator::GenerateAccessorDeclarations(
140 io::Printer* printer) const {
141 Formatter format(printer, variables_);
142 format(
143 "$deprecated_attr$$type$ ${1$$name$$}$() const;\n"
144 "$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n"
145 "private:\n"
146 "$type$ ${1$_internal_$name$$}$() const;\n"
147 "void ${1$_internal_set_$name$$}$($type$ value);\n"
148 "public:\n",
149 descriptor_);
150}
151
152void PrimitiveFieldGenerator::GenerateInlineAccessorDefinitions(
153 io::Printer* printer) const {
154 Formatter format(printer, variables_);
155 format(
156 "inline $type$ $classname$::_internal_$name$() const {\n"
157 " return $field$;\n"
158 "}\n"
159 "inline $type$ $classname$::$name$() const {\n"
160 "$annotate_get$"
161 " // @@protoc_insertion_point(field_get:$full_name$)\n"
162 " return _internal_$name$();\n"
163 "}\n"
164 "inline void $classname$::_internal_set_$name$($type$ value) {\n"
165 " $set_hasbit$\n"
166 " $field$ = value;\n"
167 "}\n"
168 "inline void $classname$::set_$name$($type$ value) {\n"
169 "$maybe_prepare_split_message$"
170 " _internal_set_$name$(value);\n"
171 "$annotate_set$"
172 " // @@protoc_insertion_point(field_set:$full_name$)\n"
173 "}\n");
174}
175
176void PrimitiveFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
177 Formatter format(printer, variables_);
178 format("$field$ = $default$;\n");
179}
180
181void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
182 Formatter format(printer, variables_);
183 format("_this->_internal_set_$name$(from._internal_$name$());\n");
184}
185
186void PrimitiveFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
187 Formatter format(printer, variables_);
188 format("swap($field$, other->$field$);\n");
189}
190
191void PrimitiveFieldGenerator::GenerateCopyConstructorCode(
192 io::Printer* printer) const {
193 Formatter format(printer, variables_);
194 format("_this->$field$ = from.$field$;\n");
195}
196
197void PrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray(
198 io::Printer* printer) const {
199 Formatter format(printer, variables_);
200 format(
201 "target = stream->EnsureSpace(target);\n"
202 "target = "
203 "::_pbi::WireFormatLite::Write$declared_type$ToArray("
204 "$number$, this->_internal_$name$(), target);\n");
205}
206
207void PrimitiveFieldGenerator::GenerateByteSize(io::Printer* printer) const {
208 Formatter format(printer, variables_);
209 int fixed_size = FixedSize(type: descriptor_->type());
210 if (fixed_size == -1) {
211 if (internal::WireFormat::TagSize(field_number: descriptor_->number(),
212 type: descriptor_->type()) == 1) {
213 // Adding one is very common and it turns out it can be done for
214 // free inside of WireFormatLite, so we can save an instruction here.
215 format(
216 "total_size += ::_pbi::WireFormatLite::"
217 "$declared_type$SizePlusOne(this->_internal_$name$());\n");
218 } else {
219 format(
220 "total_size += $tag_size$ +\n"
221 " ::_pbi::WireFormatLite::$declared_type$Size(\n"
222 " this->_internal_$name$());\n");
223 }
224 } else {
225 format("total_size += $tag_size$ + $fixed_size$;\n");
226 }
227}
228
229void PrimitiveFieldGenerator::GenerateConstexprAggregateInitializer(
230 io::Printer* printer) const {
231 Formatter format(printer, variables_);
232 format("/*decltype($field$)*/$default$");
233}
234
235void PrimitiveFieldGenerator::GenerateAggregateInitializer(
236 io::Printer* printer) const {
237 Formatter format(printer, variables_);
238 if (ShouldSplit(field: descriptor_, options: options_)) {
239 format("decltype(Impl_::Split::$name$_){$default$}");
240 return;
241 }
242 format("decltype($field$){$default$}");
243}
244
245void PrimitiveFieldGenerator::GenerateCopyAggregateInitializer(
246 io::Printer* printer) const {
247 Formatter format(printer, variables_);
248 format("decltype($field$){}");
249}
250
251// ===================================================================
252
253PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
254 const FieldDescriptor* descriptor, const Options& options)
255 : PrimitiveFieldGenerator(descriptor, options) {
256 SetCommonOneofFieldVariables(descriptor, variables: &variables_);
257}
258
259PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
260
261void PrimitiveOneofFieldGenerator::GenerateInlineAccessorDefinitions(
262 io::Printer* printer) const {
263 Formatter format(printer, variables_);
264 format(
265 "inline $type$ $classname$::_internal_$name$() const {\n"
266 " if (_internal_has_$name$()) {\n"
267 " return $field$;\n"
268 " }\n"
269 " return $default$;\n"
270 "}\n"
271 "inline void $classname$::_internal_set_$name$($type$ value) {\n"
272 " if (!_internal_has_$name$()) {\n"
273 " clear_$oneof_name$();\n"
274 " set_has_$name$();\n"
275 " }\n"
276 " $field$ = value;\n"
277 "}\n"
278 "inline $type$ $classname$::$name$() const {\n"
279 "$annotate_get$"
280 " // @@protoc_insertion_point(field_get:$full_name$)\n"
281 " return _internal_$name$();\n"
282 "}\n"
283 "inline void $classname$::set_$name$($type$ value) {\n"
284 " _internal_set_$name$(value);\n"
285 "$annotate_set$"
286 " // @@protoc_insertion_point(field_set:$full_name$)\n"
287 "}\n");
288}
289
290void PrimitiveOneofFieldGenerator::GenerateClearingCode(
291 io::Printer* printer) const {
292 Formatter format(printer, variables_);
293 format("$field$ = $default$;\n");
294}
295
296void PrimitiveOneofFieldGenerator::GenerateSwappingCode(
297 io::Printer* printer) const {
298 // Don't print any swapping code. Swapping the union will swap this field.
299}
300
301void PrimitiveOneofFieldGenerator::GenerateConstructorCode(
302 io::Printer* printer) const {
303 Formatter format(printer, variables_);
304 format("$ns$::_$classname$_default_instance_.$field$ = $default$;\n");
305}
306
307// ===================================================================
308
309RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
310 const FieldDescriptor* descriptor, const Options& options)
311 : FieldGenerator(descriptor, options) {
312 SetPrimitiveVariables(descriptor, variables: &variables_, options);
313
314 if (descriptor->is_packed()) {
315 variables_["packed_reader"] = "ReadPackedPrimitive";
316 variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
317 } else {
318 variables_["packed_reader"] = "ReadPackedPrimitiveNoInline";
319 variables_["repeated_reader"] = "ReadRepeatedPrimitive";
320 }
321}
322
323RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
324
325void RepeatedPrimitiveFieldGenerator::GeneratePrivateMembers(
326 io::Printer* printer) const {
327 Formatter format(printer, variables_);
328 format("::$proto_ns$::RepeatedField< $type$ > $name$_;\n");
329 if (descriptor_->is_packed() && FixedSize(type: descriptor_->type()) == -1 &&
330 HasGeneratedMethods(file: descriptor_->file(), options: options_)) {
331 format("mutable std::atomic<int> $cached_byte_size_name$;\n");
332 }
333}
334
335void RepeatedPrimitiveFieldGenerator::GenerateAccessorDeclarations(
336 io::Printer* printer) const {
337 Formatter format(printer, variables_);
338 format(
339 "private:\n"
340 "$type$ ${1$_internal_$name$$}$(int index) const;\n"
341 "const ::$proto_ns$::RepeatedField< $type$ >&\n"
342 " ${1$_internal_$name$$}$() const;\n"
343 "void ${1$_internal_add_$name$$}$($type$ value);\n"
344 "::$proto_ns$::RepeatedField< $type$ >*\n"
345 " ${1$_internal_mutable_$name$$}$();\n"
346 "public:\n"
347 "$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n"
348 "$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n"
349 "$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n"
350 "$deprecated_attr$const ::$proto_ns$::RepeatedField< $type$ >&\n"
351 " ${1$$name$$}$() const;\n"
352 "$deprecated_attr$::$proto_ns$::RepeatedField< $type$ >*\n"
353 " ${1$mutable_$name$$}$();\n",
354 descriptor_);
355}
356
357void RepeatedPrimitiveFieldGenerator::GenerateInlineAccessorDefinitions(
358 io::Printer* printer) const {
359 Formatter format(printer, variables_);
360 format(
361 "inline $type$ $classname$::_internal_$name$(int index) const {\n"
362 " return $field$.Get(index);\n"
363 "}\n"
364 "inline $type$ $classname$::$name$(int index) const {\n"
365 "$annotate_get$"
366 " // @@protoc_insertion_point(field_get:$full_name$)\n"
367 " return _internal_$name$(index);\n"
368 "}\n"
369 "inline void $classname$::set_$name$(int index, $type$ value) {\n"
370 "$annotate_set$"
371 " $field$.Set(index, value);\n"
372 " // @@protoc_insertion_point(field_set:$full_name$)\n"
373 "}\n"
374 "inline void $classname$::_internal_add_$name$($type$ value) {\n"
375 " $field$.Add(value);\n"
376 "}\n"
377 "inline void $classname$::add_$name$($type$ value) {\n"
378 " _internal_add_$name$(value);\n"
379 "$annotate_add$"
380 " // @@protoc_insertion_point(field_add:$full_name$)\n"
381 "}\n"
382 "inline const ::$proto_ns$::RepeatedField< $type$ >&\n"
383 "$classname$::_internal_$name$() const {\n"
384 " return $field$;\n"
385 "}\n"
386 "inline const ::$proto_ns$::RepeatedField< $type$ >&\n"
387 "$classname$::$name$() const {\n"
388 "$annotate_list$"
389 " // @@protoc_insertion_point(field_list:$full_name$)\n"
390 " return _internal_$name$();\n"
391 "}\n"
392 "inline ::$proto_ns$::RepeatedField< $type$ >*\n"
393 "$classname$::_internal_mutable_$name$() {\n"
394 " return &$field$;\n"
395 "}\n"
396 "inline ::$proto_ns$::RepeatedField< $type$ >*\n"
397 "$classname$::mutable_$name$() {\n"
398 "$annotate_mutable_list$"
399 " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
400 " return _internal_mutable_$name$();\n"
401 "}\n");
402}
403
404void RepeatedPrimitiveFieldGenerator::GenerateClearingCode(
405 io::Printer* printer) const {
406 Formatter format(printer, variables_);
407 format("$field$.Clear();\n");
408}
409
410void RepeatedPrimitiveFieldGenerator::GenerateMergingCode(
411 io::Printer* printer) const {
412 Formatter format(printer, variables_);
413 format("_this->$field$.MergeFrom(from.$field$);\n");
414}
415
416void RepeatedPrimitiveFieldGenerator::GenerateSwappingCode(
417 io::Printer* printer) const {
418 Formatter format(printer, variables_);
419 format("$field$.InternalSwap(&other->$field$);\n");
420}
421
422void RepeatedPrimitiveFieldGenerator::GenerateDestructorCode(
423 io::Printer* printer) const {
424 Formatter format(printer, variables_);
425 format("$field$.~RepeatedField();\n");
426}
427
428void RepeatedPrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray(
429 io::Printer* printer) const {
430 Formatter format(printer, variables_);
431 if (descriptor_->is_packed()) {
432 if (FixedSize(type: descriptor_->type()) == -1) {
433 format(
434 "{\n"
435 " int byte_size = "
436 "$cached_byte_size_field$.load(std::memory_order_relaxed);\n"
437 " if (byte_size > 0) {\n"
438 " target = stream->Write$declared_type$Packed(\n"
439 " $number$, _internal_$name$(), byte_size, target);\n"
440 " }\n"
441 "}\n");
442 } else {
443 format(
444 "if (this->_internal_$name$_size() > 0) {\n"
445 " target = stream->WriteFixedPacked($number$, _internal_$name$(), "
446 "target);\n"
447 "}\n");
448 }
449 } else {
450 format(
451 "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n"
452 " target = stream->EnsureSpace(target);\n"
453 " target = ::_pbi::WireFormatLite::"
454 "Write$declared_type$ToArray($number$, this->_internal_$name$(i), "
455 "target);\n"
456 "}\n");
457 }
458}
459
460void RepeatedPrimitiveFieldGenerator::GenerateByteSize(
461 io::Printer* printer) const {
462 Formatter format(printer, variables_);
463 format("{\n");
464 format.Indent();
465 int fixed_size = FixedSize(type: descriptor_->type());
466 if (fixed_size == -1) {
467 format(
468 "size_t data_size = ::_pbi::WireFormatLite::\n"
469 " $declared_type$Size(this->$field$);\n");
470 } else {
471 format(
472 "unsigned int count = static_cast<unsigned "
473 "int>(this->_internal_$name$_size());\n"
474 "size_t data_size = $fixed_size$UL * count;\n");
475 }
476
477 if (descriptor_->is_packed()) {
478 format(
479 "if (data_size > 0) {\n"
480 " total_size += $tag_size$ +\n"
481 " "
482 "::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n"
483 "}\n");
484 if (FixedSize(type: descriptor_->type()) == -1) {
485 format(
486 "int cached_size = ::_pbi::ToCachedSize(data_size);\n"
487 "$cached_byte_size_field$.store(cached_size,\n"
488 " std::memory_order_relaxed);\n");
489 }
490 format("total_size += data_size;\n");
491 } else {
492 format(
493 "total_size += $tag_size$ *\n"
494 " "
495 "::_pbi::FromIntSize(this->_internal_$name$_size());\n"
496 "total_size += data_size;\n");
497 }
498 format.Outdent();
499 format("}\n");
500}
501
502void RepeatedPrimitiveFieldGenerator::GenerateConstexprAggregateInitializer(
503 io::Printer* printer) const {
504 Formatter format(printer, variables_);
505 format("/*decltype($field$)*/{}");
506 if (descriptor_->is_packed() && FixedSize(type: descriptor_->type()) == -1 &&
507 HasGeneratedMethods(file: descriptor_->file(), options: options_)) {
508 format("\n, /*decltype($cached_byte_size_field$)*/{0}");
509 }
510}
511
512void RepeatedPrimitiveFieldGenerator::GenerateAggregateInitializer(
513 io::Printer* printer) const {
514 Formatter format(printer, variables_);
515 format("decltype($field$){arena}");
516 if (descriptor_->is_packed() && FixedSize(type: descriptor_->type()) == -1 &&
517 HasGeneratedMethods(file: descriptor_->file(), options: options_)) {
518 // std::atomic has no move constructor, which prevents explicit aggregate
519 // initialization pre-C++17.
520 format("\n, /*decltype($cached_byte_size_field$)*/{0}");
521 }
522}
523
524void RepeatedPrimitiveFieldGenerator::GenerateCopyAggregateInitializer(
525 io::Printer* printer) const {
526
527 Formatter format(printer, variables_);
528 format("decltype($field$){from.$field$}");
529 if (descriptor_->is_packed() && FixedSize(type: descriptor_->type()) == -1 &&
530 HasGeneratedMethods(file: descriptor_->file(), options: options_)) {
531 // std::atomic has no move constructor.
532 format("\n, /*decltype($cached_byte_size_field$)*/{0}");
533 }
534}
535
536} // namespace cpp
537} // namespace compiler
538} // namespace protobuf
539} // namespace google
540