cpp_primitive_field.cc revision d0332953cda33fb4f8e24ebff9c49159b69c43d6
1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://code.google.com/p/protobuf/
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  SetCommonFieldVariables(descriptor, variables);
85  (*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type());
86  (*variables)["default"] = DefaultValue(descriptor);
87  (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
88  int fixed_size = FixedSize(descriptor->type());
89  if (fixed_size != -1) {
90    (*variables)["fixed_size"] = SimpleItoa(fixed_size);
91  }
92  (*variables)["wire_format_field_type"] =
93      "::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name(
94          static_cast<FieldDescriptorProto_Type>(descriptor->type()));
95}
96
97}  // namespace
98
99// ===================================================================
100
101PrimitiveFieldGenerator::
102PrimitiveFieldGenerator(const FieldDescriptor* descriptor)
103  : descriptor_(descriptor) {
104  SetPrimitiveVariables(descriptor, &variables_);
105}
106
107PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
108
109void PrimitiveFieldGenerator::
110GeneratePrivateMembers(io::Printer* printer) const {
111  printer->Print(variables_, "$type$ $name$_;\n");
112}
113
114void PrimitiveFieldGenerator::
115GenerateAccessorDeclarations(io::Printer* printer) const {
116  printer->Print(variables_,
117    "inline $type$ $name$() const$deprecation$;\n"
118    "inline void set_$name$($type$ value)$deprecation$;\n");
119}
120
121void PrimitiveFieldGenerator::
122GenerateInlineAccessorDefinitions(io::Printer* printer) const {
123  printer->Print(variables_,
124    "inline $type$ $classname$::$name$() const {\n"
125    "  return $name$_;\n"
126    "}\n"
127    "inline void $classname$::set_$name$($type$ value) {\n"
128    "  _set_bit($index$);\n"
129    "  $name$_ = value;\n"
130    "}\n");
131}
132
133void PrimitiveFieldGenerator::
134GenerateClearingCode(io::Printer* printer) const {
135  printer->Print(variables_, "$name$_ = $default$;\n");
136}
137
138void PrimitiveFieldGenerator::
139GenerateMergingCode(io::Printer* printer) const {
140  printer->Print(variables_, "set_$name$(from.$name$());\n");
141}
142
143void PrimitiveFieldGenerator::
144GenerateSwappingCode(io::Printer* printer) const {
145  printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
146}
147
148void PrimitiveFieldGenerator::
149GenerateConstructorCode(io::Printer* printer) const {
150  printer->Print(variables_, "$name$_ = $default$;\n");
151}
152
153void PrimitiveFieldGenerator::
154GenerateMergeFromCodedStream(io::Printer* printer) const {
155  printer->Print(variables_,
156    "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
157    "         $type$, $wire_format_field_type$>(\n"
158    "       input, &$name$_)));\n"
159    "_set_bit($index$);\n");
160}
161
162void PrimitiveFieldGenerator::
163GenerateSerializeWithCachedSizes(io::Printer* printer) const {
164  printer->Print(variables_,
165    "::google::protobuf::internal::WireFormatLite::Write$declared_type$("
166      "$number$, this->$name$(), output);\n");
167}
168
169void PrimitiveFieldGenerator::
170GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
171  printer->Print(variables_,
172    "target = ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray("
173      "$number$, this->$name$(), target);\n");
174}
175
176void PrimitiveFieldGenerator::
177GenerateByteSize(io::Printer* printer) const {
178  int fixed_size = FixedSize(descriptor_->type());
179  if (fixed_size == -1) {
180    printer->Print(variables_,
181      "total_size += $tag_size$ +\n"
182      "  ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
183      "    this->$name$());\n");
184  } else {
185    printer->Print(variables_,
186      "total_size += $tag_size$ + $fixed_size$;\n");
187  }
188}
189
190// ===================================================================
191
192RepeatedPrimitiveFieldGenerator::
193RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor)
194  : descriptor_(descriptor) {
195  SetPrimitiveVariables(descriptor, &variables_);
196
197  if (descriptor->options().packed()) {
198    variables_["packed_reader"] = "ReadPackedPrimitive";
199    variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
200  } else {
201    variables_["packed_reader"] = "ReadPackedPrimitiveNoInline";
202    variables_["repeated_reader"] = "ReadRepeatedPrimitive";
203  }
204}
205
206RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
207
208void RepeatedPrimitiveFieldGenerator::
209GeneratePrivateMembers(io::Printer* printer) const {
210  printer->Print(variables_,
211    "::google::protobuf::RepeatedField< $type$ > $name$_;\n");
212  if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
213    printer->Print(variables_,
214      "mutable int _$name$_cached_byte_size_;\n");
215  }
216}
217
218void RepeatedPrimitiveFieldGenerator::
219GenerateAccessorDeclarations(io::Printer* printer) const {
220  printer->Print(variables_,
221    "inline $type$ $name$(int index) const$deprecation$;\n"
222    "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
223    "inline void add_$name$($type$ value)$deprecation$;\n");
224  printer->Print(variables_,
225    "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
226    "    $name$() const$deprecation$;\n"
227    "inline ::google::protobuf::RepeatedField< $type$ >*\n"
228    "    mutable_$name$()$deprecation$;\n");
229}
230
231void RepeatedPrimitiveFieldGenerator::
232GenerateInlineAccessorDefinitions(io::Printer* printer) const {
233  printer->Print(variables_,
234    "inline $type$ $classname$::$name$(int index) const {\n"
235    "  return $name$_.Get(index);\n"
236    "}\n"
237    "inline void $classname$::set_$name$(int index, $type$ value) {\n"
238    "  $name$_.Set(index, value);\n"
239    "}\n"
240    "inline void $classname$::add_$name$($type$ value) {\n"
241    "  $name$_.Add(value);\n"
242    "}\n");
243  printer->Print(variables_,
244    "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
245    "$classname$::$name$() const {\n"
246    "  return $name$_;\n"
247    "}\n"
248    "inline ::google::protobuf::RepeatedField< $type$ >*\n"
249    "$classname$::mutable_$name$() {\n"
250    "  return &$name$_;\n"
251    "}\n");
252}
253
254void RepeatedPrimitiveFieldGenerator::
255GenerateClearingCode(io::Printer* printer) const {
256  printer->Print(variables_, "$name$_.Clear();\n");
257}
258
259void RepeatedPrimitiveFieldGenerator::
260GenerateMergingCode(io::Printer* printer) const {
261  printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
262}
263
264void RepeatedPrimitiveFieldGenerator::
265GenerateSwappingCode(io::Printer* printer) const {
266  printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
267}
268
269void RepeatedPrimitiveFieldGenerator::
270GenerateConstructorCode(io::Printer* printer) const {
271  // Not needed for repeated fields.
272}
273
274void RepeatedPrimitiveFieldGenerator::
275GenerateMergeFromCodedStream(io::Printer* printer) const {
276  printer->Print(variables_,
277    "DO_((::google::protobuf::internal::WireFormatLite::$repeated_reader$<\n"
278    "         $type$, $wire_format_field_type$>(\n"
279    "       $tag_size$, $tag$, input, this->mutable_$name$())));\n");
280}
281
282void RepeatedPrimitiveFieldGenerator::
283GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
284  printer->Print(variables_,
285    "DO_((::google::protobuf::internal::WireFormatLite::$packed_reader$<\n"
286    "         $type$, $wire_format_field_type$>(\n"
287    "       input, this->mutable_$name$())));\n");
288}
289
290void RepeatedPrimitiveFieldGenerator::
291GenerateSerializeWithCachedSizes(io::Printer* printer) const {
292  if (descriptor_->options().packed()) {
293    // Write the tag and the size.
294    printer->Print(variables_,
295      "if (this->$name$_size() > 0) {\n"
296      "  ::google::protobuf::internal::WireFormatLite::WriteTag("
297          "$number$, "
298          "::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, "
299          "output);\n"
300      "  output->WriteVarint32(_$name$_cached_byte_size_);\n"
301      "}\n");
302  }
303  printer->Print(variables_,
304      "for (int i = 0; i < this->$name$_size(); i++) {\n");
305  if (descriptor_->options().packed()) {
306    printer->Print(variables_,
307      "  ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n"
308      "    this->$name$(i), output);\n");
309  } else {
310    printer->Print(variables_,
311      "  ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
312      "    $number$, this->$name$(i), output);\n");
313  }
314  printer->Print("}\n");
315}
316
317void RepeatedPrimitiveFieldGenerator::
318GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
319  if (descriptor_->options().packed()) {
320    // Write the tag and the size.
321    printer->Print(variables_,
322      "if (this->$name$_size() > 0) {\n"
323      "  target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
324      "    $number$,\n"
325      "    ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
326      "    target);\n"
327      "  target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n"
328      "    _$name$_cached_byte_size_, target);\n"
329      "}\n");
330  }
331  printer->Print(variables_,
332      "for (int i = 0; i < this->$name$_size(); i++) {\n");
333  if (descriptor_->options().packed()) {
334    printer->Print(variables_,
335      "  target = ::google::protobuf::internal::WireFormatLite::\n"
336      "    Write$declared_type$NoTagToArray(this->$name$(i), target);\n");
337  } else {
338    printer->Print(variables_,
339      "  target = ::google::protobuf::internal::WireFormatLite::\n"
340      "    Write$declared_type$ToArray($number$, this->$name$(i), target);\n");
341  }
342  printer->Print("}\n");
343}
344
345void RepeatedPrimitiveFieldGenerator::
346GenerateByteSize(io::Printer* printer) const {
347  printer->Print(variables_,
348    "{\n"
349    "  int data_size = 0;\n");
350  printer->Indent();
351  int fixed_size = FixedSize(descriptor_->type());
352  if (fixed_size == -1) {
353    printer->Print(variables_,
354      "for (int i = 0; i < this->$name$_size(); i++) {\n"
355      "  data_size += ::google::protobuf::internal::WireFormatLite::\n"
356      "    $declared_type$Size(this->$name$(i));\n"
357      "}\n");
358  } else {
359    printer->Print(variables_,
360      "data_size = $fixed_size$ * this->$name$_size();\n");
361  }
362
363  if (descriptor_->options().packed()) {
364    printer->Print(variables_,
365      "if (data_size > 0) {\n"
366      "  total_size += $tag_size$ +\n"
367      "    ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
368      "}\n"
369      "_$name$_cached_byte_size_ = data_size;\n"
370      "total_size += data_size;\n");
371  } else {
372    printer->Print(variables_,
373      "total_size += $tag_size$ * this->$name$_size() + data_size;\n");
374  }
375  printer->Outdent();
376  printer->Print("}\n");
377}
378
379}  // namespace cpp
380}  // namespace compiler
381}  // namespace protobuf
382}  // namespace google
383