javanano_primitive_field.cc revision ccc48faf20dbf3b3cddcffe78d198876d543529b
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 <math.h>
37#include <string>
38
39#include <google/protobuf/compiler/javanano/javanano_primitive_field.h>
40#include <google/protobuf/stubs/common.h>
41#include <google/protobuf/compiler/javanano/javanano_helpers.h>
42#include <google/protobuf/io/printer.h>
43#include <google/protobuf/wire_format.h>
44#include <google/protobuf/stubs/strutil.h>
45#include <google/protobuf/stubs/substitute.h>
46
47namespace google {
48namespace protobuf {
49namespace compiler {
50namespace javanano {
51
52using internal::WireFormat;
53using internal::WireFormatLite;
54
55namespace {
56
57const char* PrimitiveTypeName(JavaType type) {
58  switch (type) {
59    case JAVATYPE_INT    : return "int";
60    case JAVATYPE_LONG   : return "long";
61    case JAVATYPE_FLOAT  : return "float";
62    case JAVATYPE_DOUBLE : return "double";
63    case JAVATYPE_BOOLEAN: return "boolean";
64    case JAVATYPE_STRING : return "java.lang.String";
65    case JAVATYPE_BYTES  : return "byte[]";
66    case JAVATYPE_ENUM   : return NULL;
67    case JAVATYPE_MESSAGE: return NULL;
68
69    // No default because we want the compiler to complain if any new
70    // JavaTypes are added.
71  }
72
73  GOOGLE_LOG(FATAL) << "Can't get here.";
74  return NULL;
75}
76
77bool IsReferenceType(JavaType type) {
78  switch (type) {
79    case JAVATYPE_INT    : return false;
80    case JAVATYPE_LONG   : return false;
81    case JAVATYPE_FLOAT  : return false;
82    case JAVATYPE_DOUBLE : return false;
83    case JAVATYPE_BOOLEAN: return false;
84    case JAVATYPE_STRING : return true;
85    case JAVATYPE_BYTES  : return true;
86    case JAVATYPE_ENUM   : return false;
87    case JAVATYPE_MESSAGE: return true;
88
89    // No default because we want the compiler to complain if any new
90    // JavaTypes are added.
91  }
92
93  GOOGLE_LOG(FATAL) << "Can't get here.";
94  return false;
95}
96
97bool IsArrayType(JavaType type) {
98  switch (type) {
99    case JAVATYPE_INT    : return false;
100    case JAVATYPE_LONG   : return false;
101    case JAVATYPE_FLOAT  : return false;
102    case JAVATYPE_DOUBLE : return false;
103    case JAVATYPE_BOOLEAN: return false;
104    case JAVATYPE_STRING : return false;
105    case JAVATYPE_BYTES  : return true;
106    case JAVATYPE_ENUM   : return false;
107    case JAVATYPE_MESSAGE: return false;
108
109    // No default because we want the compiler to complain if any new
110    // JavaTypes are added.
111  }
112
113  GOOGLE_LOG(FATAL) << "Can't get here.";
114  return false;
115}
116
117const char* GetCapitalizedType(const FieldDescriptor* field) {
118  switch (field->type()) {
119    case FieldDescriptor::TYPE_INT32   : return "Int32"   ;
120    case FieldDescriptor::TYPE_UINT32  : return "UInt32"  ;
121    case FieldDescriptor::TYPE_SINT32  : return "SInt32"  ;
122    case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ;
123    case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
124    case FieldDescriptor::TYPE_INT64   : return "Int64"   ;
125    case FieldDescriptor::TYPE_UINT64  : return "UInt64"  ;
126    case FieldDescriptor::TYPE_SINT64  : return "SInt64"  ;
127    case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ;
128    case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
129    case FieldDescriptor::TYPE_FLOAT   : return "Float"   ;
130    case FieldDescriptor::TYPE_DOUBLE  : return "Double"  ;
131    case FieldDescriptor::TYPE_BOOL    : return "Bool"    ;
132    case FieldDescriptor::TYPE_STRING  : return "String"  ;
133    case FieldDescriptor::TYPE_BYTES   : return "Bytes"   ;
134    case FieldDescriptor::TYPE_ENUM    : return "Enum"    ;
135    case FieldDescriptor::TYPE_GROUP   : return "Group"   ;
136    case FieldDescriptor::TYPE_MESSAGE : return "Message" ;
137
138    // No default because we want the compiler to complain if any new
139    // types are added.
140  }
141
142  GOOGLE_LOG(FATAL) << "Can't get here.";
143  return NULL;
144}
145
146// For encodings with fixed sizes, returns that size in bytes.  Otherwise
147// returns -1.
148int FixedSize(FieldDescriptor::Type type) {
149  switch (type) {
150    case FieldDescriptor::TYPE_INT32   : return -1;
151    case FieldDescriptor::TYPE_INT64   : return -1;
152    case FieldDescriptor::TYPE_UINT32  : return -1;
153    case FieldDescriptor::TYPE_UINT64  : return -1;
154    case FieldDescriptor::TYPE_SINT32  : return -1;
155    case FieldDescriptor::TYPE_SINT64  : return -1;
156    case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
157    case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
158    case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
159    case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
160    case FieldDescriptor::TYPE_FLOAT   : return WireFormatLite::kFloatSize;
161    case FieldDescriptor::TYPE_DOUBLE  : return WireFormatLite::kDoubleSize;
162
163    case FieldDescriptor::TYPE_BOOL    : return WireFormatLite::kBoolSize;
164    case FieldDescriptor::TYPE_ENUM    : return -1;
165
166    case FieldDescriptor::TYPE_STRING  : return -1;
167    case FieldDescriptor::TYPE_BYTES   : return -1;
168    case FieldDescriptor::TYPE_GROUP   : return -1;
169    case FieldDescriptor::TYPE_MESSAGE : return -1;
170
171    // No default because we want the compiler to complain if any new
172    // types are added.
173  }
174  GOOGLE_LOG(FATAL) << "Can't get here.";
175  return -1;
176}
177
178// Returns true if the field has a default value equal to NaN.
179bool IsDefaultNaN(const FieldDescriptor* field) {
180  switch (field->type()) {
181    case FieldDescriptor::TYPE_INT32   : return false;
182    case FieldDescriptor::TYPE_UINT32  : return false;
183    case FieldDescriptor::TYPE_SINT32  : return false;
184    case FieldDescriptor::TYPE_FIXED32 : return false;
185    case FieldDescriptor::TYPE_SFIXED32: return false;
186    case FieldDescriptor::TYPE_INT64   : return false;
187    case FieldDescriptor::TYPE_UINT64  : return false;
188    case FieldDescriptor::TYPE_SINT64  : return false;
189    case FieldDescriptor::TYPE_FIXED64 : return false;
190    case FieldDescriptor::TYPE_SFIXED64: return false;
191    case FieldDescriptor::TYPE_FLOAT   :
192      return isnan(field->default_value_float());
193    case FieldDescriptor::TYPE_DOUBLE  :
194      return isnan(field->default_value_double());
195    case FieldDescriptor::TYPE_BOOL    : return false;
196    case FieldDescriptor::TYPE_STRING  : return false;
197    case FieldDescriptor::TYPE_BYTES   : return false;
198    case FieldDescriptor::TYPE_ENUM    : return false;
199    case FieldDescriptor::TYPE_GROUP   : return false;
200    case FieldDescriptor::TYPE_MESSAGE : return false;
201
202    // No default because we want the compiler to complain if any new
203    // types are added.
204  }
205
206  GOOGLE_LOG(FATAL) << "Can't get here.";
207  return false;
208}
209
210// Return true if the type is a that has variable length
211// for instance String's.
212bool IsVariableLenType(JavaType type) {
213  switch (type) {
214    case JAVATYPE_INT    : return false;
215    case JAVATYPE_LONG   : return false;
216    case JAVATYPE_FLOAT  : return false;
217    case JAVATYPE_DOUBLE : return false;
218    case JAVATYPE_BOOLEAN: return false;
219    case JAVATYPE_STRING : return true;
220    case JAVATYPE_BYTES  : return true;
221    case JAVATYPE_ENUM   : return false;
222    case JAVATYPE_MESSAGE: return true;
223
224    // No default because we want the compiler to complain if any new
225    // JavaTypes are added.
226  }
227
228  GOOGLE_LOG(FATAL) << "Can't get here.";
229  return false;
230}
231
232bool AllAscii(const string& text) {
233  for (int i = 0; i < text.size(); i++) {
234    if ((text[i] & 0x80) != 0) {
235      return false;
236    }
237  }
238  return true;
239}
240
241void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params params,
242                           map<string, string>* variables) {
243  (*variables)["name"] =
244    RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
245  (*variables)["capitalized_name"] =
246    RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor));
247  (*variables)["number"] = SimpleItoa(descriptor->number());
248  if (params.use_reference_types_for_primitives()
249      && !descriptor->is_repeated()) {
250    (*variables)["type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
251  } else {
252    (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
253  }
254  (*variables)["default"] = DefaultValue(params, descriptor);
255  (*variables)["default_constant"] = FieldDefaultConstantName(descriptor);
256  // For C++-string types (string and bytes), we might need to have
257  // the generated code do the unicode decoding (see comments in
258  // InternalNano.java for gory details.). We would like to do this
259  // once into a "private static final" field and re-use that from
260  // then on.
261  if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
262      !descriptor->default_value_string().empty() &&
263      !params.use_reference_types_for_primitives()) {
264    string default_value;
265    if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
266      default_value = strings::Substitute(
267          "com.google.protobuf.nano.InternalNano.bytesDefaultValue(\"$0\")",
268          CEscape(descriptor->default_value_string()));
269      (*variables)["default_copy_if_needed"] = (*variables)["default"] + ".clone()";
270    } else {
271      if (AllAscii(descriptor->default_value_string())) {
272        // All chars are ASCII.  In this case CEscape() works fine.
273        default_value = "\"" + CEscape(descriptor->default_value_string()) + "\"";
274      } else {
275        default_value = strings::Substitute(
276            "com.google.protobuf.nano.InternalNano.stringDefaultValue(\"$0\")",
277            CEscape(descriptor->default_value_string()));
278      }
279      (*variables)["default_copy_if_needed"] = (*variables)["default"];
280    }
281    (*variables)["default_constant_value"] = default_value;
282  } else {
283    (*variables)["default_copy_if_needed"] = (*variables)["default"];
284  }
285  (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
286  (*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
287  (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
288  (*variables)["tag_size"] = SimpleItoa(
289      WireFormat::TagSize(descriptor->number(), descriptor->type()));
290  int fixed_size = FixedSize(descriptor->type());
291  if (fixed_size != -1) {
292    (*variables)["fixed_size"] = SimpleItoa(fixed_size);
293  }
294  (*variables)["message_name"] = descriptor->containing_type()->name();
295  (*variables)["empty_array_name"] = EmptyArrayName(params, descriptor);
296}
297}  // namespace
298
299// ===================================================================
300
301PrimitiveFieldGenerator::
302PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
303  : FieldGenerator(params), descriptor_(descriptor) {
304  SetPrimitiveVariables(descriptor, params, &variables_);
305}
306
307PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
308
309void PrimitiveFieldGenerator::
310GenerateMembers(io::Printer* printer) const {
311  if (variables_.find("default_constant_value") != variables_.end()) {
312    // Those primitive types that need a saved default.
313    printer->Print(variables_,
314      "private static final $type$ $default_constant$ = $default_constant_value$;\n");
315  }
316
317  printer->Print(variables_,
318    "public $type$ $name$;\n");
319
320  if (params_.generate_has()) {
321    printer->Print(variables_,
322      "public boolean has$capitalized_name$ = false;\n");
323  }
324}
325
326void PrimitiveFieldGenerator::
327GenerateClearCode(io::Printer* printer) const {
328  printer->Print(variables_,
329    "$name$ = $default_copy_if_needed$;\n");
330
331  if (params_.generate_has()) {
332    printer->Print(variables_,
333      "has$capitalized_name$ = false;\n");
334  }
335}
336
337void PrimitiveFieldGenerator::
338GenerateMergingCode(io::Printer* printer) const {
339  printer->Print(variables_,
340    "this.$name$ = input.read$capitalized_type$();\n");
341
342  if (params_.generate_has()) {
343    printer->Print(variables_,
344      "has$capitalized_name$ = true;\n");
345  }
346}
347
348void PrimitiveFieldGenerator::
349GenerateSerializationConditional(io::Printer* printer) const {
350  if (params_.use_reference_types_for_primitives()) {
351    // For reference type mode, serialize based on equality
352    // to null.
353    printer->Print(variables_,
354      "if (this.$name$ != null) {\n");
355    return;
356  }
357  if (params_.generate_has()) {
358    printer->Print(variables_,
359      "if (has$capitalized_name$ || ");
360  } else {
361    printer->Print(variables_,
362      "if (");
363  }
364  if (IsArrayType(GetJavaType(descriptor_))) {
365    printer->Print(variables_,
366      "!java.util.Arrays.equals(this.$name$, $default$)) {\n");
367  } else if (IsReferenceType(GetJavaType(descriptor_))) {
368    printer->Print(variables_,
369      "!this.$name$.equals($default$)) {\n");
370  } else if (IsDefaultNaN(descriptor_)) {
371    printer->Print(variables_,
372      "!$capitalized_type$.isNaN(this.$name$)) {\n");
373  } else {
374    printer->Print(variables_,
375      "this.$name$ != $default$) {\n");
376  }
377}
378
379void PrimitiveFieldGenerator::
380GenerateSerializationCode(io::Printer* printer) const {
381  if (descriptor_->is_required()) {
382    printer->Print(variables_,
383      "output.write$capitalized_type$($number$, this.$name$);\n");
384  } else {
385    GenerateSerializationConditional(printer);
386    printer->Print(variables_,
387      "  output.write$capitalized_type$($number$, this.$name$);\n"
388      "}\n");
389  }
390}
391
392void PrimitiveFieldGenerator::
393GenerateSerializedSizeCode(io::Printer* printer) const {
394  if (descriptor_->is_required()) {
395    printer->Print(variables_,
396      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
397      "    .compute$capitalized_type$Size($number$, this.$name$);\n");
398  } else {
399    GenerateSerializationConditional(printer);
400    printer->Print(variables_,
401      "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
402      "      .compute$capitalized_type$Size($number$, this.$name$);\n"
403      "}\n");
404  }
405}
406
407void PrimitiveFieldGenerator::
408GenerateEqualsCode(io::Printer* printer) const {
409  // We define equality as serialized form equality. If generate_has(),
410  // then if the field value equals the default value in both messages,
411  // but one's 'has' field is set and the other's is not, the serialized
412  // forms are different and we should return false.
413  JavaType java_type = GetJavaType(descriptor_);
414  if (java_type == JAVATYPE_BYTES) {
415    printer->Print(variables_,
416      "if (!java.util.Arrays.equals(this.$name$, other.$name$)");
417    if (params_.generate_has()) {
418      printer->Print(variables_,
419        "\n"
420        "    || (java.util.Arrays.equals(this.$name$, $default$)\n"
421        "        && this.has$capitalized_name$ != other.has$capitalized_name$)");
422    }
423    printer->Print(") {\n"
424      "  return false;\n"
425      "}\n");
426  } else if (java_type == JAVATYPE_STRING
427      || params_.use_reference_types_for_primitives()) {
428    printer->Print(variables_,
429      "if (this.$name$ == null) {\n"
430      "  if (other.$name$ != null) {\n"
431      "    return false;\n"
432      "  }\n"
433      "} else if (!this.$name$.equals(other.$name$)");
434    if (params_.generate_has()) {
435      printer->Print(variables_,
436        "\n"
437        "    || (this.$name$.equals($default$)\n"
438        "        && this.has$capitalized_name$ != other.has$capitalized_name$)");
439    }
440    printer->Print(") {\n"
441      "  return false;\n"
442      "}\n");
443  } else {
444    printer->Print(variables_,
445      "if (this.$name$ != other.$name$");
446    if (params_.generate_has()) {
447      printer->Print(variables_,
448        "\n"
449        "    || (this.$name$ == $default$\n"
450        "        && this.has$capitalized_name$ != other.has$capitalized_name$)");
451    }
452    printer->Print(") {\n"
453      "  return false;\n"
454      "}\n");
455  }
456}
457
458void PrimitiveFieldGenerator::
459GenerateHashCodeCode(io::Printer* printer) const {
460  JavaType java_type = GetJavaType(descriptor_);
461  if (java_type == JAVATYPE_BYTES) {
462    printer->Print(variables_,
463      "result = 31 * result + java.util.Arrays.hashCode(this.$name$);\n");
464  } else if (java_type == JAVATYPE_STRING
465      || params_.use_reference_types_for_primitives()) {
466    printer->Print(variables_,
467      "result = 31 * result\n"
468      "    + (this.$name$ == null ? 0 : this.$name$.hashCode());\n");
469  } else {
470    switch (java_type) {
471      // For all Java primitive types below, the hash codes match the
472      // results of BoxedType.valueOf(primitiveValue).hashCode().
473      case JAVATYPE_INT:
474        printer->Print(variables_,
475          "result = 31 * result + this.$name$;\n");
476        break;
477      case JAVATYPE_LONG:
478        printer->Print(variables_,
479          "result = 31 * result\n"
480          "    + (int) (this.$name$ ^ (this.$name$ >>> 32));\n");
481        break;
482      case JAVATYPE_FLOAT:
483        printer->Print(variables_,
484          "result = 31 * result\n"
485          "    + java.lang.Float.floatToIntBits(this.$name$);\n");
486        break;
487      case JAVATYPE_DOUBLE:
488        printer->Print(variables_,
489          "{\n"
490          "  long v = java.lang.Double.doubleToLongBits(this.$name$);\n"
491          "  result = 31 * result + (int) (v ^ (v >>> 32));\n"
492          "}\n");
493        break;
494      case JAVATYPE_BOOLEAN:
495        printer->Print(variables_,
496          "result = 31 * result + (this.$name$ ? 1231 : 1237);\n");
497        break;
498      default:
499        GOOGLE_LOG(ERROR) << "unknown java type for primitive field";
500        break;
501    }
502  }
503}
504
505// ===================================================================
506
507AccessorPrimitiveFieldGenerator::
508AccessorPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
509     const Params& params, int has_bit_index)
510  : FieldGenerator(params), descriptor_(descriptor) {
511  SetPrimitiveVariables(descriptor, params, &variables_);
512  SetBitOperationVariables("has", has_bit_index, &variables_);
513}
514
515AccessorPrimitiveFieldGenerator::~AccessorPrimitiveFieldGenerator() {}
516
517void AccessorPrimitiveFieldGenerator::
518GenerateMembers(io::Printer* printer) const {
519  if (variables_.find("default_constant_value") != variables_.end()) {
520    printer->Print(variables_,
521      "private static final $type$ $default_constant$ = $default_constant_value$;\n");
522  }
523  printer->Print(variables_,
524    "private $type$ $name$_;\n"
525    "public $type$ get$capitalized_name$() {\n"
526    "  return $name$_;\n"
527    "}\n"
528    "public $message_name$ set$capitalized_name$($type$ value) {\n");
529  if (IsReferenceType(GetJavaType(descriptor_))) {
530    printer->Print(variables_,
531      "  if (value == null) {\n"
532      "    throw new java.lang.NullPointerException();\n"
533      "  }\n");
534  }
535  printer->Print(variables_,
536    "  $name$_ = value;\n"
537    "  $set_has$;\n"
538    "  return this;\n"
539    "}\n"
540    "public boolean has$capitalized_name$() {\n"
541    "  return $get_has$;\n"
542    "}\n"
543    "public $message_name$ clear$capitalized_name$() {\n"
544    "  $name$_ = $default_copy_if_needed$;\n"
545    "  $clear_has$;\n"
546    "  return this;\n"
547    "}\n");
548}
549
550void AccessorPrimitiveFieldGenerator::
551GenerateClearCode(io::Printer* printer) const {
552  printer->Print(variables_,
553    "$name$_ = $default_copy_if_needed$;\n");
554}
555
556void AccessorPrimitiveFieldGenerator::
557GenerateMergingCode(io::Printer* printer) const {
558  printer->Print(variables_,
559    "$name$_ = input.read$capitalized_type$();\n"
560    "$set_has$;\n");
561}
562
563void AccessorPrimitiveFieldGenerator::
564GenerateSerializationCode(io::Printer* printer) const {
565  printer->Print(variables_,
566    "if ($get_has$) {\n"
567    "  output.write$capitalized_type$($number$, $name$_);\n"
568    "}\n");
569}
570
571void AccessorPrimitiveFieldGenerator::
572GenerateSerializedSizeCode(io::Printer* printer) const {
573  printer->Print(variables_,
574    "if ($get_has$) {\n"
575    "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
576    "      .compute$capitalized_type$Size($number$, $name$_);\n"
577    "}\n");
578}
579
580void AccessorPrimitiveFieldGenerator::
581GenerateEqualsCode(io::Printer* printer) const {
582  switch (GetJavaType(descriptor_)) {
583    // For all Java primitive types below, the hash codes match the
584    // results of BoxedType.valueOf(primitiveValue).hashCode().
585    case JAVATYPE_INT:
586    case JAVATYPE_LONG:
587    case JAVATYPE_FLOAT:
588    case JAVATYPE_DOUBLE:
589    case JAVATYPE_BOOLEAN:
590      printer->Print(variables_,
591        "if ($different_has$\n"
592        "    || $name$_ != other.$name$_) {\n"
593        "  return false;\n"
594        "}\n");
595      break;
596    case JAVATYPE_STRING:
597      // Accessor style would guarantee $name$_ non-null
598      printer->Print(variables_,
599        "if ($different_has$\n"
600        "    || !$name$_.equals(other.$name$_)) {\n"
601        "  return false;\n"
602        "}\n");
603      break;
604    case JAVATYPE_BYTES:
605      // Accessor style would guarantee $name$_ non-null
606      printer->Print(variables_,
607        "if ($different_has$\n"
608        "    || !java.util.Arrays.equals($name$_, other.$name$_)) {\n"
609        "  return false;\n"
610        "}\n");
611      break;
612    default:
613      GOOGLE_LOG(ERROR) << "unknown java type for primitive field";
614      break;
615  }
616}
617
618void AccessorPrimitiveFieldGenerator::
619GenerateHashCodeCode(io::Printer* printer) const {
620  switch (GetJavaType(descriptor_)) {
621    // For all Java primitive types below, the hash codes match the
622    // results of BoxedType.valueOf(primitiveValue).hashCode().
623    case JAVATYPE_INT:
624      printer->Print(variables_,
625        "result = 31 * result + $name$_;\n");
626      break;
627    case JAVATYPE_LONG:
628      printer->Print(variables_,
629        "result = 31 * result + (int) ($name$_ ^ ($name$_ >>> 32));\n");
630      break;
631    case JAVATYPE_FLOAT:
632      printer->Print(variables_,
633        "result = 31 * result +\n"
634        "    java.lang.Float.floatToIntBits($name$_);\n");
635      break;
636    case JAVATYPE_DOUBLE:
637      printer->Print(variables_,
638        "{\n"
639        "  long v = java.lang.Double.doubleToLongBits($name$_);\n"
640        "  result = 31 * result + (int) (v ^ (v >>> 32));\n"
641        "}\n");
642      break;
643    case JAVATYPE_BOOLEAN:
644      printer->Print(variables_,
645        "result = 31 * result + ($name$_ ? 1231 : 1237);\n");
646      break;
647    case JAVATYPE_STRING:
648      // Accessor style would guarantee $name$_ non-null
649      printer->Print(variables_,
650        "result = 31 * result + $name$_.hashCode();\n");
651      break;
652    case JAVATYPE_BYTES:
653      // Accessor style would guarantee $name$_ non-null
654      printer->Print(variables_,
655        "result = 31 * result + java.util.Arrays.hashCode($name$_);\n");
656      break;
657    default:
658      GOOGLE_LOG(ERROR) << "unknown java type for primitive field";
659      break;
660  }
661}
662
663// ===================================================================
664
665RepeatedPrimitiveFieldGenerator::
666RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
667  : FieldGenerator(params), descriptor_(descriptor) {
668  SetPrimitiveVariables(descriptor, params, &variables_);
669}
670
671RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
672
673void RepeatedPrimitiveFieldGenerator::
674GenerateMembers(io::Printer* printer) const {
675  printer->Print(variables_,
676    "public $type$[] $name$;\n");
677}
678
679void RepeatedPrimitiveFieldGenerator::
680GenerateClearCode(io::Printer* printer) const {
681  printer->Print(variables_,
682    "$name$ = $default$;\n");
683}
684
685void RepeatedPrimitiveFieldGenerator::
686GenerateMergingCode(io::Printer* printer) const {
687  // First, figure out the length of the array, then parse.
688  if (descriptor_->options().packed()) {
689    printer->Print(variables_,
690      "int length = input.readRawVarint32();\n"
691      "int limit = input.pushLimit(length);\n"
692      "// First pass to compute array length.\n"
693      "int arrayLength = 0;\n"
694      "int startPos = input.getPosition();\n"
695      "while (input.getBytesUntilLimit() > 0) {\n"
696      "  input.read$capitalized_type$();\n"
697      "  arrayLength++;\n"
698      "}\n"
699      "input.rewindToPosition(startPos);\n"
700      "int i = this.$name$ == null ? 0 : this.$name$.length;\n"
701      "$type$[] newArray = new $type$[i + arrayLength];\n"
702      "if (i != 0) {\n"
703      "  java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
704      "}\n"
705      "for (; i < newArray.length; i++) {\n"
706      "  newArray[i] = input.read$capitalized_type$();\n"
707      "}\n"
708      "this.$name$ = newArray;\n"
709      "input.popLimit(limit);\n");
710  } else {
711    printer->Print(variables_,
712      "int arrayLength = com.google.protobuf.nano.WireFormatNano\n"
713      "    .getRepeatedFieldArrayLength(input, $tag$);\n"
714      "int i = this.$name$ == null ? 0 : this.$name$.length;\n");
715
716    if (GetJavaType(descriptor_) == JAVATYPE_BYTES) {
717      printer->Print(variables_,
718        "byte[][] newArray = new byte[i + arrayLength][];\n");
719    } else {
720      printer->Print(variables_,
721        "$type$[] newArray = new $type$[i + arrayLength];\n");
722    }
723    printer->Print(variables_,
724      "if (i != 0) {\n"
725      "  java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
726      "}\n"
727      "for (; i < newArray.length - 1; i++) {\n"
728      "  newArray[i] = input.read$capitalized_type$();\n"
729      "  input.readTag();\n"
730      "}\n"
731      "// Last one without readTag.\n"
732      "newArray[i] = input.read$capitalized_type$();\n"
733      "this.$name$ = newArray;\n");
734  }
735}
736
737void RepeatedPrimitiveFieldGenerator::
738GenerateRepeatedDataSizeCode(io::Printer* printer) const {
739  // Creates a variable dataSize and puts the serialized size in
740  // there.
741  if (FixedSize(descriptor_->type()) == -1) {
742    printer->Print(variables_,
743      "int dataSize = 0;\n"
744      "for ($type$ element : this.$name$) {\n"
745      "  dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
746      "    .compute$capitalized_type$SizeNoTag(element);\n"
747      "}\n");
748  } else {
749    printer->Print(variables_,
750      "int dataSize = $fixed_size$ * this.$name$.length;\n");
751  }
752}
753
754void RepeatedPrimitiveFieldGenerator::
755GenerateSerializationCode(io::Printer* printer) const {
756  printer->Print(variables_,
757    "if (this.$name$ != null && this.$name$.length > 0) {\n");
758  printer->Indent();
759
760  if (descriptor_->options().packed()) {
761    GenerateRepeatedDataSizeCode(printer);
762    printer->Print(variables_,
763      "output.writeRawVarint32($tag$);\n"
764      "output.writeRawVarint32(dataSize);\n"
765      "for ($type$ element : this.$name$) {\n"
766      "  output.write$capitalized_type$NoTag(element);\n"
767      "}\n");
768  } else {
769    printer->Print(variables_,
770      "for ($type$ element : this.$name$) {\n"
771      "  output.write$capitalized_type$($number$, element);\n"
772      "}\n");
773  }
774
775  printer->Outdent();
776  printer->Print("}\n");
777}
778
779void RepeatedPrimitiveFieldGenerator::
780GenerateSerializedSizeCode(io::Printer* printer) const {
781  printer->Print(variables_,
782    "if (this.$name$ != null && this.$name$.length > 0) {\n");
783  printer->Indent();
784
785  GenerateRepeatedDataSizeCode(printer);
786
787  printer->Print(
788    "size += dataSize;\n");
789  if (descriptor_->options().packed()) {
790    printer->Print(variables_,
791      "size += $tag_size$;\n"
792      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
793      "  .computeRawVarint32Size(dataSize);\n");
794  } else {
795    printer->Print(variables_,
796        "size += $tag_size$ * this.$name$.length;\n");
797  }
798
799  printer->Outdent();
800
801  printer->Print(
802    "}\n");
803}
804
805void RepeatedPrimitiveFieldGenerator::
806GenerateEqualsCode(io::Printer* printer) const {
807  printer->Print(variables_,
808    "if (!com.google.protobuf.nano.InternalNano.equals(\n"
809    "    this.$name$, other.$name$)) {\n"
810    "  return false;\n"
811    "}\n");
812}
813
814void RepeatedPrimitiveFieldGenerator::
815GenerateHashCodeCode(io::Printer* printer) const {
816  printer->Print(variables_,
817    "result = 31 * result\n"
818    "    + com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n");
819}
820
821}  // namespace javanano
822}  // namespace compiler
823}  // namespace protobuf
824}  // namespace google
825