javanano_primitive_field.cc revision 0f2ca89132ab81441f7eb351c7a053a8c8d9d1c3
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  (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
249  (*variables)["default"] = DefaultValue(params, descriptor);
250  (*variables)["default_constant"] = FieldDefaultConstantName(descriptor);
251  // For C++-string types (string and bytes), we might need to have
252  // the generated code do the unicode decoding (see comments in
253  // InternalNano.java for gory details.). We would like to do this
254  // once into a "private static final" field and re-use that from
255  // then on.
256  if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
257      !descriptor->default_value_string().empty()) {
258    string default_value;
259    if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
260      default_value = strings::Substitute(
261          "com.google.protobuf.nano.InternalNano.bytesDefaultValue(\"$0\")",
262          CEscape(descriptor->default_value_string()));
263    } else {
264      if (AllAscii(descriptor->default_value_string())) {
265        // All chars are ASCII.  In this case CEscape() works fine.
266        default_value = "\"" + CEscape(descriptor->default_value_string()) + "\"";
267      } else {
268        default_value = strings::Substitute(
269            "com.google.protobuf.nano.InternalNano.stringDefaultValue(\"$0\")",
270            CEscape(descriptor->default_value_string()));
271      }
272    }
273    (*variables)["default_constant_value"] = default_value;
274  }
275  (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
276  (*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
277  (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
278  (*variables)["tag_size"] = SimpleItoa(
279      WireFormat::TagSize(descriptor->number(), descriptor->type()));
280  if (IsReferenceType(GetJavaType(descriptor))) {
281    (*variables)["null_check"] =
282        "  if (value == null) {\n"
283        "    throw new NullPointerException();\n"
284        "  }\n";
285  } else {
286    (*variables)["null_check"] = "";
287  }
288  int fixed_size = FixedSize(descriptor->type());
289  if (fixed_size != -1) {
290    (*variables)["fixed_size"] = SimpleItoa(fixed_size);
291  }
292  (*variables)["message_name"] = descriptor->containing_type()->name();
293  (*variables)["empty_array_name"] = EmptyArrayName(params, descriptor);
294}
295}  // namespace
296
297// ===================================================================
298
299PrimitiveFieldGenerator::
300PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
301  : FieldGenerator(params), descriptor_(descriptor) {
302  SetPrimitiveVariables(descriptor, params, &variables_);
303}
304
305PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
306
307void PrimitiveFieldGenerator::
308GenerateMembers(io::Printer* printer) const {
309  if (variables_.find("default_constant_value") != variables_.end()) {
310    // Those primitive types that need a saved default.
311    printer->Print(variables_,
312      "private static final $type$ $default_constant$ = $default_constant_value$;\n");
313    if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) {
314      printer->Print(variables_,
315        "public $type$ $name$ = $default$.clone();\n");
316    } else {
317      printer->Print(variables_,
318        "public $type$ $name$ = $default$;\n");
319    }
320  } else {
321    printer->Print(variables_,
322      "public $type$ $name$ = $default$;\n");
323  }
324}
325
326void PrimitiveFieldGenerator::
327GenerateParsingCode(io::Printer* printer) const {
328  printer->Print(variables_,
329    "this.$name$ = input.read$capitalized_type$();\n");
330}
331
332void PrimitiveFieldGenerator::
333GenerateSerializationCode(io::Printer* printer) const {
334  if (descriptor_->is_required()) {
335    printer->Print(variables_,
336      "output.write$capitalized_type$($number$, this.$name$);\n");
337  } else {
338    if (IsArrayType(GetJavaType(descriptor_))) {
339      printer->Print(variables_,
340        "if (!java.util.Arrays.equals(this.$name$, $default$)) {\n");
341    } else if (IsReferenceType(GetJavaType(descriptor_))) {
342      printer->Print(variables_,
343        "if (!this.$name$.equals($default$)) {\n");
344    } else if (IsDefaultNaN(descriptor_)) {
345      printer->Print(variables_,
346        "if (!$capitalized_type$.isNaN(this.$name$)) {\n");
347    } else {
348      printer->Print(variables_,
349        "if (this.$name$ != $default$) {\n");
350    }
351
352    printer->Print(variables_,
353      "  output.write$capitalized_type$($number$, this.$name$);\n"
354      "}\n");
355  }
356}
357
358void PrimitiveFieldGenerator::
359GenerateSerializedSizeCode(io::Printer* printer) const {
360  if (descriptor_->is_required()) {
361    printer->Print(variables_,
362      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
363      "    .compute$capitalized_type$Size($number$, this.$name$);\n");
364  } else {
365    if (IsArrayType(GetJavaType(descriptor_))) {
366      printer->Print(variables_,
367        "if (!java.util.Arrays.equals(this.$name$, $default$)) {\n");
368    } else  if (IsReferenceType(GetJavaType(descriptor_))) {
369      printer->Print(variables_,
370        "if (!this.$name$.equals($default$)) {\n");
371    } else if (IsDefaultNaN(descriptor_)) {
372      printer->Print(variables_,
373        "if (!$capitalized_type$.isNaN(this.$name$)) {\n");
374    } else {
375      printer->Print(variables_,
376        "if (this.$name$ != $default$) {\n");
377    }
378
379    printer->Print(variables_,
380      "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
381      "      .compute$capitalized_type$Size($number$, this.$name$);\n"
382      "}\n");
383  }
384}
385
386string PrimitiveFieldGenerator::GetBoxedType() const {
387  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
388}
389
390// ===================================================================
391
392RepeatedPrimitiveFieldGenerator::
393RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
394  : FieldGenerator(params), descriptor_(descriptor) {
395  SetPrimitiveVariables(descriptor, params, &variables_);
396}
397
398RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
399
400void RepeatedPrimitiveFieldGenerator::
401GenerateMembers(io::Printer* printer) const {
402  printer->Print(variables_,
403    "public $type$[] $name$ = $default$;\n");
404  if (descriptor_->options().packed()) {
405    printer->Print(variables_,
406      "private int $name$MemoizedSerializedSize;\n");
407  }
408}
409
410void RepeatedPrimitiveFieldGenerator::
411GenerateParsingCode(io::Printer* printer) const {
412  // First, figure out the length of the array, then parse.
413  if (descriptor_->options().packed()) {
414    printer->Print(variables_,
415      "int length = input.readRawVarint32();\n"
416      "int limit = input.pushLimit(length);\n"
417      "// First pass to compute array length.\n"
418      "int arrayLength = 0;\n"
419      "int startPos = input.getPosition();\n"
420      "while (input.getBytesUntilLimit() > 0) {\n"
421      "  input.read$capitalized_type$();\n"
422      "  arrayLength++;\n"
423      "}\n"
424      "input.rewindToPosition(startPos);\n"
425      "this.$name$ = new $type$[arrayLength];\n"
426      "for (int i = 0; i < arrayLength; i++) {\n"
427      "  this.$name$[i] = input.read$capitalized_type$();\n"
428      "}\n"
429      "input.popLimit(limit);\n");
430  } else {
431    printer->Print(variables_,
432      "int arrayLength = com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, $tag$);\n"
433      "int i = this.$name$.length;\n");
434
435    if (GetJavaType(descriptor_) == JAVATYPE_BYTES) {
436      printer->Print(variables_,
437        "byte[][] newArray = new byte[i + arrayLength][];\n"
438        "System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
439        "this.$name$ = newArray;\n");
440    } else {
441      printer->Print(variables_,
442        "$type$[] newArray = new $type$[i + arrayLength];\n"
443        "System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
444        "this.$name$ = newArray;\n");
445    }
446    printer->Print(variables_,
447      "for (; i < this.$name$.length - 1; i++) {\n"
448      "  this.$name$[i] = input.read$capitalized_type$();\n"
449      "  input.readTag();\n"
450      "}\n"
451      "// Last one without readTag.\n"
452      "this.$name$[i] = input.read$capitalized_type$();\n");
453  }
454}
455
456void RepeatedPrimitiveFieldGenerator::
457GenerateSerializationCode(io::Printer* printer) const {
458  if (descriptor_->options().packed()) {
459    printer->Print(variables_,
460      "if (this.$name$.length > 0) {\n"
461      "  output.writeRawVarint32($tag$);\n"
462      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
463      "}\n");
464    printer->Print(variables_,
465      "for ($type$ element : this.$name$) {\n"
466      "  output.write$capitalized_type$NoTag(element);\n"
467      "}\n");
468  } else {
469    printer->Print(variables_,
470      "for ($type$ element : this.$name$) {\n"
471      "  output.write$capitalized_type$($number$, element);\n"
472      "}\n");
473  }
474}
475
476void RepeatedPrimitiveFieldGenerator::
477GenerateSerializedSizeCode(io::Printer* printer) const {
478  printer->Print(variables_,
479    "if (this.$name$.length > 0) {\n");
480  printer->Indent();
481
482  if (FixedSize(descriptor_->type()) == -1) {
483    printer->Print(variables_,
484      "int dataSize = 0;\n"
485      "for ($type$ element : this.$name$) {\n"
486      "  dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
487      "    .compute$capitalized_type$SizeNoTag(element);\n"
488      "}\n");
489  } else {
490    printer->Print(variables_,
491      "int dataSize = $fixed_size$ * this.$name$.length;\n");
492  }
493
494  printer->Print(
495    "size += dataSize;\n");
496  if (descriptor_->options().packed()) {
497    // cache the data size for packed fields.
498    printer->Print(variables_,
499      "size += $tag_size$;\n"
500      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
501      "  .computeRawVarint32Size(dataSize);\n"
502      "$name$MemoizedSerializedSize = dataSize;\n");
503  } else {
504    printer->Print(variables_,
505        "size += $tag_size$ * this.$name$.length;\n");
506  }
507
508  printer->Outdent();
509
510  // set cached size to 0 for empty packed fields.
511  if (descriptor_->options().packed()) {
512    printer->Print(variables_,
513      "} else {\n"
514      "  $name$MemoizedSerializedSize = 0;\n"
515      "}\n");
516  } else {
517    printer->Print(
518      "}\n");
519  }
520}
521
522string RepeatedPrimitiveFieldGenerator::GetBoxedType() const {
523  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
524}
525
526}  // namespace javanano
527}  // namespace compiler
528}  // namespace protobuf
529}  // namespace google
530