• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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