OLD | NEW |
| (Empty) |
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 <map> | |
36 #include <string> | |
37 | |
38 #include <google/protobuf/compiler/java/java_primitive_field.h> | |
39 #include <google/protobuf/compiler/java/java_doc_comment.h> | |
40 #include <google/protobuf/stubs/common.h> | |
41 #include <google/protobuf/compiler/java/java_helpers.h> | |
42 #include <google/protobuf/io/printer.h> | |
43 #include <google/protobuf/wire_format.h> | |
44 #include <google/protobuf/stubs/strutil.h> | |
45 | |
46 namespace google { | |
47 namespace protobuf { | |
48 namespace compiler { | |
49 namespace java { | |
50 | |
51 using internal::WireFormat; | |
52 using internal::WireFormatLite; | |
53 | |
54 namespace { | |
55 | |
56 const char* PrimitiveTypeName(JavaType type) { | |
57 switch (type) { | |
58 case JAVATYPE_INT : return "int"; | |
59 case JAVATYPE_LONG : return "long"; | |
60 case JAVATYPE_FLOAT : return "float"; | |
61 case JAVATYPE_DOUBLE : return "double"; | |
62 case JAVATYPE_BOOLEAN: return "boolean"; | |
63 case JAVATYPE_STRING : return "java.lang.String"; | |
64 case JAVATYPE_BYTES : return "com.google.protobuf.ByteString"; | |
65 case JAVATYPE_ENUM : return NULL; | |
66 case JAVATYPE_MESSAGE: return NULL; | |
67 | |
68 // No default because we want the compiler to complain if any new | |
69 // JavaTypes are added. | |
70 } | |
71 | |
72 GOOGLE_LOG(FATAL) << "Can't get here."; | |
73 return NULL; | |
74 } | |
75 | |
76 bool IsReferenceType(JavaType type) { | |
77 switch (type) { | |
78 case JAVATYPE_INT : return false; | |
79 case JAVATYPE_LONG : return false; | |
80 case JAVATYPE_FLOAT : return false; | |
81 case JAVATYPE_DOUBLE : return false; | |
82 case JAVATYPE_BOOLEAN: return false; | |
83 case JAVATYPE_STRING : return true; | |
84 case JAVATYPE_BYTES : return true; | |
85 case JAVATYPE_ENUM : return true; | |
86 case JAVATYPE_MESSAGE: return true; | |
87 | |
88 // No default because we want the compiler to complain if any new | |
89 // JavaTypes are added. | |
90 } | |
91 | |
92 GOOGLE_LOG(FATAL) << "Can't get here."; | |
93 return false; | |
94 } | |
95 | |
96 const char* GetCapitalizedType(const FieldDescriptor* field) { | |
97 switch (GetType(field)) { | |
98 case FieldDescriptor::TYPE_INT32 : return "Int32" ; | |
99 case FieldDescriptor::TYPE_UINT32 : return "UInt32" ; | |
100 case FieldDescriptor::TYPE_SINT32 : return "SInt32" ; | |
101 case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ; | |
102 case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; | |
103 case FieldDescriptor::TYPE_INT64 : return "Int64" ; | |
104 case FieldDescriptor::TYPE_UINT64 : return "UInt64" ; | |
105 case FieldDescriptor::TYPE_SINT64 : return "SInt64" ; | |
106 case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ; | |
107 case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; | |
108 case FieldDescriptor::TYPE_FLOAT : return "Float" ; | |
109 case FieldDescriptor::TYPE_DOUBLE : return "Double" ; | |
110 case FieldDescriptor::TYPE_BOOL : return "Bool" ; | |
111 case FieldDescriptor::TYPE_STRING : return "String" ; | |
112 case FieldDescriptor::TYPE_BYTES : return "Bytes" ; | |
113 case FieldDescriptor::TYPE_ENUM : return "Enum" ; | |
114 case FieldDescriptor::TYPE_GROUP : return "Group" ; | |
115 case FieldDescriptor::TYPE_MESSAGE : return "Message" ; | |
116 | |
117 // No default because we want the compiler to complain if any new | |
118 // types are added. | |
119 } | |
120 | |
121 GOOGLE_LOG(FATAL) << "Can't get here."; | |
122 return NULL; | |
123 } | |
124 | |
125 // For encodings with fixed sizes, returns that size in bytes. Otherwise | |
126 // returns -1. | |
127 int FixedSize(FieldDescriptor::Type type) { | |
128 switch (type) { | |
129 case FieldDescriptor::TYPE_INT32 : return -1; | |
130 case FieldDescriptor::TYPE_INT64 : return -1; | |
131 case FieldDescriptor::TYPE_UINT32 : return -1; | |
132 case FieldDescriptor::TYPE_UINT64 : return -1; | |
133 case FieldDescriptor::TYPE_SINT32 : return -1; | |
134 case FieldDescriptor::TYPE_SINT64 : return -1; | |
135 case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; | |
136 case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; | |
137 case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; | |
138 case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; | |
139 case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; | |
140 case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; | |
141 | |
142 case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; | |
143 case FieldDescriptor::TYPE_ENUM : return -1; | |
144 | |
145 case FieldDescriptor::TYPE_STRING : return -1; | |
146 case FieldDescriptor::TYPE_BYTES : return -1; | |
147 case FieldDescriptor::TYPE_GROUP : return -1; | |
148 case FieldDescriptor::TYPE_MESSAGE : return -1; | |
149 | |
150 // No default because we want the compiler to complain if any new | |
151 // types are added. | |
152 } | |
153 GOOGLE_LOG(FATAL) << "Can't get here."; | |
154 return -1; | |
155 } | |
156 | |
157 void SetPrimitiveVariables(const FieldDescriptor* descriptor, | |
158 int messageBitIndex, | |
159 int builderBitIndex, | |
160 map<string, string>* variables) { | |
161 (*variables)["name"] = | |
162 UnderscoresToCamelCase(descriptor); | |
163 (*variables)["capitalized_name"] = | |
164 UnderscoresToCapitalizedCamelCase(descriptor); | |
165 (*variables)["constant_name"] = FieldConstantName(descriptor); | |
166 (*variables)["number"] = SimpleItoa(descriptor->number()); | |
167 (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor)); | |
168 (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor)); | |
169 (*variables)["field_type"] = (*variables)["type"]; | |
170 (*variables)["field_list_type"] = "java.util.List<" + | |
171 (*variables)["boxed_type"] + ">"; | |
172 (*variables)["empty_list"] = "java.util.Collections.emptyList()"; | |
173 (*variables)["default"] = DefaultValue(descriptor); | |
174 (*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ? | |
175 "" : ("= " + DefaultValue(descriptor)); | |
176 (*variables)["capitalized_type"] = GetCapitalizedType(descriptor); | |
177 (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); | |
178 (*variables)["tag_size"] = SimpleItoa( | |
179 WireFormat::TagSize(descriptor->number(), GetType(descriptor))); | |
180 if (IsReferenceType(GetJavaType(descriptor))) { | |
181 (*variables)["null_check"] = | |
182 " if (value == null) {\n" | |
183 " throw new NullPointerException();\n" | |
184 " }\n"; | |
185 } else { | |
186 (*variables)["null_check"] = ""; | |
187 } | |
188 // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported | |
189 // by the proto compiler | |
190 (*variables)["deprecation"] = descriptor->options().deprecated() | |
191 ? "@java.lang.Deprecated " : ""; | |
192 int fixed_size = FixedSize(GetType(descriptor)); | |
193 if (fixed_size != -1) { | |
194 (*variables)["fixed_size"] = SimpleItoa(fixed_size); | |
195 } | |
196 (*variables)["on_changed"] = | |
197 HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; | |
198 | |
199 // For singular messages and builders, one bit is used for the hasField bit. | |
200 (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); | |
201 (*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex); | |
202 | |
203 (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); | |
204 (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); | |
205 (*variables)["clear_has_field_bit_builder"] = | |
206 GenerateClearBit(builderBitIndex); | |
207 | |
208 // For repated builders, one bit is used for whether the array is immutable. | |
209 (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); | |
210 (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); | |
211 (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); | |
212 | |
213 // For repeated fields, one bit is used for whether the array is immutable | |
214 // in the parsing constructor. | |
215 (*variables)["get_mutable_bit_parser"] = | |
216 GenerateGetBitMutableLocal(builderBitIndex); | |
217 (*variables)["set_mutable_bit_parser"] = | |
218 GenerateSetBitMutableLocal(builderBitIndex); | |
219 | |
220 (*variables)["get_has_field_bit_from_local"] = | |
221 GenerateGetBitFromLocal(builderBitIndex); | |
222 (*variables)["set_has_field_bit_to_local"] = | |
223 GenerateSetBitToLocal(messageBitIndex); | |
224 } | |
225 | |
226 } // namespace | |
227 | |
228 // =================================================================== | |
229 | |
230 PrimitiveFieldGenerator:: | |
231 PrimitiveFieldGenerator(const FieldDescriptor* descriptor, | |
232 int messageBitIndex, | |
233 int builderBitIndex) | |
234 : descriptor_(descriptor), messageBitIndex_(messageBitIndex), | |
235 builderBitIndex_(builderBitIndex) { | |
236 SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, | |
237 &variables_); | |
238 } | |
239 | |
240 PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} | |
241 | |
242 int PrimitiveFieldGenerator::GetNumBitsForMessage() const { | |
243 return 1; | |
244 } | |
245 | |
246 int PrimitiveFieldGenerator::GetNumBitsForBuilder() const { | |
247 return 1; | |
248 } | |
249 | |
250 void PrimitiveFieldGenerator:: | |
251 GenerateInterfaceMembers(io::Printer* printer) const { | |
252 WriteFieldDocComment(printer, descriptor_); | |
253 printer->Print(variables_, | |
254 "$deprecation$boolean has$capitalized_name$();\n"); | |
255 WriteFieldDocComment(printer, descriptor_); | |
256 printer->Print(variables_, | |
257 "$deprecation$$type$ get$capitalized_name$();\n"); | |
258 } | |
259 | |
260 void PrimitiveFieldGenerator:: | |
261 GenerateMembers(io::Printer* printer) const { | |
262 printer->Print(variables_, | |
263 "private $field_type$ $name$_;\n"); | |
264 | |
265 WriteFieldDocComment(printer, descriptor_); | |
266 printer->Print(variables_, | |
267 "$deprecation$public boolean has$capitalized_name$() {\n" | |
268 " return $get_has_field_bit_message$;\n" | |
269 "}\n"); | |
270 | |
271 WriteFieldDocComment(printer, descriptor_); | |
272 printer->Print(variables_, | |
273 "$deprecation$public $type$ get$capitalized_name$() {\n" | |
274 " return $name$_;\n" | |
275 "}\n"); | |
276 } | |
277 | |
278 void PrimitiveFieldGenerator:: | |
279 GenerateBuilderMembers(io::Printer* printer) const { | |
280 printer->Print(variables_, | |
281 "private $field_type$ $name$_ $default_init$;\n"); | |
282 | |
283 WriteFieldDocComment(printer, descriptor_); | |
284 printer->Print(variables_, | |
285 "$deprecation$public boolean has$capitalized_name$() {\n" | |
286 " return $get_has_field_bit_builder$;\n" | |
287 "}\n"); | |
288 | |
289 WriteFieldDocComment(printer, descriptor_); | |
290 printer->Print(variables_, | |
291 "$deprecation$public $type$ get$capitalized_name$() {\n" | |
292 " return $name$_;\n" | |
293 "}\n"); | |
294 | |
295 WriteFieldDocComment(printer, descriptor_); | |
296 printer->Print(variables_, | |
297 "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" | |
298 "$null_check$" | |
299 " $set_has_field_bit_builder$;\n" | |
300 " $name$_ = value;\n" | |
301 " $on_changed$\n" | |
302 " return this;\n" | |
303 "}\n"); | |
304 | |
305 WriteFieldDocComment(printer, descriptor_); | |
306 printer->Print(variables_, | |
307 "$deprecation$public Builder clear$capitalized_name$() {\n" | |
308 " $clear_has_field_bit_builder$;\n"); | |
309 JavaType type = GetJavaType(descriptor_); | |
310 if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) { | |
311 // The default value is not a simple literal so we want to avoid executing | |
312 // it multiple times. Instead, get the default out of the default instance. | |
313 printer->Print(variables_, | |
314 " $name$_ = getDefaultInstance().get$capitalized_name$();\n"); | |
315 } else { | |
316 printer->Print(variables_, | |
317 " $name$_ = $default$;\n"); | |
318 } | |
319 printer->Print(variables_, | |
320 " $on_changed$\n" | |
321 " return this;\n" | |
322 "}\n"); | |
323 } | |
324 | |
325 void PrimitiveFieldGenerator:: | |
326 GenerateFieldBuilderInitializationCode(io::Printer* printer) const { | |
327 // noop for primitives | |
328 } | |
329 | |
330 void PrimitiveFieldGenerator:: | |
331 GenerateInitializationCode(io::Printer* printer) const { | |
332 printer->Print(variables_, "$name$_ = $default$;\n"); | |
333 } | |
334 | |
335 void PrimitiveFieldGenerator:: | |
336 GenerateBuilderClearCode(io::Printer* printer) const { | |
337 printer->Print(variables_, | |
338 "$name$_ = $default$;\n" | |
339 "$clear_has_field_bit_builder$;\n"); | |
340 } | |
341 | |
342 void PrimitiveFieldGenerator:: | |
343 GenerateMergingCode(io::Printer* printer) const { | |
344 printer->Print(variables_, | |
345 "if (other.has$capitalized_name$()) {\n" | |
346 " set$capitalized_name$(other.get$capitalized_name$());\n" | |
347 "}\n"); | |
348 } | |
349 | |
350 void PrimitiveFieldGenerator:: | |
351 GenerateBuildingCode(io::Printer* printer) const { | |
352 printer->Print(variables_, | |
353 "if ($get_has_field_bit_from_local$) {\n" | |
354 " $set_has_field_bit_to_local$;\n" | |
355 "}\n" | |
356 "result.$name$_ = $name$_;\n"); | |
357 } | |
358 | |
359 void PrimitiveFieldGenerator:: | |
360 GenerateParsingCode(io::Printer* printer) const { | |
361 printer->Print(variables_, | |
362 "$set_has_field_bit_message$;\n" | |
363 "$name$_ = input.read$capitalized_type$();\n"); | |
364 } | |
365 | |
366 void PrimitiveFieldGenerator:: | |
367 GenerateParsingDoneCode(io::Printer* printer) const { | |
368 // noop for primitives. | |
369 } | |
370 | |
371 void PrimitiveFieldGenerator:: | |
372 GenerateSerializationCode(io::Printer* printer) const { | |
373 printer->Print(variables_, | |
374 "if ($get_has_field_bit_message$) {\n" | |
375 " output.write$capitalized_type$($number$, $name$_);\n" | |
376 "}\n"); | |
377 } | |
378 | |
379 void PrimitiveFieldGenerator:: | |
380 GenerateSerializedSizeCode(io::Printer* printer) const { | |
381 printer->Print(variables_, | |
382 "if ($get_has_field_bit_message$) {\n" | |
383 " size += com.google.protobuf.CodedOutputStream\n" | |
384 " .compute$capitalized_type$Size($number$, $name$_);\n" | |
385 "}\n"); | |
386 } | |
387 | |
388 void PrimitiveFieldGenerator:: | |
389 GenerateEqualsCode(io::Printer* printer) const { | |
390 switch (GetJavaType(descriptor_)) { | |
391 case JAVATYPE_INT: | |
392 case JAVATYPE_LONG: | |
393 case JAVATYPE_BOOLEAN: | |
394 printer->Print(variables_, | |
395 "result = result && (get$capitalized_name$()\n" | |
396 " == other.get$capitalized_name$());\n"); | |
397 break; | |
398 | |
399 case JAVATYPE_FLOAT: | |
400 printer->Print(variables_, | |
401 "result = result && (Float.floatToIntBits(get$capitalized_name$())" | |
402 " == Float.floatToIntBits(other.get$capitalized_name$()));\n"); | |
403 break; | |
404 | |
405 case JAVATYPE_DOUBLE: | |
406 printer->Print(variables_, | |
407 "result = result && (Double.doubleToLongBits(get$capitalized_name$())" | |
408 " == Double.doubleToLongBits(other.get$capitalized_name$()));\n"); | |
409 break; | |
410 | |
411 case JAVATYPE_STRING: | |
412 case JAVATYPE_BYTES: | |
413 printer->Print(variables_, | |
414 "result = result && get$capitalized_name$()\n" | |
415 " .equals(other.get$capitalized_name$());\n"); | |
416 break; | |
417 | |
418 case JAVATYPE_ENUM: | |
419 case JAVATYPE_MESSAGE: | |
420 default: | |
421 GOOGLE_LOG(FATAL) << "Can't get here."; | |
422 break; | |
423 } | |
424 } | |
425 | |
426 void PrimitiveFieldGenerator:: | |
427 GenerateHashCode(io::Printer* printer) const { | |
428 printer->Print(variables_, | |
429 "hash = (37 * hash) + $constant_name$;\n"); | |
430 switch (GetJavaType(descriptor_)) { | |
431 case JAVATYPE_INT: | |
432 printer->Print(variables_, | |
433 "hash = (53 * hash) + get$capitalized_name$();\n"); | |
434 break; | |
435 | |
436 case JAVATYPE_LONG: | |
437 printer->Print(variables_, | |
438 "hash = (53 * hash) + hashLong(get$capitalized_name$());\n"); | |
439 break; | |
440 | |
441 case JAVATYPE_BOOLEAN: | |
442 printer->Print(variables_, | |
443 "hash = (53 * hash) + hashBoolean(get$capitalized_name$());\n"); | |
444 break; | |
445 | |
446 case JAVATYPE_FLOAT: | |
447 printer->Print(variables_, | |
448 "hash = (53 * hash) + Float.floatToIntBits(\n" | |
449 " get$capitalized_name$());\n"); | |
450 break; | |
451 | |
452 case JAVATYPE_DOUBLE: | |
453 printer->Print(variables_, | |
454 "hash = (53 * hash) + hashLong(\n" | |
455 " Double.doubleToLongBits(get$capitalized_name$()));\n"); | |
456 break; | |
457 | |
458 case JAVATYPE_STRING: | |
459 case JAVATYPE_BYTES: | |
460 printer->Print(variables_, | |
461 "hash = (53 * hash) + get$capitalized_name$().hashCode();\n"); | |
462 break; | |
463 | |
464 case JAVATYPE_ENUM: | |
465 case JAVATYPE_MESSAGE: | |
466 default: | |
467 GOOGLE_LOG(FATAL) << "Can't get here."; | |
468 break; | |
469 } | |
470 } | |
471 | |
472 string PrimitiveFieldGenerator::GetBoxedType() const { | |
473 return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); | |
474 } | |
475 | |
476 // =================================================================== | |
477 | |
478 RepeatedPrimitiveFieldGenerator:: | |
479 RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, | |
480 int messageBitIndex, | |
481 int builderBitIndex) | |
482 : descriptor_(descriptor), messageBitIndex_(messageBitIndex), | |
483 builderBitIndex_(builderBitIndex) { | |
484 SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, | |
485 &variables_); | |
486 } | |
487 | |
488 RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} | |
489 | |
490 int RepeatedPrimitiveFieldGenerator::GetNumBitsForMessage() const { | |
491 return 0; | |
492 } | |
493 | |
494 int RepeatedPrimitiveFieldGenerator::GetNumBitsForBuilder() const { | |
495 return 1; | |
496 } | |
497 | |
498 void RepeatedPrimitiveFieldGenerator:: | |
499 GenerateInterfaceMembers(io::Printer* printer) const { | |
500 WriteFieldDocComment(printer, descriptor_); | |
501 printer->Print(variables_, | |
502 "$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n"); | |
503 WriteFieldDocComment(printer, descriptor_); | |
504 printer->Print(variables_, | |
505 "$deprecation$int get$capitalized_name$Count();\n"); | |
506 WriteFieldDocComment(printer, descriptor_); | |
507 printer->Print(variables_, | |
508 "$deprecation$$type$ get$capitalized_name$(int index);\n"); | |
509 } | |
510 | |
511 | |
512 void RepeatedPrimitiveFieldGenerator:: | |
513 GenerateMembers(io::Printer* printer) const { | |
514 printer->Print(variables_, | |
515 "private $field_list_type$ $name$_;\n"); | |
516 WriteFieldDocComment(printer, descriptor_); | |
517 printer->Print(variables_, | |
518 "$deprecation$public java.util.List<$boxed_type$>\n" | |
519 " get$capitalized_name$List() {\n" | |
520 " return $name$_;\n" // note: unmodifiable list | |
521 "}\n"); | |
522 WriteFieldDocComment(printer, descriptor_); | |
523 printer->Print(variables_, | |
524 "$deprecation$public int get$capitalized_name$Count() {\n" | |
525 " return $name$_.size();\n" | |
526 "}\n"); | |
527 WriteFieldDocComment(printer, descriptor_); | |
528 printer->Print(variables_, | |
529 "$deprecation$public $type$ get$capitalized_name$(int index) {\n" | |
530 " return $name$_.get(index);\n" | |
531 "}\n"); | |
532 | |
533 if (descriptor_->options().packed() && | |
534 HasGeneratedMethods(descriptor_->containing_type())) { | |
535 printer->Print(variables_, | |
536 "private int $name$MemoizedSerializedSize = -1;\n"); | |
537 } | |
538 } | |
539 | |
540 void RepeatedPrimitiveFieldGenerator:: | |
541 GenerateBuilderMembers(io::Printer* printer) const { | |
542 // One field is the list and the bit field keeps track of whether the | |
543 // list is immutable. If it's immutable, the invariant is that it must | |
544 // either an instance of Collections.emptyList() or it's an ArrayList | |
545 // wrapped in a Collections.unmodifiableList() wrapper and nobody else has | |
546 // a refererence to the underlying ArrayList. This invariant allows us to | |
547 // share instances of lists between protocol buffers avoiding expensive | |
548 // memory allocations. Note, immutable is a strong guarantee here -- not | |
549 // just that the list cannot be modified via the reference but that the | |
550 // list can never be modified. | |
551 printer->Print(variables_, | |
552 "private $field_list_type$ $name$_ = $empty_list$;\n"); | |
553 | |
554 printer->Print(variables_, | |
555 "private void ensure$capitalized_name$IsMutable() {\n" | |
556 " if (!$get_mutable_bit_builder$) {\n" | |
557 " $name$_ = new java.util.ArrayList<$boxed_type$>($name$_);\n" | |
558 " $set_mutable_bit_builder$;\n" | |
559 " }\n" | |
560 "}\n"); | |
561 | |
562 // Note: We return an unmodifiable list because otherwise the caller | |
563 // could hold on to the returned list and modify it after the message | |
564 // has been built, thus mutating the message which is supposed to be | |
565 // immutable. | |
566 WriteFieldDocComment(printer, descriptor_); | |
567 printer->Print(variables_, | |
568 "$deprecation$public java.util.List<$boxed_type$>\n" | |
569 " get$capitalized_name$List() {\n" | |
570 " return java.util.Collections.unmodifiableList($name$_);\n" | |
571 "}\n"); | |
572 WriteFieldDocComment(printer, descriptor_); | |
573 printer->Print(variables_, | |
574 "$deprecation$public int get$capitalized_name$Count() {\n" | |
575 " return $name$_.size();\n" | |
576 "}\n"); | |
577 WriteFieldDocComment(printer, descriptor_); | |
578 printer->Print(variables_, | |
579 "$deprecation$public $type$ get$capitalized_name$(int index) {\n" | |
580 " return $name$_.get(index);\n" | |
581 "}\n"); | |
582 WriteFieldDocComment(printer, descriptor_); | |
583 printer->Print(variables_, | |
584 "$deprecation$public Builder set$capitalized_name$(\n" | |
585 " int index, $type$ value) {\n" | |
586 "$null_check$" | |
587 " ensure$capitalized_name$IsMutable();\n" | |
588 " $name$_.set(index, value);\n" | |
589 " $on_changed$\n" | |
590 " return this;\n" | |
591 "}\n"); | |
592 WriteFieldDocComment(printer, descriptor_); | |
593 printer->Print(variables_, | |
594 "$deprecation$public Builder add$capitalized_name$($type$ value) {\n" | |
595 "$null_check$" | |
596 " ensure$capitalized_name$IsMutable();\n" | |
597 " $name$_.add(value);\n" | |
598 " $on_changed$\n" | |
599 " return this;\n" | |
600 "}\n"); | |
601 WriteFieldDocComment(printer, descriptor_); | |
602 printer->Print(variables_, | |
603 "$deprecation$public Builder addAll$capitalized_name$(\n" | |
604 " java.lang.Iterable<? extends $boxed_type$> values) {\n" | |
605 " ensure$capitalized_name$IsMutable();\n" | |
606 " super.addAll(values, $name$_);\n" | |
607 " $on_changed$\n" | |
608 " return this;\n" | |
609 "}\n"); | |
610 WriteFieldDocComment(printer, descriptor_); | |
611 printer->Print(variables_, | |
612 "$deprecation$public Builder clear$capitalized_name$() {\n" | |
613 " $name$_ = $empty_list$;\n" | |
614 " $clear_mutable_bit_builder$;\n" | |
615 " $on_changed$\n" | |
616 " return this;\n" | |
617 "}\n"); | |
618 } | |
619 | |
620 void RepeatedPrimitiveFieldGenerator:: | |
621 GenerateFieldBuilderInitializationCode(io::Printer* printer) const { | |
622 // noop for primitives | |
623 } | |
624 | |
625 void RepeatedPrimitiveFieldGenerator:: | |
626 GenerateInitializationCode(io::Printer* printer) const { | |
627 printer->Print(variables_, "$name$_ = $empty_list$;\n"); | |
628 } | |
629 | |
630 void RepeatedPrimitiveFieldGenerator:: | |
631 GenerateBuilderClearCode(io::Printer* printer) const { | |
632 printer->Print(variables_, | |
633 "$name$_ = $empty_list$;\n" | |
634 "$clear_mutable_bit_builder$;\n"); | |
635 } | |
636 | |
637 void RepeatedPrimitiveFieldGenerator:: | |
638 GenerateMergingCode(io::Printer* printer) const { | |
639 // The code below does two optimizations: | |
640 // 1. If the other list is empty, there's nothing to do. This ensures we | |
641 // don't allocate a new array if we already have an immutable one. | |
642 // 2. If the other list is non-empty and our current list is empty, we can | |
643 // reuse the other list which is guaranteed to be immutable. | |
644 printer->Print(variables_, | |
645 "if (!other.$name$_.isEmpty()) {\n" | |
646 " if ($name$_.isEmpty()) {\n" | |
647 " $name$_ = other.$name$_;\n" | |
648 " $clear_mutable_bit_builder$;\n" | |
649 " } else {\n" | |
650 " ensure$capitalized_name$IsMutable();\n" | |
651 " $name$_.addAll(other.$name$_);\n" | |
652 " }\n" | |
653 " $on_changed$\n" | |
654 "}\n"); | |
655 } | |
656 | |
657 void RepeatedPrimitiveFieldGenerator:: | |
658 GenerateBuildingCode(io::Printer* printer) const { | |
659 // The code below ensures that the result has an immutable list. If our | |
660 // list is immutable, we can just reuse it. If not, we make it immutable. | |
661 printer->Print(variables_, | |
662 "if ($get_mutable_bit_builder$) {\n" | |
663 " $name$_ = java.util.Collections.unmodifiableList($name$_);\n" | |
664 " $clear_mutable_bit_builder$;\n" | |
665 "}\n" | |
666 "result.$name$_ = $name$_;\n"); | |
667 } | |
668 | |
669 void RepeatedPrimitiveFieldGenerator:: | |
670 GenerateParsingCode(io::Printer* printer) const { | |
671 printer->Print(variables_, | |
672 "if (!$get_mutable_bit_parser$) {\n" | |
673 " $name$_ = new java.util.ArrayList<$boxed_type$>();\n" | |
674 " $set_mutable_bit_parser$;\n" | |
675 "}\n" | |
676 "$name$_.add(input.read$capitalized_type$());\n"); | |
677 } | |
678 | |
679 void RepeatedPrimitiveFieldGenerator:: | |
680 GenerateParsingCodeFromPacked(io::Printer* printer) const { | |
681 printer->Print(variables_, | |
682 "int length = input.readRawVarint32();\n" | |
683 "int limit = input.pushLimit(length);\n" | |
684 "if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n" | |
685 " $name$_ = new java.util.ArrayList<$boxed_type$>();\n" | |
686 " $set_mutable_bit_parser$;\n" | |
687 "}\n" | |
688 "while (input.getBytesUntilLimit() > 0) {\n" | |
689 " $name$_.add(input.read$capitalized_type$());\n" | |
690 "}\n" | |
691 "input.popLimit(limit);\n"); | |
692 } | |
693 | |
694 void RepeatedPrimitiveFieldGenerator:: | |
695 GenerateParsingDoneCode(io::Printer* printer) const { | |
696 printer->Print(variables_, | |
697 "if ($get_mutable_bit_parser$) {\n" | |
698 " $name$_ = java.util.Collections.unmodifiableList($name$_);\n" | |
699 "}\n"); | |
700 } | |
701 | |
702 void RepeatedPrimitiveFieldGenerator:: | |
703 GenerateSerializationCode(io::Printer* printer) const { | |
704 if (descriptor_->options().packed()) { | |
705 printer->Print(variables_, | |
706 "if (get$capitalized_name$List().size() > 0) {\n" | |
707 " output.writeRawVarint32($tag$);\n" | |
708 " output.writeRawVarint32($name$MemoizedSerializedSize);\n" | |
709 "}\n" | |
710 "for (int i = 0; i < $name$_.size(); i++) {\n" | |
711 " output.write$capitalized_type$NoTag($name$_.get(i));\n" | |
712 "}\n"); | |
713 } else { | |
714 printer->Print(variables_, | |
715 "for (int i = 0; i < $name$_.size(); i++) {\n" | |
716 " output.write$capitalized_type$($number$, $name$_.get(i));\n" | |
717 "}\n"); | |
718 } | |
719 } | |
720 | |
721 void RepeatedPrimitiveFieldGenerator:: | |
722 GenerateSerializedSizeCode(io::Printer* printer) const { | |
723 printer->Print(variables_, | |
724 "{\n" | |
725 " int dataSize = 0;\n"); | |
726 printer->Indent(); | |
727 | |
728 if (FixedSize(GetType(descriptor_)) == -1) { | |
729 printer->Print(variables_, | |
730 "for (int i = 0; i < $name$_.size(); i++) {\n" | |
731 " dataSize += com.google.protobuf.CodedOutputStream\n" | |
732 " .compute$capitalized_type$SizeNoTag($name$_.get(i));\n" | |
733 "}\n"); | |
734 } else { | |
735 printer->Print(variables_, | |
736 "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n"); | |
737 } | |
738 | |
739 printer->Print( | |
740 "size += dataSize;\n"); | |
741 | |
742 if (descriptor_->options().packed()) { | |
743 printer->Print(variables_, | |
744 "if (!get$capitalized_name$List().isEmpty()) {\n" | |
745 " size += $tag_size$;\n" | |
746 " size += com.google.protobuf.CodedOutputStream\n" | |
747 " .computeInt32SizeNoTag(dataSize);\n" | |
748 "}\n"); | |
749 } else { | |
750 printer->Print(variables_, | |
751 "size += $tag_size$ * get$capitalized_name$List().size();\n"); | |
752 } | |
753 | |
754 // cache the data size for packed fields. | |
755 if (descriptor_->options().packed()) { | |
756 printer->Print(variables_, | |
757 "$name$MemoizedSerializedSize = dataSize;\n"); | |
758 } | |
759 | |
760 printer->Outdent(); | |
761 printer->Print("}\n"); | |
762 } | |
763 | |
764 void RepeatedPrimitiveFieldGenerator:: | |
765 GenerateEqualsCode(io::Printer* printer) const { | |
766 printer->Print(variables_, | |
767 "result = result && get$capitalized_name$List()\n" | |
768 " .equals(other.get$capitalized_name$List());\n"); | |
769 } | |
770 | |
771 void RepeatedPrimitiveFieldGenerator:: | |
772 GenerateHashCode(io::Printer* printer) const { | |
773 printer->Print(variables_, | |
774 "if (get$capitalized_name$Count() > 0) {\n" | |
775 " hash = (37 * hash) + $constant_name$;\n" | |
776 " hash = (53 * hash) + get$capitalized_name$List().hashCode();\n" | |
777 "}\n"); | |
778 } | |
779 | |
780 string RepeatedPrimitiveFieldGenerator::GetBoxedType() const { | |
781 return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); | |
782 } | |
783 | |
784 } // namespace java | |
785 } // namespace compiler | |
786 } // namespace protobuf | |
787 } // namespace google | |
OLD | NEW |