blob: 5e8df0f49719de62f9f0d53ef9f14da03e1d9def [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
temporal40ee5512008-07-10 02:12:20 +00003// http://code.google.com/p/protobuf/
4//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * 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.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// 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.
temporal40ee5512008-07-10 02:12:20 +000030
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>
kenton@google.com80b1d622009-07-29 01:13:20 +000038#include <google/protobuf/wire_format.h>
temporal40ee5512008-07-10 02:12:20 +000039#include <google/protobuf/stubs/strutil.h>
40
41namespace google {
42namespace protobuf {
43namespace compiler {
44namespace cpp {
45
kenton@google.com80b1d622009-07-29 01:13:20 +000046using internal::WireFormatLite;
temporal40ee5512008-07-10 02:12:20 +000047
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;
kenton@google.com80b1d622009-07-29 01:13:20 +000060 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;
temporal40ee5512008-07-10 02:12:20 +000066
kenton@google.com80b1d622009-07-29 01:13:20 +000067 case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize;
temporal40ee5512008-07-10 02:12:20 +000068 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
temporal40ee5512008-07-10 02:12:20 +000082void SetPrimitiveVariables(const FieldDescriptor* descriptor,
83 map<string, string>* variables) {
kenton@google.com80b1d622009-07-29 01:13:20 +000084 SetCommonFieldVariables(descriptor, variables);
temporal40ee5512008-07-10 02:12:20 +000085 (*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type());
86 (*variables)["default"] = DefaultValue(descriptor);
kenton@google.comfccb1462009-12-18 02:11:36 +000087 (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
temporal40ee5512008-07-10 02:12:20 +000088 int fixed_size = FixedSize(descriptor->type());
89 if (fixed_size != -1) {
90 (*variables)["fixed_size"] = SimpleItoa(fixed_size);
91 }
kenton@google.comfccb1462009-12-18 02:11:36 +000092 (*variables)["wire_format_field_type"] =
93 "::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name(
94 static_cast<FieldDescriptorProto_Type>(descriptor->type()));
temporal40ee5512008-07-10 02:12:20 +000095}
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_,
kenton@google.com80b1d622009-07-29 01:13:20 +0000117 "inline $type$ $name$() const$deprecation$;\n"
118 "inline void set_$name$($type$ value)$deprecation$;\n");
temporal40ee5512008-07-10 02:12:20 +0000119}
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"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000128 " set_has_$name$();\n"
temporal40ee5512008-07-10 02:12:20 +0000129 " $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::
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000144GenerateSwappingCode(io::Printer* printer) const {
145 printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
146}
147
148void PrimitiveFieldGenerator::
kenton@google.comd37d46d2009-04-25 02:53:47 +0000149GenerateConstructorCode(io::Printer* printer) const {
150 printer->Print(variables_, "$name$_ = $default$;\n");
temporal40ee5512008-07-10 02:12:20 +0000151}
152
153void PrimitiveFieldGenerator::
154GenerateMergeFromCodedStream(io::Printer* printer) const {
155 printer->Print(variables_,
kenton@google.comfccb1462009-12-18 02:11:36 +0000156 "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
157 " $type$, $wire_format_field_type$>(\n"
158 " input, &$name$_)));\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000159 "set_has_$name$();\n");
temporal40ee5512008-07-10 02:12:20 +0000160}
161
162void PrimitiveFieldGenerator::
163GenerateSerializeWithCachedSizes(io::Printer* printer) const {
164 printer->Print(variables_,
kenton@google.com80b1d622009-07-29 01:13:20 +0000165 "::google::protobuf::internal::WireFormatLite::Write$declared_type$("
kenton@google.comd37d46d2009-04-25 02:53:47 +0000166 "$number$, this->$name$(), output);\n");
167}
168
169void PrimitiveFieldGenerator::
170GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
171 printer->Print(variables_,
kenton@google.com80b1d622009-07-29 01:13:20 +0000172 "target = ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray("
kenton@google.comd37d46d2009-04-25 02:53:47 +0000173 "$number$, this->$name$(), target);\n");
temporal40ee5512008-07-10 02:12:20 +0000174}
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"
kenton@google.com80b1d622009-07-29 01:13:20 +0000182 " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
temporal40ee5512008-07-10 02:12:20 +0000183 " 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_);
kenton@google.comfccb1462009-12-18 02:11:36 +0000196
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 }
temporal40ee5512008-07-10 02:12:20 +0000204}
205
206RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
207
208void RepeatedPrimitiveFieldGenerator::
209GeneratePrivateMembers(io::Printer* printer) const {
210 printer->Print(variables_,
211 "::google::protobuf::RepeatedField< $type$ > $name$_;\n");
kenton@google.com80b1d622009-07-29 01:13:20 +0000212 if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
kenton@google.com2d6daa72009-01-22 01:27:00 +0000213 printer->Print(variables_,
214 "mutable int _$name$_cached_byte_size_;\n");
215 }
temporal40ee5512008-07-10 02:12:20 +0000216}
217
218void RepeatedPrimitiveFieldGenerator::
219GenerateAccessorDeclarations(io::Printer* printer) const {
220 printer->Print(variables_,
kenton@google.com80b1d622009-07-29 01:13:20 +0000221 "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");
kenton@google.comfccb1462009-12-18 02:11:36 +0000224 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");
temporal40ee5512008-07-10 02:12:20 +0000229}
230
231void RepeatedPrimitiveFieldGenerator::
232GenerateInlineAccessorDefinitions(io::Printer* printer) const {
233 printer->Print(variables_,
temporal40ee5512008-07-10 02:12:20 +0000234 "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");
kenton@google.comfccb1462009-12-18 02:11:36 +0000243 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");
temporal40ee5512008-07-10 02:12:20 +0000252}
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::
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000265GenerateSwappingCode(io::Printer* printer) const {
266 printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
267}
268
269void RepeatedPrimitiveFieldGenerator::
kenton@google.comd37d46d2009-04-25 02:53:47 +0000270GenerateConstructorCode(io::Printer* printer) const {
271 // Not needed for repeated fields.
temporal40ee5512008-07-10 02:12:20 +0000272}
273
274void RepeatedPrimitiveFieldGenerator::
275GenerateMergeFromCodedStream(io::Printer* printer) const {
kenton@google.comfccb1462009-12-18 02:11:36 +0000276 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");
temporal40ee5512008-07-10 02:12:20 +0000288}
289
290void RepeatedPrimitiveFieldGenerator::
291GenerateSerializeWithCachedSizes(io::Printer* printer) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +0000292 if (descriptor_->options().packed()) {
293 // Write the tag and the size.
294 printer->Print(variables_,
295 "if (this->$name$_size() > 0) {\n"
kenton@google.com80b1d622009-07-29 01:13:20 +0000296 " ::google::protobuf::internal::WireFormatLite::WriteTag("
kenton@google.comd37d46d2009-04-25 02:53:47 +0000297 "$number$, "
kenton@google.com80b1d622009-07-29 01:13:20 +0000298 "::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, "
kenton@google.comd37d46d2009-04-25 02:53:47 +0000299 "output);\n"
300 " output->WriteVarint32(_$name$_cached_byte_size_);\n"
kenton@google.com2d6daa72009-01-22 01:27:00 +0000301 "}\n");
302 }
temporal40ee5512008-07-10 02:12:20 +0000303 printer->Print(variables_,
kenton@google.com2d6daa72009-01-22 01:27:00 +0000304 "for (int i = 0; i < this->$name$_size(); i++) {\n");
305 if (descriptor_->options().packed()) {
306 printer->Print(variables_,
kenton@google.com80b1d622009-07-29 01:13:20 +0000307 " ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n"
308 " this->$name$(i), output);\n");
kenton@google.com2d6daa72009-01-22 01:27:00 +0000309 } else {
310 printer->Print(variables_,
kenton@google.com80b1d622009-07-29 01:13:20 +0000311 " ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
312 " $number$, this->$name$(i), output);\n");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000313 }
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"
kenton@google.com80b1d622009-07-29 01:13:20 +0000323 " 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"
kenton@google.comd37d46d2009-04-25 02:53:47 +0000329 "}\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_,
kenton@google.com80b1d622009-07-29 01:13:20 +0000335 " target = ::google::protobuf::internal::WireFormatLite::\n"
336 " Write$declared_type$NoTagToArray(this->$name$(i), target);\n");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000337 } else {
338 printer->Print(variables_,
kenton@google.com80b1d622009-07-29 01:13:20 +0000339 " target = ::google::protobuf::internal::WireFormatLite::\n"
340 " Write$declared_type$ToArray($number$, this->$name$(i), target);\n");
kenton@google.com2d6daa72009-01-22 01:27:00 +0000341 }
342 printer->Print("}\n");
temporal40ee5512008-07-10 02:12:20 +0000343}
344
345void RepeatedPrimitiveFieldGenerator::
346GenerateByteSize(io::Printer* printer) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +0000347 printer->Print(variables_,
348 "{\n"
349 " int data_size = 0;\n");
350 printer->Indent();
temporal40ee5512008-07-10 02:12:20 +0000351 int fixed_size = FixedSize(descriptor_->type());
352 if (fixed_size == -1) {
353 printer->Print(variables_,
kenton@google.com2d6daa72009-01-22 01:27:00 +0000354 "for (int i = 0; i < this->$name$_size(); i++) {\n"
kenton@google.com80b1d622009-07-29 01:13:20 +0000355 " data_size += ::google::protobuf::internal::WireFormatLite::\n"
356 " $declared_type$Size(this->$name$(i));\n"
temporal40ee5512008-07-10 02:12:20 +0000357 "}\n");
358 } else {
359 printer->Print(variables_,
kenton@google.com2d6daa72009-01-22 01:27:00 +0000360 "data_size = $fixed_size$ * this->$name$_size();\n");
temporal40ee5512008-07-10 02:12:20 +0000361 }
kenton@google.com2d6daa72009-01-22 01:27:00 +0000362
363 if (descriptor_->options().packed()) {
364 printer->Print(variables_,
365 "if (data_size > 0) {\n"
kenton@google.com80b1d622009-07-29 01:13:20 +0000366 " total_size += $tag_size$ +\n"
367 " ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
kenton@google.com2d6daa72009-01-22 01:27:00 +0000368 "}\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");
temporal40ee5512008-07-10 02:12:20 +0000377}
378
379} // namespace cpp
380} // namespace compiler
381} // namespace protobuf
382} // namespace google