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
103 PrimitiveFieldGenerator::
PrimitiveFieldGenerator(const FieldDescriptor * descriptor,const Options & options)104 PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
105 const Options& options)
106 : descriptor_(descriptor) {
107 SetPrimitiveVariables(descriptor, &variables_, options);
108 }
109
~PrimitiveFieldGenerator()110 PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
111
112 void PrimitiveFieldGenerator::
GeneratePrivateMembers(io::Printer * printer) const113 GeneratePrivateMembers(io::Printer* printer) const {
114 printer->Print(variables_, "$type$ $name$_;\n");
115 }
116
117 void PrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer * printer) const118 GenerateAccessorDeclarations(io::Printer* printer) const {
119 printer->Print(variables_,
120 "inline $type$ $name$() const$deprecation$;\n"
121 "inline void set_$name$($type$ value)$deprecation$;\n");
122 }
123
124 void PrimitiveFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer * printer) const125 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
126 printer->Print(variables_,
127 "inline $type$ $classname$::$name$() const {\n"
128 " // @@protoc_insertion_point(field_get:$full_name$)\n"
129 " return $name$_;\n"
130 "}\n"
131 "inline void $classname$::set_$name$($type$ value) {\n"
132 " set_has_$name$();\n"
133 " $name$_ = value;\n"
134 " // @@protoc_insertion_point(field_set:$full_name$)\n"
135 "}\n");
136 }
137
138 void PrimitiveFieldGenerator::
GenerateClearingCode(io::Printer * printer) const139 GenerateClearingCode(io::Printer* printer) const {
140 printer->Print(variables_, "$name$_ = $default$;\n");
141 }
142
143 void PrimitiveFieldGenerator::
GenerateMergingCode(io::Printer * printer) const144 GenerateMergingCode(io::Printer* printer) const {
145 printer->Print(variables_, "set_$name$(from.$name$());\n");
146 }
147
148 void PrimitiveFieldGenerator::
GenerateSwappingCode(io::Printer * printer) const149 GenerateSwappingCode(io::Printer* printer) const {
150 printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
151 }
152
153 void PrimitiveFieldGenerator::
GenerateConstructorCode(io::Printer * printer) const154 GenerateConstructorCode(io::Printer* printer) const {
155 printer->Print(variables_, "$name$_ = $default$;\n");
156 }
157
158 void PrimitiveFieldGenerator::
GenerateMergeFromCodedStream(io::Printer * printer) const159 GenerateMergeFromCodedStream(io::Printer* printer) const {
160 printer->Print(variables_,
161 "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
162 " $type$, $wire_format_field_type$>(\n"
163 " input, &$name$_)));\n"
164 "set_has_$name$();\n");
165 }
166
167 void PrimitiveFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer * printer) const168 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
169 printer->Print(variables_,
170 "::google::protobuf::internal::WireFormatLite::Write$declared_type$("
171 "$number$, this->$name$(), output);\n");
172 }
173
174 void PrimitiveFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const175 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
176 printer->Print(variables_,
177 "target = ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray("
178 "$number$, this->$name$(), target);\n");
179 }
180
181 void PrimitiveFieldGenerator::
GenerateByteSize(io::Printer * printer) const182 GenerateByteSize(io::Printer* printer) const {
183 int fixed_size = FixedSize(descriptor_->type());
184 if (fixed_size == -1) {
185 printer->Print(variables_,
186 "total_size += $tag_size$ +\n"
187 " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
188 " this->$name$());\n");
189 } else {
190 printer->Print(variables_,
191 "total_size += $tag_size$ + $fixed_size$;\n");
192 }
193 }
194
195 // ===================================================================
196
197 PrimitiveOneofFieldGenerator::
PrimitiveOneofFieldGenerator(const FieldDescriptor * descriptor,const Options & options)198 PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
199 const Options& options)
200 : PrimitiveFieldGenerator(descriptor, options) {
201 SetCommonOneofFieldVariables(descriptor, &variables_);
202 }
203
~PrimitiveOneofFieldGenerator()204 PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
205
206 void PrimitiveOneofFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer * printer) const207 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
208 printer->Print(variables_,
209 "inline $type$ $classname$::$name$() const {\n"
210 " if (has_$name$()) {\n"
211 " return $oneof_prefix$$name$_;\n"
212 " }\n"
213 " return $default$;\n"
214 "}\n"
215 "inline void $classname$::set_$name$($type$ value) {\n"
216 " if (!has_$name$()) {\n"
217 " clear_$oneof_name$();\n"
218 " set_has_$name$();\n"
219 " }\n"
220 " $oneof_prefix$$name$_ = value;\n"
221 "}\n");
222 }
223
224 void PrimitiveOneofFieldGenerator::
GenerateClearingCode(io::Printer * printer) const225 GenerateClearingCode(io::Printer* printer) const {
226 printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
227 }
228
229 void PrimitiveOneofFieldGenerator::
GenerateSwappingCode(io::Printer * printer) const230 GenerateSwappingCode(io::Printer* printer) const {
231 // Don't print any swapping code. Swapping the union will swap this field.
232 }
233
234 void PrimitiveOneofFieldGenerator::
GenerateConstructorCode(io::Printer * printer) const235 GenerateConstructorCode(io::Printer* printer) const {
236 printer->Print(
237 variables_,
238 " $classname$_default_oneof_instance_->$name$_ = $default$;\n");
239 }
240
241 void PrimitiveOneofFieldGenerator::
GenerateMergeFromCodedStream(io::Printer * printer) const242 GenerateMergeFromCodedStream(io::Printer* printer) const {
243 printer->Print(variables_,
244 "clear_$oneof_name$();\n"
245 "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
246 " $type$, $wire_format_field_type$>(\n"
247 " input, &$oneof_prefix$$name$_)));\n"
248 "set_has_$name$();\n");
249 }
250
251 // ===================================================================
252
253 RepeatedPrimitiveFieldGenerator::
RepeatedPrimitiveFieldGenerator(const FieldDescriptor * descriptor,const Options & options)254 RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
255 const Options& options)
256 : descriptor_(descriptor) {
257 SetPrimitiveVariables(descriptor, &variables_, options);
258
259 if (descriptor->options().packed()) {
260 variables_["packed_reader"] = "ReadPackedPrimitive";
261 variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
262 } else {
263 variables_["packed_reader"] = "ReadPackedPrimitiveNoInline";
264 variables_["repeated_reader"] = "ReadRepeatedPrimitive";
265 }
266 }
267
~RepeatedPrimitiveFieldGenerator()268 RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
269
270 void RepeatedPrimitiveFieldGenerator::
GeneratePrivateMembers(io::Printer * printer) const271 GeneratePrivateMembers(io::Printer* printer) const {
272 printer->Print(variables_,
273 "::google::protobuf::RepeatedField< $type$ > $name$_;\n");
274 if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
275 printer->Print(variables_,
276 "mutable int _$name$_cached_byte_size_;\n");
277 }
278 }
279
280 void RepeatedPrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer * printer) const281 GenerateAccessorDeclarations(io::Printer* printer) const {
282 printer->Print(variables_,
283 "inline $type$ $name$(int index) const$deprecation$;\n"
284 "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
285 "inline void add_$name$($type$ value)$deprecation$;\n");
286 printer->Print(variables_,
287 "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
288 " $name$() const$deprecation$;\n"
289 "inline ::google::protobuf::RepeatedField< $type$ >*\n"
290 " mutable_$name$()$deprecation$;\n");
291 }
292
293 void RepeatedPrimitiveFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer * printer) const294 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
295 printer->Print(variables_,
296 "inline $type$ $classname$::$name$(int index) const {\n"
297 " // @@protoc_insertion_point(field_get:$full_name$)\n"
298 " return $name$_.Get(index);\n"
299 "}\n"
300 "inline void $classname$::set_$name$(int index, $type$ value) {\n"
301 " $name$_.Set(index, value);\n"
302 " // @@protoc_insertion_point(field_set:$full_name$)\n"
303 "}\n"
304 "inline void $classname$::add_$name$($type$ value) {\n"
305 " $name$_.Add(value);\n"
306 " // @@protoc_insertion_point(field_add:$full_name$)\n"
307 "}\n");
308 printer->Print(variables_,
309 "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
310 "$classname$::$name$() const {\n"
311 " // @@protoc_insertion_point(field_list:$full_name$)\n"
312 " return $name$_;\n"
313 "}\n"
314 "inline ::google::protobuf::RepeatedField< $type$ >*\n"
315 "$classname$::mutable_$name$() {\n"
316 " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
317 " return &$name$_;\n"
318 "}\n");
319 }
320
321 void RepeatedPrimitiveFieldGenerator::
GenerateClearingCode(io::Printer * printer) const322 GenerateClearingCode(io::Printer* printer) const {
323 printer->Print(variables_, "$name$_.Clear();\n");
324 }
325
326 void RepeatedPrimitiveFieldGenerator::
GenerateMergingCode(io::Printer * printer) const327 GenerateMergingCode(io::Printer* printer) const {
328 printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
329 }
330
331 void RepeatedPrimitiveFieldGenerator::
GenerateSwappingCode(io::Printer * printer) const332 GenerateSwappingCode(io::Printer* printer) const {
333 printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
334 }
335
336 void RepeatedPrimitiveFieldGenerator::
GenerateConstructorCode(io::Printer * printer) const337 GenerateConstructorCode(io::Printer* printer) const {
338 // Not needed for repeated fields.
339 }
340
341 void RepeatedPrimitiveFieldGenerator::
GenerateMergeFromCodedStream(io::Printer * printer) const342 GenerateMergeFromCodedStream(io::Printer* printer) const {
343 printer->Print(variables_,
344 "DO_((::google::protobuf::internal::WireFormatLite::$repeated_reader$<\n"
345 " $type$, $wire_format_field_type$>(\n"
346 " $tag_size$, $tag$, input, this->mutable_$name$())));\n");
347 }
348
349 void RepeatedPrimitiveFieldGenerator::
GenerateMergeFromCodedStreamWithPacking(io::Printer * printer) const350 GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
351 printer->Print(variables_,
352 "DO_((::google::protobuf::internal::WireFormatLite::$packed_reader$<\n"
353 " $type$, $wire_format_field_type$>(\n"
354 " input, this->mutable_$name$())));\n");
355 }
356
357 void RepeatedPrimitiveFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer * printer) const358 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
359 if (descriptor_->options().packed()) {
360 // Write the tag and the size.
361 printer->Print(variables_,
362 "if (this->$name$_size() > 0) {\n"
363 " ::google::protobuf::internal::WireFormatLite::WriteTag("
364 "$number$, "
365 "::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, "
366 "output);\n"
367 " output->WriteVarint32(_$name$_cached_byte_size_);\n"
368 "}\n");
369 }
370 printer->Print(variables_,
371 "for (int i = 0; i < this->$name$_size(); i++) {\n");
372 if (descriptor_->options().packed()) {
373 printer->Print(variables_,
374 " ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n"
375 " this->$name$(i), output);\n");
376 } else {
377 printer->Print(variables_,
378 " ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
379 " $number$, this->$name$(i), output);\n");
380 }
381 printer->Print("}\n");
382 }
383
384 void RepeatedPrimitiveFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const385 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
386 if (descriptor_->options().packed()) {
387 // Write the tag and the size.
388 printer->Print(variables_,
389 "if (this->$name$_size() > 0) {\n"
390 " target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
391 " $number$,\n"
392 " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
393 " target);\n"
394 " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n"
395 " _$name$_cached_byte_size_, target);\n"
396 "}\n");
397 }
398 printer->Print(variables_,
399 "for (int i = 0; i < this->$name$_size(); i++) {\n");
400 if (descriptor_->options().packed()) {
401 printer->Print(variables_,
402 " target = ::google::protobuf::internal::WireFormatLite::\n"
403 " Write$declared_type$NoTagToArray(this->$name$(i), target);\n");
404 } else {
405 printer->Print(variables_,
406 " target = ::google::protobuf::internal::WireFormatLite::\n"
407 " Write$declared_type$ToArray($number$, this->$name$(i), target);\n");
408 }
409 printer->Print("}\n");
410 }
411
412 void RepeatedPrimitiveFieldGenerator::
GenerateByteSize(io::Printer * printer) const413 GenerateByteSize(io::Printer* printer) const {
414 printer->Print(variables_,
415 "{\n"
416 " int data_size = 0;\n");
417 printer->Indent();
418 int fixed_size = FixedSize(descriptor_->type());
419 if (fixed_size == -1) {
420 printer->Print(variables_,
421 "for (int i = 0; i < this->$name$_size(); i++) {\n"
422 " data_size += ::google::protobuf::internal::WireFormatLite::\n"
423 " $declared_type$Size(this->$name$(i));\n"
424 "}\n");
425 } else {
426 printer->Print(variables_,
427 "data_size = $fixed_size$ * this->$name$_size();\n");
428 }
429
430 if (descriptor_->options().packed()) {
431 printer->Print(variables_,
432 "if (data_size > 0) {\n"
433 " total_size += $tag_size$ +\n"
434 " ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
435 "}\n"
436 "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
437 "_$name$_cached_byte_size_ = data_size;\n"
438 "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n"
439 "total_size += data_size;\n");
440 } else {
441 printer->Print(variables_,
442 "total_size += $tag_size$ * this->$name$_size() + data_size;\n");
443 }
444 printer->Outdent();
445 printer->Print("}\n");
446 }
447
448 } // namespace cpp
449 } // namespace compiler
450 } // namespace protobuf
451 } // namespace google
452