blob: addb881906e5a100b8f6e31d81ef9a8376a67360 [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 <map>
36#include <string>
37
38#include <google/protobuf/compiler/java/java_primitive_field.h>
39#include <google/protobuf/stubs/common.h>
40#include <google/protobuf/compiler/java/java_helpers.h>
41#include <google/protobuf/io/printer.h>
kenton@google.com80b1d622009-07-29 01:13:20 +000042#include <google/protobuf/wire_format.h>
temporal40ee5512008-07-10 02:12:20 +000043#include <google/protobuf/stubs/strutil.h>
temporal40ee5512008-07-10 02:12:20 +000044
45namespace google {
46namespace protobuf {
47namespace compiler {
48namespace java {
49
kenton@google.com2d6daa72009-01-22 01:27:00 +000050using internal::WireFormat;
kenton@google.com80b1d622009-07-29 01:13:20 +000051using internal::WireFormatLite;
kenton@google.com2d6daa72009-01-22 01:27:00 +000052
temporal40ee5512008-07-10 02:12:20 +000053namespace {
54
55const char* PrimitiveTypeName(JavaType type) {
56 switch (type) {
57 case JAVATYPE_INT : return "int";
58 case JAVATYPE_LONG : return "long";
59 case JAVATYPE_FLOAT : return "float";
60 case JAVATYPE_DOUBLE : return "double";
61 case JAVATYPE_BOOLEAN: return "boolean";
62 case JAVATYPE_STRING : return "java.lang.String";
63 case JAVATYPE_BYTES : return "com.google.protobuf.ByteString";
64 case JAVATYPE_ENUM : return NULL;
65 case JAVATYPE_MESSAGE: return NULL;
66
67 // No default because we want the compiler to complain if any new
68 // JavaTypes are added.
69 }
70
71 GOOGLE_LOG(FATAL) << "Can't get here.";
72 return NULL;
73}
74
kenton@google.com2d6daa72009-01-22 01:27:00 +000075bool IsReferenceType(JavaType type) {
76 switch (type) {
77 case JAVATYPE_INT : return false;
78 case JAVATYPE_LONG : return false;
79 case JAVATYPE_FLOAT : return false;
80 case JAVATYPE_DOUBLE : return false;
81 case JAVATYPE_BOOLEAN: return false;
82 case JAVATYPE_STRING : return true;
83 case JAVATYPE_BYTES : return true;
84 case JAVATYPE_ENUM : return true;
85 case JAVATYPE_MESSAGE: return true;
86
87 // No default because we want the compiler to complain if any new
88 // JavaTypes are added.
89 }
90
91 GOOGLE_LOG(FATAL) << "Can't get here.";
92 return false;
93}
94
temporal40ee5512008-07-10 02:12:20 +000095const char* GetCapitalizedType(const FieldDescriptor* field) {
kenton@google.comfccb1462009-12-18 02:11:36 +000096 switch (GetType(field)) {
temporal40ee5512008-07-10 02:12:20 +000097 case FieldDescriptor::TYPE_INT32 : return "Int32" ;
98 case FieldDescriptor::TYPE_UINT32 : return "UInt32" ;
99 case FieldDescriptor::TYPE_SINT32 : return "SInt32" ;
100 case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ;
101 case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
102 case FieldDescriptor::TYPE_INT64 : return "Int64" ;
103 case FieldDescriptor::TYPE_UINT64 : return "UInt64" ;
104 case FieldDescriptor::TYPE_SINT64 : return "SInt64" ;
105 case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ;
106 case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
107 case FieldDescriptor::TYPE_FLOAT : return "Float" ;
108 case FieldDescriptor::TYPE_DOUBLE : return "Double" ;
109 case FieldDescriptor::TYPE_BOOL : return "Bool" ;
110 case FieldDescriptor::TYPE_STRING : return "String" ;
111 case FieldDescriptor::TYPE_BYTES : return "Bytes" ;
112 case FieldDescriptor::TYPE_ENUM : return "Enum" ;
113 case FieldDescriptor::TYPE_GROUP : return "Group" ;
114 case FieldDescriptor::TYPE_MESSAGE : return "Message" ;
115
116 // No default because we want the compiler to complain if any new
117 // types are added.
118 }
119
120 GOOGLE_LOG(FATAL) << "Can't get here.";
121 return NULL;
122}
123
kenton@google.com2d6daa72009-01-22 01:27:00 +0000124// For encodings with fixed sizes, returns that size in bytes. Otherwise
125// returns -1.
126int FixedSize(FieldDescriptor::Type type) {
127 switch (type) {
128 case FieldDescriptor::TYPE_INT32 : return -1;
129 case FieldDescriptor::TYPE_INT64 : return -1;
130 case FieldDescriptor::TYPE_UINT32 : return -1;
131 case FieldDescriptor::TYPE_UINT64 : return -1;
132 case FieldDescriptor::TYPE_SINT32 : return -1;
133 case FieldDescriptor::TYPE_SINT64 : return -1;
kenton@google.com80b1d622009-07-29 01:13:20 +0000134 case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
135 case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
136 case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
137 case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
138 case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize;
139 case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize;
kenton@google.com2d6daa72009-01-22 01:27:00 +0000140
kenton@google.com80b1d622009-07-29 01:13:20 +0000141 case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize;
kenton@google.com2d6daa72009-01-22 01:27:00 +0000142 case FieldDescriptor::TYPE_ENUM : return -1;
143
144 case FieldDescriptor::TYPE_STRING : return -1;
145 case FieldDescriptor::TYPE_BYTES : return -1;
146 case FieldDescriptor::TYPE_GROUP : return -1;
147 case FieldDescriptor::TYPE_MESSAGE : return -1;
148
149 // No default because we want the compiler to complain if any new
150 // types are added.
151 }
152 GOOGLE_LOG(FATAL) << "Can't get here.";
153 return -1;
154}
155
temporal40ee5512008-07-10 02:12:20 +0000156void SetPrimitiveVariables(const FieldDescriptor* descriptor,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000157 int messageBitIndex,
158 int builderBitIndex,
temporal40ee5512008-07-10 02:12:20 +0000159 map<string, string>* variables) {
160 (*variables)["name"] =
161 UnderscoresToCamelCase(descriptor);
162 (*variables)["capitalized_name"] =
163 UnderscoresToCapitalizedCamelCase(descriptor);
liujisi@google.com33165fe2010-11-02 13:14:58 +0000164 (*variables)["constant_name"] = FieldConstantName(descriptor);
temporal40ee5512008-07-10 02:12:20 +0000165 (*variables)["number"] = SimpleItoa(descriptor->number());
166 (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
167 (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
liujisi@google.com33165fe2010-11-02 13:14:58 +0000168 (*variables)["field_type"] = (*variables)["type"];
169 (*variables)["field_list_type"] = "java.util.List<" +
170 (*variables)["boxed_type"] + ">";
171 (*variables)["empty_list"] = "java.util.Collections.emptyList();";
temporal40ee5512008-07-10 02:12:20 +0000172 (*variables)["default"] = DefaultValue(descriptor);
liujisi@google.com33165fe2010-11-02 13:14:58 +0000173 (*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ?
174 "" : ("= " + DefaultValue(descriptor));
temporal40ee5512008-07-10 02:12:20 +0000175 (*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
kenton@google.com2d6daa72009-01-22 01:27:00 +0000176 (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
177 (*variables)["tag_size"] = SimpleItoa(
kenton@google.comfccb1462009-12-18 02:11:36 +0000178 WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
kenton@google.com2d6daa72009-01-22 01:27:00 +0000179 if (IsReferenceType(GetJavaType(descriptor))) {
180 (*variables)["null_check"] =
181 " if (value == null) {\n"
182 " throw new NullPointerException();\n"
183 " }\n";
184 } else {
185 (*variables)["null_check"] = "";
186 }
liujisi@google.com33165fe2010-11-02 13:14:58 +0000187 // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
188 // by the proto compiler
189 (*variables)["deprecation"] = descriptor->options().deprecated()
190 ? "@java.lang.Deprecated " : "";
kenton@google.comfccb1462009-12-18 02:11:36 +0000191 int fixed_size = FixedSize(GetType(descriptor));
kenton@google.com2d6daa72009-01-22 01:27:00 +0000192 if (fixed_size != -1) {
193 (*variables)["fixed_size"] = SimpleItoa(fixed_size);
194 }
liujisi@google.com33165fe2010-11-02 13:14:58 +0000195 (*variables)["on_changed"] =
196 HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
197
198 // For singular messages and builders, one bit is used for the hasField bit.
199 (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
200
201 (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
202 (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
203 (*variables)["clear_has_field_bit_builder"] =
204 GenerateClearBit(builderBitIndex);
205
206 // For repated builders, one bit is used for whether the array is immutable.
207 (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
208 (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
209 (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
210
211 (*variables)["get_has_field_bit_from_local"] =
212 GenerateGetBitFromLocal(builderBitIndex);
213 (*variables)["set_has_field_bit_to_local"] =
214 GenerateSetBitToLocal(messageBitIndex);
temporal40ee5512008-07-10 02:12:20 +0000215}
liujisi@google.com33165fe2010-11-02 13:14:58 +0000216
temporal40ee5512008-07-10 02:12:20 +0000217} // namespace
218
219// ===================================================================
220
221PrimitiveFieldGenerator::
liujisi@google.com33165fe2010-11-02 13:14:58 +0000222PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
223 int messageBitIndex,
224 int builderBitIndex)
225 : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
226 builderBitIndex_(builderBitIndex) {
227 SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
228 &variables_);
temporal40ee5512008-07-10 02:12:20 +0000229}
230
231PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
232
liujisi@google.com33165fe2010-11-02 13:14:58 +0000233int PrimitiveFieldGenerator::GetNumBitsForMessage() const {
234 return 1;
235}
236
237int PrimitiveFieldGenerator::GetNumBitsForBuilder() const {
238 return 1;
239}
240
241void PrimitiveFieldGenerator::
242GenerateInterfaceMembers(io::Printer* printer) const {
243 printer->Print(variables_,
244 "$deprecation$boolean has$capitalized_name$();\n"
245 "$deprecation$$type$ get$capitalized_name$();\n");
246}
247
temporal40ee5512008-07-10 02:12:20 +0000248void PrimitiveFieldGenerator::
249GenerateMembers(io::Printer* printer) const {
250 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000251 "private $field_type$ $name$_;\n"
252 "$deprecation$public boolean has$capitalized_name$() {\n"
253 " return $get_has_field_bit_message$;\n"
254 "}\n");
255
256 printer->Print(variables_,
257 "$deprecation$public $type$ get$capitalized_name$() {\n"
258 " return $name$_;\n"
259 "}\n");
temporal40ee5512008-07-10 02:12:20 +0000260}
261
262void PrimitiveFieldGenerator::
263GenerateBuilderMembers(io::Printer* printer) const {
264 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000265 "private $field_type$ $name$_ $default_init$;\n"
266 "$deprecation$public boolean has$capitalized_name$() {\n"
267 " return $get_has_field_bit_builder$;\n"
268 "}\n");
269
270 printer->Print(variables_,
271 "$deprecation$public $type$ get$capitalized_name$() {\n"
272 " return $name$_;\n"
273 "}\n");
274
275 printer->Print(variables_,
276 "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
kenton@google.com2d6daa72009-01-22 01:27:00 +0000277 "$null_check$"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000278 " $set_has_field_bit_builder$;\n"
279 " $name$_ = value;\n"
280 " $on_changed$\n"
temporal40ee5512008-07-10 02:12:20 +0000281 " return this;\n"
282 "}\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000283 "$deprecation$public Builder clear$capitalized_name$() {\n"
284 " $clear_has_field_bit_builder$;\n");
kenton@google.comfccb1462009-12-18 02:11:36 +0000285 JavaType type = GetJavaType(descriptor_);
286 if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) {
kenton@google.com80b1d622009-07-29 01:13:20 +0000287 // The default value is not a simple literal so we want to avoid executing
288 // it multiple times. Instead, get the default out of the default instance.
289 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000290 " $name$_ = getDefaultInstance().get$capitalized_name$();\n");
kenton@google.com80b1d622009-07-29 01:13:20 +0000291 } else {
292 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000293 " $name$_ = $default$;\n");
kenton@google.com80b1d622009-07-29 01:13:20 +0000294 }
295 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000296 " $on_changed$\n"
temporal40ee5512008-07-10 02:12:20 +0000297 " return this;\n"
298 "}\n");
299}
300
301void PrimitiveFieldGenerator::
liujisi@google.com33165fe2010-11-02 13:14:58 +0000302GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
303 // noop for primitives
304}
305
306void PrimitiveFieldGenerator::
kenton@google.comfccb1462009-12-18 02:11:36 +0000307GenerateInitializationCode(io::Printer* printer) const {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000308 printer->Print(variables_, "$name$_ = $default$;\n");
309}
310
311void PrimitiveFieldGenerator::
312GenerateBuilderClearCode(io::Printer* printer) const {
313 printer->Print(variables_,
314 "$name$_ = $default$;\n"
315 "$clear_has_field_bit_builder$;\n");
kenton@google.comfccb1462009-12-18 02:11:36 +0000316}
317
318void PrimitiveFieldGenerator::
temporal40ee5512008-07-10 02:12:20 +0000319GenerateMergingCode(io::Printer* printer) const {
320 printer->Print(variables_,
321 "if (other.has$capitalized_name$()) {\n"
322 " set$capitalized_name$(other.get$capitalized_name$());\n"
323 "}\n");
324}
325
326void PrimitiveFieldGenerator::
327GenerateBuildingCode(io::Printer* printer) const {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000328 printer->Print(variables_,
329 "if ($get_has_field_bit_from_local$) {\n"
330 " $set_has_field_bit_to_local$;\n"
331 "}\n"
332 "result.$name$_ = $name$_;\n");
temporal40ee5512008-07-10 02:12:20 +0000333}
334
335void PrimitiveFieldGenerator::
336GenerateParsingCode(io::Printer* printer) const {
337 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000338 "$set_has_field_bit_builder$;\n"
339 "$name$_ = input.read$capitalized_type$();\n");
temporal40ee5512008-07-10 02:12:20 +0000340}
341
342void PrimitiveFieldGenerator::
343GenerateSerializationCode(io::Printer* printer) const {
kenton@google.coma4a9ef82010-09-17 23:20:04 +0000344 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000345 "if ($get_has_field_bit_message$) {\n"
346 " output.write$capitalized_type$($number$, $name$_);\n"
kenton@google.coma4a9ef82010-09-17 23:20:04 +0000347 "}\n");
temporal40ee5512008-07-10 02:12:20 +0000348}
349
350void PrimitiveFieldGenerator::
351GenerateSerializedSizeCode(io::Printer* printer) const {
kenton@google.coma4a9ef82010-09-17 23:20:04 +0000352 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000353 "if ($get_has_field_bit_message$) {\n"
kenton@google.coma4a9ef82010-09-17 23:20:04 +0000354 " size += com.google.protobuf.CodedOutputStream\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000355 " .compute$capitalized_type$Size($number$, $name$_);\n"
kenton@google.coma4a9ef82010-09-17 23:20:04 +0000356 "}\n");
temporal40ee5512008-07-10 02:12:20 +0000357}
358
liujisi@google.com33165fe2010-11-02 13:14:58 +0000359void PrimitiveFieldGenerator::
360GenerateEqualsCode(io::Printer* printer) const {
361 switch (GetJavaType(descriptor_)) {
362 case JAVATYPE_INT:
363 case JAVATYPE_LONG:
364 case JAVATYPE_BOOLEAN:
365 printer->Print(variables_,
366 "result = result && (get$capitalized_name$()\n"
367 " == other.get$capitalized_name$());\n");
368 break;
369
370 case JAVATYPE_FLOAT:
371 printer->Print(variables_,
372 "result = result && (Float.floatToIntBits(get$capitalized_name$())"
373 " == Float.floatToIntBits(other.get$capitalized_name$()));\n");
374 break;
375
376 case JAVATYPE_DOUBLE:
377 printer->Print(variables_,
378 "result = result && (Double.doubleToLongBits(get$capitalized_name$())"
379 " == Double.doubleToLongBits(other.get$capitalized_name$()));\n");
380 break;
381
382 case JAVATYPE_STRING:
383 case JAVATYPE_BYTES:
384 printer->Print(variables_,
385 "result = result && get$capitalized_name$()\n"
386 " .equals(other.get$capitalized_name$());\n");
387 break;
388
389 case JAVATYPE_ENUM:
390 case JAVATYPE_MESSAGE:
391 default:
392 GOOGLE_LOG(FATAL) << "Can't get here.";
393 break;
394 }
395}
396
397void PrimitiveFieldGenerator::
398GenerateHashCode(io::Printer* printer) const {
399 printer->Print(variables_,
400 "hash = (37 * hash) + $constant_name$;\n");
401 switch (GetJavaType(descriptor_)) {
402 case JAVATYPE_INT:
403 printer->Print(variables_,
404 "hash = (53 * hash) + get$capitalized_name$();\n");
405 break;
406
407 case JAVATYPE_LONG:
408 printer->Print(variables_,
409 "hash = (53 * hash) + hashLong(get$capitalized_name$());\n");
410 break;
411
412 case JAVATYPE_BOOLEAN:
413 printer->Print(variables_,
414 "hash = (53 * hash) + hashBoolean(get$capitalized_name$());\n");
415 break;
416
417 case JAVATYPE_FLOAT:
418 printer->Print(variables_,
419 "hash = (53 * hash) + Float.floatToIntBits(\n"
420 " get$capitalized_name$());\n");
421 break;
422
423 case JAVATYPE_DOUBLE:
424 printer->Print(variables_,
425 "hash = (53 * hash) + hashLong(\n"
426 " Double.doubleToLongBits(get$capitalized_name$()));\n");
427 break;
428
429 case JAVATYPE_STRING:
430 case JAVATYPE_BYTES:
431 printer->Print(variables_,
432 "hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
433 break;
434
435 case JAVATYPE_ENUM:
436 case JAVATYPE_MESSAGE:
437 default:
438 GOOGLE_LOG(FATAL) << "Can't get here.";
439 break;
440 }
441}
442
temporal40ee5512008-07-10 02:12:20 +0000443string PrimitiveFieldGenerator::GetBoxedType() const {
444 return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
445}
446
447// ===================================================================
448
449RepeatedPrimitiveFieldGenerator::
liujisi@google.com33165fe2010-11-02 13:14:58 +0000450RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
451 int messageBitIndex,
452 int builderBitIndex)
453 : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
454 builderBitIndex_(builderBitIndex) {
455 SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
456 &variables_);
temporal40ee5512008-07-10 02:12:20 +0000457}
458
459RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
460
liujisi@google.com33165fe2010-11-02 13:14:58 +0000461int RepeatedPrimitiveFieldGenerator::GetNumBitsForMessage() const {
462 return 0;
463}
464
465int RepeatedPrimitiveFieldGenerator::GetNumBitsForBuilder() const {
466 return 1;
467}
468
469void RepeatedPrimitiveFieldGenerator::
470GenerateInterfaceMembers(io::Printer* printer) const {
471 printer->Print(variables_,
472 "$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n"
473 "$deprecation$int get$capitalized_name$Count();\n"
474 "$deprecation$$type$ get$capitalized_name$(int index);\n");
475}
476
477
temporal40ee5512008-07-10 02:12:20 +0000478void RepeatedPrimitiveFieldGenerator::
479GenerateMembers(io::Printer* printer) const {
480 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000481 "private $field_list_type$ $name$_;\n"
482 "$deprecation$public java.util.List<$boxed_type$>\n"
483 " get$capitalized_name$List() {\n"
temporal40ee5512008-07-10 02:12:20 +0000484 " return $name$_;\n" // note: unmodifiable list
485 "}\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000486 "$deprecation$public int get$capitalized_name$Count() {\n"
487 " return $name$_.size();\n"
488 "}\n"
489 "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
temporal40ee5512008-07-10 02:12:20 +0000490 " return $name$_.get(index);\n"
491 "}\n");
kenton@google.com2d6daa72009-01-22 01:27:00 +0000492
493 if (descriptor_->options().packed() &&
kenton@google.com80b1d622009-07-29 01:13:20 +0000494 HasGeneratedMethods(descriptor_->containing_type())) {
kenton@google.com2d6daa72009-01-22 01:27:00 +0000495 printer->Print(variables_,
jasonh+personal@google.com99512332009-12-01 18:05:21 +0000496 "private int $name$MemoizedSerializedSize = -1;\n");
kenton@google.com2d6daa72009-01-22 01:27:00 +0000497 }
temporal40ee5512008-07-10 02:12:20 +0000498}
499
500void RepeatedPrimitiveFieldGenerator::
501GenerateBuilderMembers(io::Printer* printer) const {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000502 // One field is the list and the bit field keeps track of whether the
503 // list is immutable. If it's immutable, the invariant is that it must
504 // either an instance of Collections.emptyList() or it's an ArrayList
505 // wrapped in a Collections.unmodifiableList() wrapper and nobody else has
506 // a refererence to the underlying ArrayList. This invariant allows us to
507 // share instances of lists between protocol buffers avoiding expensive
508 // memory allocations. Note, immutable is a strong guarantee here -- not
509 // just that the list cannot be modified via the reference but that the
510 // list can never be modified.
temporal40ee5512008-07-10 02:12:20 +0000511 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000512 "private $field_list_type$ $name$_ = $empty_list$;\n");
513
514 printer->Print(variables_,
515 "private void ensure$capitalized_name$IsMutable() {\n"
516 " if (!$get_mutable_bit_builder$) {\n"
517 " $name$_ = new java.util.ArrayList<$boxed_type$>($name$_);\n"
518 " $set_mutable_bit_builder$;\n"
519 " }\n"
520 "}\n");
521
temporal40ee5512008-07-10 02:12:20 +0000522 // Note: We return an unmodifiable list because otherwise the caller
523 // could hold on to the returned list and modify it after the message
524 // has been built, thus mutating the message which is supposed to be
525 // immutable.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000526 printer->Print(variables_,
527 "$deprecation$public java.util.List<$boxed_type$>\n"
528 " get$capitalized_name$List() {\n"
529 " return java.util.Collections.unmodifiableList($name$_);\n"
temporal40ee5512008-07-10 02:12:20 +0000530 "}\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000531 "$deprecation$public int get$capitalized_name$Count() {\n"
532 " return $name$_.size();\n"
temporal40ee5512008-07-10 02:12:20 +0000533 "}\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000534 "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
535 " return $name$_.get(index);\n"
temporal40ee5512008-07-10 02:12:20 +0000536 "}\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000537 "$deprecation$public Builder set$capitalized_name$(\n"
538 " int index, $type$ value) {\n"
kenton@google.com2d6daa72009-01-22 01:27:00 +0000539 "$null_check$"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000540 " ensure$capitalized_name$IsMutable();\n"
541 " $name$_.set(index, value);\n"
542 " $on_changed$\n"
temporal40ee5512008-07-10 02:12:20 +0000543 " return this;\n"
544 "}\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000545 "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
kenton@google.com2d6daa72009-01-22 01:27:00 +0000546 "$null_check$"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000547 " ensure$capitalized_name$IsMutable();\n"
548 " $name$_.add(value);\n"
549 " $on_changed$\n"
temporal40ee5512008-07-10 02:12:20 +0000550 " return this;\n"
551 "}\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000552 "$deprecation$public Builder addAll$capitalized_name$(\n"
temporal40ee5512008-07-10 02:12:20 +0000553 " java.lang.Iterable<? extends $boxed_type$> values) {\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000554 " ensure$capitalized_name$IsMutable();\n"
555 " super.addAll(values, $name$_);\n"
556 " $on_changed$\n"
temporal40ee5512008-07-10 02:12:20 +0000557 " return this;\n"
558 "}\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000559 "$deprecation$public Builder clear$capitalized_name$() {\n"
560 " $name$_ = $empty_list$;\n"
561 " $clear_mutable_bit_builder$;\n"
562 " $on_changed$\n"
temporal40ee5512008-07-10 02:12:20 +0000563 " return this;\n"
564 "}\n");
565}
566
567void RepeatedPrimitiveFieldGenerator::
liujisi@google.com33165fe2010-11-02 13:14:58 +0000568GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
569 // noop for primitives
570}
571
572void RepeatedPrimitiveFieldGenerator::
kenton@google.comfccb1462009-12-18 02:11:36 +0000573GenerateInitializationCode(io::Printer* printer) const {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000574 printer->Print(variables_, "$name$_ = $empty_list$;\n");
575}
576
577void RepeatedPrimitiveFieldGenerator::
578GenerateBuilderClearCode(io::Printer* printer) const {
579 printer->Print(variables_,
580 "$name$_ = $empty_list$;\n"
581 "$clear_mutable_bit_builder$;\n");
kenton@google.comfccb1462009-12-18 02:11:36 +0000582}
583
584void RepeatedPrimitiveFieldGenerator::
temporal40ee5512008-07-10 02:12:20 +0000585GenerateMergingCode(io::Printer* printer) const {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000586 // The code below does two optimizations:
587 // 1. If the other list is empty, there's nothing to do. This ensures we
588 // don't allocate a new array if we already have an immutable one.
589 // 2. If the other list is non-empty and our current list is empty, we can
590 // reuse the other list which is guaranteed to be immutable.
temporal40ee5512008-07-10 02:12:20 +0000591 printer->Print(variables_,
592 "if (!other.$name$_.isEmpty()) {\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000593 " if ($name$_.isEmpty()) {\n"
594 " $name$_ = other.$name$_;\n"
595 " $clear_mutable_bit_builder$;\n"
596 " } else {\n"
597 " ensure$capitalized_name$IsMutable();\n"
598 " $name$_.addAll(other.$name$_);\n"
temporal40ee5512008-07-10 02:12:20 +0000599 " }\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000600 " $on_changed$\n"
temporal40ee5512008-07-10 02:12:20 +0000601 "}\n");
602}
603
604void RepeatedPrimitiveFieldGenerator::
605GenerateBuildingCode(io::Printer* printer) const {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000606 // The code below ensures that the result has an immutable list. If our
607 // list is immutable, we can just reuse it. If not, we make it immutable.
temporal40ee5512008-07-10 02:12:20 +0000608 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000609 "if ($get_mutable_bit_builder$) {\n"
610 " $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
611 " $clear_mutable_bit_builder$;\n"
612 "}\n"
613 "result.$name$_ = $name$_;\n");
temporal40ee5512008-07-10 02:12:20 +0000614}
615
616void RepeatedPrimitiveFieldGenerator::
617GenerateParsingCode(io::Printer* printer) const {
kenton@google.comfccb1462009-12-18 02:11:36 +0000618 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000619 "ensure$capitalized_name$IsMutable();\n"
620 "$name$_.add(input.read$capitalized_type$());\n");
kenton@google.comfccb1462009-12-18 02:11:36 +0000621}
622
623void RepeatedPrimitiveFieldGenerator::
624GenerateParsingCodeFromPacked(io::Printer* printer) const {
625 printer->Print(variables_,
626 "int length = input.readRawVarint32();\n"
627 "int limit = input.pushLimit(length);\n"
628 "while (input.getBytesUntilLimit() > 0) {\n"
629 " add$capitalized_name$(input.read$capitalized_type$());\n"
630 "}\n"
631 "input.popLimit(limit);\n");
temporal40ee5512008-07-10 02:12:20 +0000632}
633
634void RepeatedPrimitiveFieldGenerator::
635GenerateSerializationCode(io::Printer* printer) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +0000636 if (descriptor_->options().packed()) {
637 printer->Print(variables_,
638 "if (get$capitalized_name$List().size() > 0) {\n"
639 " output.writeRawVarint32($tag$);\n"
640 " output.writeRawVarint32($name$MemoizedSerializedSize);\n"
641 "}\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000642 "for (int i = 0; i < $name$_.size(); i++) {\n"
643 " output.write$capitalized_type$NoTag($name$_.get(i));\n"
kenton@google.com2d6daa72009-01-22 01:27:00 +0000644 "}\n");
645 } else {
646 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000647 "for (int i = 0; i < $name$_.size(); i++) {\n"
648 " output.write$capitalized_type$($number$, $name$_.get(i));\n"
kenton@google.com2d6daa72009-01-22 01:27:00 +0000649 "}\n");
650 }
temporal40ee5512008-07-10 02:12:20 +0000651}
652
653void RepeatedPrimitiveFieldGenerator::
654GenerateSerializedSizeCode(io::Printer* printer) const {
655 printer->Print(variables_,
kenton@google.com2d6daa72009-01-22 01:27:00 +0000656 "{\n"
657 " int dataSize = 0;\n");
658 printer->Indent();
659
kenton@google.comfccb1462009-12-18 02:11:36 +0000660 if (FixedSize(GetType(descriptor_)) == -1) {
kenton@google.com2d6daa72009-01-22 01:27:00 +0000661 printer->Print(variables_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000662 "for (int i = 0; i < $name$_.size(); i++) {\n"
kenton@google.com2d6daa72009-01-22 01:27:00 +0000663 " dataSize += com.google.protobuf.CodedOutputStream\n"
liujisi@google.com33165fe2010-11-02 13:14:58 +0000664 " .compute$capitalized_type$SizeNoTag($name$_.get(i));\n"
kenton@google.com2d6daa72009-01-22 01:27:00 +0000665 "}\n");
666 } else {
667 printer->Print(variables_,
668 "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n");
669 }
670
671 printer->Print(
672 "size += dataSize;\n");
673
674 if (descriptor_->options().packed()) {
675 printer->Print(variables_,
676 "if (!get$capitalized_name$List().isEmpty()) {\n"
677 " size += $tag_size$;\n"
678 " size += com.google.protobuf.CodedOutputStream\n"
679 " .computeInt32SizeNoTag(dataSize);\n"
680 "}\n");
681 } else {
682 printer->Print(variables_,
683 "size += $tag_size$ * get$capitalized_name$List().size();\n");
684 }
685
686 // cache the data size for packed fields.
687 if (descriptor_->options().packed()) {
688 printer->Print(variables_,
689 "$name$MemoizedSerializedSize = dataSize;\n");
690 }
691
692 printer->Outdent();
693 printer->Print("}\n");
temporal40ee5512008-07-10 02:12:20 +0000694}
695
liujisi@google.com33165fe2010-11-02 13:14:58 +0000696void RepeatedPrimitiveFieldGenerator::
697GenerateEqualsCode(io::Printer* printer) const {
698 printer->Print(variables_,
699 "result = result && get$capitalized_name$List()\n"
700 " .equals(other.get$capitalized_name$List());\n");
701}
702
703void RepeatedPrimitiveFieldGenerator::
704GenerateHashCode(io::Printer* printer) const {
705 printer->Print(variables_,
706 "if (get$capitalized_name$Count() > 0) {\n"
707 " hash = (37 * hash) + $constant_name$;\n"
708 " hash = (53 * hash) + get$capitalized_name$List().hashCode();\n"
709 "}\n");
710}
711
temporal40ee5512008-07-10 02:12:20 +0000712string RepeatedPrimitiveFieldGenerator::GetBoxedType() const {
713 return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
714}
715
716} // namespace java
717} // namespace compiler
718} // namespace protobuf
719} // namespace google