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_primitive_field.h>
36 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
37 #include <google/protobuf/io/printer.h>
38 #include <google/protobuf/wire_format.h>
39 #include <google/protobuf/stubs/strutil.h>
40
41 namespace google {
42 namespace protobuf {
43 namespace compiler {
44 namespace cpp {
45
46 using internal::WireFormatLite;
47
48 namespace {
49
50 // For encodings with fixed sizes, returns that size in bytes. Otherwise
51 // returns -1.
FixedSize(FieldDescriptor::Type type)52 int FixedSize(FieldDescriptor::Type type) {
53 switch (type) {
54 case FieldDescriptor::TYPE_INT32 : return -1;
55 case FieldDescriptor::TYPE_INT64 : return -1;
56 case FieldDescriptor::TYPE_UINT32 : return -1;
57 case FieldDescriptor::TYPE_UINT64 : return -1;
58 case FieldDescriptor::TYPE_SINT32 : return -1;
59 case FieldDescriptor::TYPE_SINT64 : return -1;
60 case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
61 case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
62 case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
63 case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
64 case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize;
65 case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize;
66
67 case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize;
68 case FieldDescriptor::TYPE_ENUM : return -1;
69
70 case FieldDescriptor::TYPE_STRING : return -1;
71 case FieldDescriptor::TYPE_BYTES : return -1;
72 case FieldDescriptor::TYPE_GROUP : return -1;
73 case FieldDescriptor::TYPE_MESSAGE : return -1;
74
75 // No default because we want the compiler to complain if any new
76 // types are added.
77 }
78 GOOGLE_LOG(FATAL) << "Can't get here.";
79 return -1;
80 }
81
SetPrimitiveVariables(const FieldDescriptor * descriptor,map<string,string> * variables,const Options & options)82 void SetPrimitiveVariables(const FieldDescriptor* descriptor,
83 map<string, string>* variables,
84 const Options& options) {
85 SetCommonFieldVariables(descriptor, variables, options);
86 (*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type());
87 (*variables)["default"] = DefaultValue(descriptor);
88 (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
89 int fixed_size = FixedSize(descriptor->type());
90 if (fixed_size != -1) {
91 (*variables)["fixed_size"] = SimpleItoa(fixed_size);
92 }
93 (*variables)["wire_format_field_type"] =
94 "::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name(
95 static_cast<FieldDescriptorProto_Type>(descriptor->type()));
96 (*variables)["full_name"] = descriptor->full_name();
97 }
98
99 } // namespace
100
101 // ===================================================================
102
PrimitiveFieldGenerator(const FieldDescriptor * descriptor,const Options & options)103 PrimitiveFieldGenerator::PrimitiveFieldGenerator(
104 const FieldDescriptor* descriptor, const Options& options)
105 : FieldGenerator(options), descriptor_(descriptor) {
106 SetPrimitiveVariables(descriptor, &variables_, options);
107 }
108
~PrimitiveFieldGenerator()109 PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
110
111 void PrimitiveFieldGenerator::
GeneratePrivateMembers(io::Printer * printer) const112 GeneratePrivateMembers(io::Printer* printer) const {
113 printer->Print(variables_, "$type$ $name$_;\n");
114 }
115
116 void PrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer * printer) const117 GenerateAccessorDeclarations(io::Printer* printer) const {
118 printer->Print(variables_,
119 "$deprecated_attr$$type$ $name$() const;\n"
120 "$deprecated_attr$void set_$name$($type$ value);\n");
121 }
122
123 void PrimitiveFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer * printer,bool is_inline) const124 GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
125 map<string, string> variables(variables_);
126 variables["inline"] = is_inline ? "inline" : "";
127 printer->Print(variables,
128 "$inline$ $type$ $classname$::$name$() const {\n"
129 " // @@protoc_insertion_point(field_get:$full_name$)\n"
130 " return $name$_;\n"
131 "}\n"
132 "$inline$ void $classname$::set_$name$($type$ value) {\n"
133 " $set_hasbit$\n"
134 " $name$_ = value;\n"
135 " // @@protoc_insertion_point(field_set:$full_name$)\n"
136 "}\n");
137 }
138
139 void PrimitiveFieldGenerator::
GenerateClearingCode(io::Printer * printer) const140 GenerateClearingCode(io::Printer* printer) const {
141 printer->Print(variables_, "$name$_ = $default$;\n");
142 }
143
144 void PrimitiveFieldGenerator::
GenerateMergingCode(io::Printer * printer) const145 GenerateMergingCode(io::Printer* printer) const {
146 printer->Print(variables_, "set_$name$(from.$name$());\n");
147 }
148
149 void PrimitiveFieldGenerator::
GenerateSwappingCode(io::Printer * printer) const150 GenerateSwappingCode(io::Printer* printer) const {
151 printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
152 }
153
154 void PrimitiveFieldGenerator::
GenerateConstructorCode(io::Printer * printer) const155 GenerateConstructorCode(io::Printer* printer) const {
156 printer->Print(variables_, "$name$_ = $default$;\n");
157 }
158
159 void PrimitiveFieldGenerator::
GenerateMergeFromCodedStream(io::Printer * printer) const160 GenerateMergeFromCodedStream(io::Printer* printer) const {
161 printer->Print(variables_,
162 "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
163 " $type$, $wire_format_field_type$>(\n"
164 " input, &$name$_)));\n"
165 "$set_hasbit$\n");
166 }
167
168 void PrimitiveFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer * printer) const169 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
170 printer->Print(variables_,
171 "::google::protobuf::internal::WireFormatLite::Write$declared_type$("
172 "$number$, this->$name$(), output);\n");
173 }
174
175 void PrimitiveFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const176 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
177 printer->Print(variables_,
178 "target = ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray("
179 "$number$, this->$name$(), target);\n");
180 }
181
182 void PrimitiveFieldGenerator::
GenerateByteSize(io::Printer * printer) const183 GenerateByteSize(io::Printer* printer) const {
184 int fixed_size = FixedSize(descriptor_->type());
185 if (fixed_size == -1) {
186 printer->Print(variables_,
187 "total_size += $tag_size$ +\n"
188 " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
189 " this->$name$());\n");
190 } else {
191 printer->Print(variables_,
192 "total_size += $tag_size$ + $fixed_size$;\n");
193 }
194 }
195
196 // ===================================================================
197
198 PrimitiveOneofFieldGenerator::
PrimitiveOneofFieldGenerator(const FieldDescriptor * descriptor,const Options & options)199 PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
200 const Options& options)
201 : PrimitiveFieldGenerator(descriptor, options) {
202 SetCommonOneofFieldVariables(descriptor, &variables_);
203 }
204
~PrimitiveOneofFieldGenerator()205 PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
206
207 void PrimitiveOneofFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer * printer,bool is_inline) const208 GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
209 map<string, string> variables(variables_);
210 variables["inline"] = is_inline ? "inline" : "";
211 printer->Print(variables,
212 "$inline$ $type$ $classname$::$name$() const {\n"
213 " // @@protoc_insertion_point(field_get:$full_name$)\n"
214 " if (has_$name$()) {\n"
215 " return $oneof_prefix$$name$_;\n"
216 " }\n"
217 " return $default$;\n"
218 "}\n"
219 "$inline$ void $classname$::set_$name$($type$ value) {\n"
220 " if (!has_$name$()) {\n"
221 " clear_$oneof_name$();\n"
222 " set_has_$name$();\n"
223 " }\n"
224 " $oneof_prefix$$name$_ = value;\n"
225 " // @@protoc_insertion_point(field_set:$full_name$)\n"
226 "}\n");
227 }
228
229 void PrimitiveOneofFieldGenerator::
GenerateClearingCode(io::Printer * printer) const230 GenerateClearingCode(io::Printer* printer) const {
231 printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
232 }
233
234 void PrimitiveOneofFieldGenerator::
GenerateSwappingCode(io::Printer * printer) const235 GenerateSwappingCode(io::Printer* printer) const {
236 // Don't print any swapping code. Swapping the union will swap this field.
237 }
238
239 void PrimitiveOneofFieldGenerator::
GenerateConstructorCode(io::Printer * printer) const240 GenerateConstructorCode(io::Printer* printer) const {
241 printer->Print(
242 variables_,
243 " $classname$_default_oneof_instance_->$name$_ = $default$;\n");
244 }
245
246 void PrimitiveOneofFieldGenerator::
GenerateMergeFromCodedStream(io::Printer * printer) const247 GenerateMergeFromCodedStream(io::Printer* printer) const {
248 printer->Print(variables_,
249 "clear_$oneof_name$();\n"
250 "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
251 " $type$, $wire_format_field_type$>(\n"
252 " input, &$oneof_prefix$$name$_)));\n"
253 "set_has_$name$();\n");
254 }
255
256 // ===================================================================
257
RepeatedPrimitiveFieldGenerator(const FieldDescriptor * descriptor,const Options & options)258 RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
259 const FieldDescriptor* descriptor, const Options& options)
260 : FieldGenerator(options), descriptor_(descriptor) {
261 SetPrimitiveVariables(descriptor, &variables_, options);
262
263 if (descriptor->is_packed()) {
264 variables_["packed_reader"] = "ReadPackedPrimitive";
265 variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
266 } else {
267 variables_["packed_reader"] = "ReadPackedPrimitiveNoInline";
268 variables_["repeated_reader"] = "ReadRepeatedPrimitive";
269 }
270 }
271
~RepeatedPrimitiveFieldGenerator()272 RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
273
274 void RepeatedPrimitiveFieldGenerator::
GeneratePrivateMembers(io::Printer * printer) const275 GeneratePrivateMembers(io::Printer* printer) const {
276 printer->Print(variables_,
277 "::google::protobuf::RepeatedField< $type$ > $name$_;\n");
278 if (descriptor_->is_packed() &&
279 HasGeneratedMethods(descriptor_->file(), options_)) {
280 printer->Print(variables_,
281 "mutable int _$name$_cached_byte_size_;\n");
282 }
283 }
284
285 void RepeatedPrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer * printer) const286 GenerateAccessorDeclarations(io::Printer* printer) const {
287 printer->Print(variables_,
288 "$deprecated_attr$$type$ $name$(int index) const;\n"
289 "$deprecated_attr$void set_$name$(int index, $type$ value);\n"
290 "$deprecated_attr$void add_$name$($type$ value);\n");
291 printer->Print(variables_,
292 "$deprecated_attr$const ::google::protobuf::RepeatedField< $type$ >&\n"
293 " $name$() const;\n"
294 "$deprecated_attr$::google::protobuf::RepeatedField< $type$ >*\n"
295 " mutable_$name$();\n");
296 }
297
298 void RepeatedPrimitiveFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer * printer,bool is_inline) const299 GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
300 map<string, string> variables(variables_);
301 variables["inline"] = is_inline ? "inline" : "";
302 printer->Print(variables,
303 "$inline$ $type$ $classname$::$name$(int index) const {\n"
304 " // @@protoc_insertion_point(field_get:$full_name$)\n"
305 " return $name$_.Get(index);\n"
306 "}\n"
307 "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n"
308 " $name$_.Set(index, value);\n"
309 " // @@protoc_insertion_point(field_set:$full_name$)\n"
310 "}\n"
311 "$inline$ void $classname$::add_$name$($type$ value) {\n"
312 " $name$_.Add(value);\n"
313 " // @@protoc_insertion_point(field_add:$full_name$)\n"
314 "}\n");
315 printer->Print(variables,
316 "$inline$ const ::google::protobuf::RepeatedField< $type$ >&\n"
317 "$classname$::$name$() const {\n"
318 " // @@protoc_insertion_point(field_list:$full_name$)\n"
319 " return $name$_;\n"
320 "}\n"
321 "$inline$ ::google::protobuf::RepeatedField< $type$ >*\n"
322 "$classname$::mutable_$name$() {\n"
323 " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
324 " return &$name$_;\n"
325 "}\n");
326 }
327
328 void RepeatedPrimitiveFieldGenerator::
GenerateClearingCode(io::Printer * printer) const329 GenerateClearingCode(io::Printer* printer) const {
330 printer->Print(variables_, "$name$_.Clear();\n");
331 }
332
333 void RepeatedPrimitiveFieldGenerator::
GenerateMergingCode(io::Printer * printer) const334 GenerateMergingCode(io::Printer* printer) const {
335 printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
336 }
337
338 void RepeatedPrimitiveFieldGenerator::
GenerateSwappingCode(io::Printer * printer) const339 GenerateSwappingCode(io::Printer* printer) const {
340 printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
341 }
342
343 void RepeatedPrimitiveFieldGenerator::
GenerateConstructorCode(io::Printer * printer) const344 GenerateConstructorCode(io::Printer* printer) const {
345 // Not needed for repeated fields.
346 }
347
348 void RepeatedPrimitiveFieldGenerator::
GenerateMergeFromCodedStream(io::Printer * printer) const349 GenerateMergeFromCodedStream(io::Printer* printer) const {
350 printer->Print(variables_,
351 "DO_((::google::protobuf::internal::WireFormatLite::$repeated_reader$<\n"
352 " $type$, $wire_format_field_type$>(\n"
353 " $tag_size$, $tag$, input, this->mutable_$name$())));\n");
354 }
355
356 void RepeatedPrimitiveFieldGenerator::
GenerateMergeFromCodedStreamWithPacking(io::Printer * printer) const357 GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
358 printer->Print(variables_,
359 "DO_((::google::protobuf::internal::WireFormatLite::$packed_reader$<\n"
360 " $type$, $wire_format_field_type$>(\n"
361 " input, this->mutable_$name$())));\n");
362 }
363
364 void RepeatedPrimitiveFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer * printer) const365 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
366 if (descriptor_->is_packed()) {
367 // Write the tag and the size.
368 printer->Print(variables_,
369 "if (this->$name$_size() > 0) {\n"
370 " ::google::protobuf::internal::WireFormatLite::WriteTag("
371 "$number$, "
372 "::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, "
373 "output);\n"
374 " output->WriteVarint32(_$name$_cached_byte_size_);\n"
375 "}\n");
376 }
377 printer->Print(variables_,
378 "for (int i = 0; i < this->$name$_size(); i++) {\n");
379 if (descriptor_->is_packed()) {
380 printer->Print(variables_,
381 " ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n"
382 " this->$name$(i), output);\n");
383 } else {
384 printer->Print(variables_,
385 " ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
386 " $number$, this->$name$(i), output);\n");
387 }
388 printer->Print("}\n");
389 }
390
391 void RepeatedPrimitiveFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const392 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
393 if (descriptor_->is_packed()) {
394 // Write the tag and the size.
395 printer->Print(variables_,
396 "if (this->$name$_size() > 0) {\n"
397 " target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
398 " $number$,\n"
399 " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
400 " target);\n"
401 " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n"
402 " _$name$_cached_byte_size_, target);\n"
403 "}\n");
404 }
405 printer->Print(variables_,
406 "for (int i = 0; i < this->$name$_size(); i++) {\n");
407 if (descriptor_->is_packed()) {
408 printer->Print(variables_,
409 " target = ::google::protobuf::internal::WireFormatLite::\n"
410 " Write$declared_type$NoTagToArray(this->$name$(i), target);\n");
411 } else {
412 printer->Print(variables_,
413 " target = ::google::protobuf::internal::WireFormatLite::\n"
414 " Write$declared_type$ToArray($number$, this->$name$(i), target);\n");
415 }
416 printer->Print("}\n");
417 }
418
419 void RepeatedPrimitiveFieldGenerator::
GenerateByteSize(io::Printer * printer) const420 GenerateByteSize(io::Printer* printer) const {
421 printer->Print(variables_,
422 "{\n"
423 " int data_size = 0;\n");
424 printer->Indent();
425 int fixed_size = FixedSize(descriptor_->type());
426 if (fixed_size == -1) {
427 printer->Print(variables_,
428 "for (int i = 0; i < this->$name$_size(); i++) {\n"
429 " data_size += ::google::protobuf::internal::WireFormatLite::\n"
430 " $declared_type$Size(this->$name$(i));\n"
431 "}\n");
432 } else {
433 printer->Print(variables_,
434 "data_size = $fixed_size$ * this->$name$_size();\n");
435 }
436
437 if (descriptor_->is_packed()) {
438 printer->Print(variables_,
439 "if (data_size > 0) {\n"
440 " total_size += $tag_size$ +\n"
441 " ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
442 "}\n"
443 "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
444 "_$name$_cached_byte_size_ = data_size;\n"
445 "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
446 "total_size += data_size;\n");
447 } else {
448 printer->Print(variables_,
449 "total_size += $tag_size$ * this->$name$_size() + data_size;\n");
450 }
451 printer->Outdent();
452 printer->Print("}\n");
453 }
454
455 } // namespace cpp
456 } // namespace compiler
457 } // namespace protobuf
458 } // namespace google
459