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
41namespace google {
42namespace protobuf {
43namespace compiler {
44namespace cpp {
45
46using internal::WireFormatLite;
47
48namespace {
49
50// For encodings with fixed sizes, returns that size in bytes.  Otherwise
51// returns -1.
52int 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
82void 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
103PrimitiveFieldGenerator::
104PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
105                        const Options& options)
106  : descriptor_(descriptor) {
107  SetPrimitiveVariables(descriptor, &variables_, options);
108}
109
110PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
111
112void PrimitiveFieldGenerator::
113GeneratePrivateMembers(io::Printer* printer) const {
114  printer->Print(variables_, "$type$ $name$_;\n");
115}
116
117void PrimitiveFieldGenerator::
118GenerateAccessorDeclarations(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
124void PrimitiveFieldGenerator::
125GenerateInlineAccessorDefinitions(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
138void PrimitiveFieldGenerator::
139GenerateClearingCode(io::Printer* printer) const {
140  printer->Print(variables_, "$name$_ = $default$;\n");
141}
142
143void PrimitiveFieldGenerator::
144GenerateMergingCode(io::Printer* printer) const {
145  printer->Print(variables_, "set_$name$(from.$name$());\n");
146}
147
148void PrimitiveFieldGenerator::
149GenerateSwappingCode(io::Printer* printer) const {
150  printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
151}
152
153void PrimitiveFieldGenerator::
154GenerateConstructorCode(io::Printer* printer) const {
155  printer->Print(variables_, "$name$_ = $default$;\n");
156}
157
158void PrimitiveFieldGenerator::
159GenerateMergeFromCodedStream(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
167void PrimitiveFieldGenerator::
168GenerateSerializeWithCachedSizes(io::Printer* printer) const {
169  printer->Print(variables_,
170    "::google::protobuf::internal::WireFormatLite::Write$declared_type$("
171      "$number$, this->$name$(), output);\n");
172}
173
174void PrimitiveFieldGenerator::
175GenerateSerializeWithCachedSizesToArray(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
181void PrimitiveFieldGenerator::
182GenerateByteSize(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
197PrimitiveOneofFieldGenerator::
198PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
199                             const Options& options)
200  : PrimitiveFieldGenerator(descriptor, options) {
201  SetCommonOneofFieldVariables(descriptor, &variables_);
202}
203
204PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
205
206void PrimitiveOneofFieldGenerator::
207GenerateInlineAccessorDefinitions(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
224void PrimitiveOneofFieldGenerator::
225GenerateClearingCode(io::Printer* printer) const {
226  printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
227}
228
229void PrimitiveOneofFieldGenerator::
230GenerateSwappingCode(io::Printer* printer) const {
231  // Don't print any swapping code. Swapping the union will swap this field.
232}
233
234void PrimitiveOneofFieldGenerator::
235GenerateConstructorCode(io::Printer* printer) const {
236  printer->Print(
237      variables_,
238      "  $classname$_default_oneof_instance_->$name$_ = $default$;\n");
239}
240
241void PrimitiveOneofFieldGenerator::
242GenerateMergeFromCodedStream(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
253RepeatedPrimitiveFieldGenerator::
254RepeatedPrimitiveFieldGenerator(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
268RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
269
270void RepeatedPrimitiveFieldGenerator::
271GeneratePrivateMembers(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
280void RepeatedPrimitiveFieldGenerator::
281GenerateAccessorDeclarations(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
293void RepeatedPrimitiveFieldGenerator::
294GenerateInlineAccessorDefinitions(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
321void RepeatedPrimitiveFieldGenerator::
322GenerateClearingCode(io::Printer* printer) const {
323  printer->Print(variables_, "$name$_.Clear();\n");
324}
325
326void RepeatedPrimitiveFieldGenerator::
327GenerateMergingCode(io::Printer* printer) const {
328  printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
329}
330
331void RepeatedPrimitiveFieldGenerator::
332GenerateSwappingCode(io::Printer* printer) const {
333  printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
334}
335
336void RepeatedPrimitiveFieldGenerator::
337GenerateConstructorCode(io::Printer* printer) const {
338  // Not needed for repeated fields.
339}
340
341void RepeatedPrimitiveFieldGenerator::
342GenerateMergeFromCodedStream(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
349void RepeatedPrimitiveFieldGenerator::
350GenerateMergeFromCodedStreamWithPacking(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
357void RepeatedPrimitiveFieldGenerator::
358GenerateSerializeWithCachedSizes(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
384void RepeatedPrimitiveFieldGenerator::
385GenerateSerializeWithCachedSizesToArray(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
412void RepeatedPrimitiveFieldGenerator::
413GenerateByteSize(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