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::PrimitiveFieldGenerator(
104    const FieldDescriptor* descriptor, const Options& options)
105    : FieldGenerator(options), descriptor_(descriptor) {
106  SetPrimitiveVariables(descriptor, &variables_, options);
107}
108
109PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
110
111void PrimitiveFieldGenerator::
112GeneratePrivateMembers(io::Printer* printer) const {
113  printer->Print(variables_, "$type$ $name$_;\n");
114}
115
116void PrimitiveFieldGenerator::
117GenerateAccessorDeclarations(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
123void PrimitiveFieldGenerator::
124GenerateInlineAccessorDefinitions(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
139void PrimitiveFieldGenerator::
140GenerateClearingCode(io::Printer* printer) const {
141  printer->Print(variables_, "$name$_ = $default$;\n");
142}
143
144void PrimitiveFieldGenerator::
145GenerateMergingCode(io::Printer* printer) const {
146  printer->Print(variables_, "set_$name$(from.$name$());\n");
147}
148
149void PrimitiveFieldGenerator::
150GenerateSwappingCode(io::Printer* printer) const {
151  printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
152}
153
154void PrimitiveFieldGenerator::
155GenerateConstructorCode(io::Printer* printer) const {
156  printer->Print(variables_, "$name$_ = $default$;\n");
157}
158
159void PrimitiveFieldGenerator::
160GenerateMergeFromCodedStream(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
168void PrimitiveFieldGenerator::
169GenerateSerializeWithCachedSizes(io::Printer* printer) const {
170  printer->Print(variables_,
171    "::google::protobuf::internal::WireFormatLite::Write$declared_type$("
172      "$number$, this->$name$(), output);\n");
173}
174
175void PrimitiveFieldGenerator::
176GenerateSerializeWithCachedSizesToArray(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
182void PrimitiveFieldGenerator::
183GenerateByteSize(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
198PrimitiveOneofFieldGenerator::
199PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
200                             const Options& options)
201  : PrimitiveFieldGenerator(descriptor, options) {
202  SetCommonOneofFieldVariables(descriptor, &variables_);
203}
204
205PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
206
207void PrimitiveOneofFieldGenerator::
208GenerateInlineAccessorDefinitions(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
229void PrimitiveOneofFieldGenerator::
230GenerateClearingCode(io::Printer* printer) const {
231  printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
232}
233
234void PrimitiveOneofFieldGenerator::
235GenerateSwappingCode(io::Printer* printer) const {
236  // Don't print any swapping code. Swapping the union will swap this field.
237}
238
239void PrimitiveOneofFieldGenerator::
240GenerateConstructorCode(io::Printer* printer) const {
241  printer->Print(
242      variables_,
243      "  $classname$_default_oneof_instance_->$name$_ = $default$;\n");
244}
245
246void PrimitiveOneofFieldGenerator::
247GenerateMergeFromCodedStream(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
258RepeatedPrimitiveFieldGenerator::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
272RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
273
274void RepeatedPrimitiveFieldGenerator::
275GeneratePrivateMembers(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
285void RepeatedPrimitiveFieldGenerator::
286GenerateAccessorDeclarations(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
298void RepeatedPrimitiveFieldGenerator::
299GenerateInlineAccessorDefinitions(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
328void RepeatedPrimitiveFieldGenerator::
329GenerateClearingCode(io::Printer* printer) const {
330  printer->Print(variables_, "$name$_.Clear();\n");
331}
332
333void RepeatedPrimitiveFieldGenerator::
334GenerateMergingCode(io::Printer* printer) const {
335  printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
336}
337
338void RepeatedPrimitiveFieldGenerator::
339GenerateSwappingCode(io::Printer* printer) const {
340  printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
341}
342
343void RepeatedPrimitiveFieldGenerator::
344GenerateConstructorCode(io::Printer* printer) const {
345  // Not needed for repeated fields.
346}
347
348void RepeatedPrimitiveFieldGenerator::
349GenerateMergeFromCodedStream(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
356void RepeatedPrimitiveFieldGenerator::
357GenerateMergeFromCodedStreamWithPacking(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
364void RepeatedPrimitiveFieldGenerator::
365GenerateSerializeWithCachedSizes(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
391void RepeatedPrimitiveFieldGenerator::
392GenerateSerializeWithCachedSizesToArray(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
419void RepeatedPrimitiveFieldGenerator::
420GenerateByteSize(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