javanano_primitive_field.cc revision 64d8d8f89050c5ada85341f967af391f4716a7cb
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/javanano/javanano_primitive_field.h>
39#include <google/protobuf/stubs/common.h>
40#include <google/protobuf/compiler/javanano/javanano_helpers.h>
41#include <google/protobuf/io/printer.h>
42#include <google/protobuf/wire_format.h>
43#include <google/protobuf/stubs/strutil.h>
44#include <google/protobuf/stubs/substitute.h>
45
46namespace google {
47namespace protobuf {
48namespace compiler {
49namespace javanano {
50
51using internal::WireFormat;
52using internal::WireFormatLite;
53
54namespace {
55
56const 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 "byte[]";
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
76bool 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 false;
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
96bool IsArrayType(JavaType type) {
97  switch (type) {
98    case JAVATYPE_INT    : return false;
99    case JAVATYPE_LONG   : return false;
100    case JAVATYPE_FLOAT  : return false;
101    case JAVATYPE_DOUBLE : return false;
102    case JAVATYPE_BOOLEAN: return false;
103    case JAVATYPE_STRING : return false;
104    case JAVATYPE_BYTES  : return true;
105    case JAVATYPE_ENUM   : return false;
106    case JAVATYPE_MESSAGE: return false;
107
108    // No default because we want the compiler to complain if any new
109    // JavaTypes are added.
110  }
111
112  GOOGLE_LOG(FATAL) << "Can't get here.";
113  return false;
114}
115
116const char* GetCapitalizedType(const FieldDescriptor* field) {
117  switch (field->type()) {
118    case FieldDescriptor::TYPE_INT32   : return "Int32"   ;
119    case FieldDescriptor::TYPE_UINT32  : return "UInt32"  ;
120    case FieldDescriptor::TYPE_SINT32  : return "SInt32"  ;
121    case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ;
122    case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
123    case FieldDescriptor::TYPE_INT64   : return "Int64"   ;
124    case FieldDescriptor::TYPE_UINT64  : return "UInt64"  ;
125    case FieldDescriptor::TYPE_SINT64  : return "SInt64"  ;
126    case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ;
127    case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
128    case FieldDescriptor::TYPE_FLOAT   : return "Float"   ;
129    case FieldDescriptor::TYPE_DOUBLE  : return "Double"  ;
130    case FieldDescriptor::TYPE_BOOL    : return "Bool"    ;
131    case FieldDescriptor::TYPE_STRING  : return "String"  ;
132    case FieldDescriptor::TYPE_BYTES   : return "Bytes"   ;
133    case FieldDescriptor::TYPE_ENUM    : return "Enum"    ;
134    case FieldDescriptor::TYPE_GROUP   : return "Group"   ;
135    case FieldDescriptor::TYPE_MESSAGE : return "Message" ;
136
137    // No default because we want the compiler to complain if any new
138    // types are added.
139  }
140
141  GOOGLE_LOG(FATAL) << "Can't get here.";
142  return NULL;
143}
144
145// For encodings with fixed sizes, returns that size in bytes.  Otherwise
146// returns -1.
147int FixedSize(FieldDescriptor::Type type) {
148  switch (type) {
149    case FieldDescriptor::TYPE_INT32   : return -1;
150    case FieldDescriptor::TYPE_INT64   : return -1;
151    case FieldDescriptor::TYPE_UINT32  : return -1;
152    case FieldDescriptor::TYPE_UINT64  : return -1;
153    case FieldDescriptor::TYPE_SINT32  : return -1;
154    case FieldDescriptor::TYPE_SINT64  : return -1;
155    case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
156    case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
157    case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
158    case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
159    case FieldDescriptor::TYPE_FLOAT   : return WireFormatLite::kFloatSize;
160    case FieldDescriptor::TYPE_DOUBLE  : return WireFormatLite::kDoubleSize;
161
162    case FieldDescriptor::TYPE_BOOL    : return WireFormatLite::kBoolSize;
163    case FieldDescriptor::TYPE_ENUM    : return -1;
164
165    case FieldDescriptor::TYPE_STRING  : return -1;
166    case FieldDescriptor::TYPE_BYTES   : return -1;
167    case FieldDescriptor::TYPE_GROUP   : return -1;
168    case FieldDescriptor::TYPE_MESSAGE : return -1;
169
170    // No default because we want the compiler to complain if any new
171    // types are added.
172  }
173  GOOGLE_LOG(FATAL) << "Can't get here.";
174  return -1;
175}
176
177// Return true if the type is a that has variable length
178// for instance String's.
179bool IsVariableLenType(JavaType type) {
180  switch (type) {
181    case JAVATYPE_INT    : return false;
182    case JAVATYPE_LONG   : return false;
183    case JAVATYPE_FLOAT  : return false;
184    case JAVATYPE_DOUBLE : return false;
185    case JAVATYPE_BOOLEAN: return false;
186    case JAVATYPE_STRING : return true;
187    case JAVATYPE_BYTES  : return true;
188    case JAVATYPE_ENUM   : return false;
189    case JAVATYPE_MESSAGE: return true;
190
191    // No default because we want the compiler to complain if any new
192    // JavaTypes are added.
193  }
194
195  GOOGLE_LOG(FATAL) << "Can't get here.";
196  return false;
197}
198
199bool AllAscii(const string& text) {
200  for (int i = 0; i < text.size(); i++) {
201    if ((text[i] & 0x80) != 0) {
202      return false;
203    }
204  }
205  return true;
206}
207
208void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params params,
209                           map<string, string>* variables) {
210  (*variables)["name"] =
211    UnderscoresToCamelCase(descriptor);
212  (*variables)["capitalized_name"] =
213    UnderscoresToCapitalizedCamelCase(descriptor);
214  (*variables)["number"] = SimpleItoa(descriptor->number());
215  (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
216  (*variables)["default"] = DefaultValue(params, descriptor);
217  (*variables)["default_constant"] = FieldDefaultConstantName(descriptor);
218  // For C++-string types (string and bytes), we might need to have
219  // the generated code do the unicode decoding (see comments in
220  // InternalNano.java for gory details.). We would like to do this
221  // once into a "private static final" field and re-use that from
222  // then on.
223  if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
224      !descriptor->default_value_string().empty()) {
225    string default_value;
226    if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
227      default_value = strings::Substitute(
228          "com.google.protobuf.nano.InternalNano.bytesDefaultValue(\"$0\")",
229          CEscape(descriptor->default_value_string()));
230    } else {
231      if (AllAscii(descriptor->default_value_string())) {
232        // All chars are ASCII.  In this case CEscape() works fine.
233        default_value = "\"" + CEscape(descriptor->default_value_string()) + "\"";
234      } else {
235        default_value = strings::Substitute(
236            "com.google.protobuf.nano.InternalNano.stringDefaultValue(\"$0\")",
237            CEscape(descriptor->default_value_string()));
238      }
239    }
240    (*variables)["default_constant_value"] = default_value;
241  }
242  (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
243  (*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
244  (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
245  (*variables)["tag_size"] = SimpleItoa(
246      WireFormat::TagSize(descriptor->number(), descriptor->type()));
247  if (IsReferenceType(GetJavaType(descriptor))) {
248    (*variables)["null_check"] =
249        "  if (value == null) {\n"
250        "    throw new NullPointerException();\n"
251        "  }\n";
252  } else {
253    (*variables)["null_check"] = "";
254  }
255  int fixed_size = FixedSize(descriptor->type());
256  if (fixed_size != -1) {
257    (*variables)["fixed_size"] = SimpleItoa(fixed_size);
258  }
259  (*variables)["message_name"] = descriptor->containing_type()->name();
260  (*variables)["empty_array_name"] = EmptyArrayName(params, descriptor);
261}
262}  // namespace
263
264// ===================================================================
265
266PrimitiveFieldGenerator::
267PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
268  : FieldGenerator(params), descriptor_(descriptor) {
269  SetPrimitiveVariables(descriptor, params, &variables_);
270}
271
272PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
273
274void PrimitiveFieldGenerator::
275GenerateMembers(io::Printer* printer) const {
276  if (variables_.find("default_constant_value") != variables_.end()) {
277    // Those primitive types that need a saved default.
278    printer->Print(variables_,
279      "private static final $type$ $default_constant$ = $default_constant_value$;\n");
280    if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) {
281      printer->Print(variables_,
282        "public $type$ $name$ = $default$.clone();\n");
283    } else {
284      printer->Print(variables_,
285        "public $type$ $name$ = $default$;\n");
286    }
287  } else {
288    printer->Print(variables_,
289      "public $type$ $name$ = $default$;\n");
290  }
291}
292
293void PrimitiveFieldGenerator::
294GenerateMergingCode(io::Printer* printer) const {
295  printer->Print(variables_, "$name$ = other.$name$;\n");
296}
297
298void PrimitiveFieldGenerator::
299GenerateParsingCode(io::Printer* printer) const {
300  printer->Print(variables_,
301    "$name$ = input.read$capitalized_type$();\n");
302}
303
304void PrimitiveFieldGenerator::
305GenerateSerializationCode(io::Printer* printer) const {
306  if (descriptor_->is_required()) {
307    printer->Print(variables_,
308      "output.write$capitalized_type$($number$, $name$);\n");
309  } else {
310    if (IsArrayType(GetJavaType(descriptor_))) {
311      printer->Print(variables_,
312        "if (!java.util.Arrays.equals($name$, $default$)) {\n");
313    } else if (IsReferenceType(GetJavaType(descriptor_))) {
314      printer->Print(variables_,
315        "if (!$name$.equals($default$)) {\n");
316    } else {
317      printer->Print(variables_,
318        "if ($name$ != $default$) {\n");
319    }
320
321    printer->Print(variables_,
322      "  output.write$capitalized_type$($number$, $name$);\n"
323      "}\n");
324  }
325}
326
327void PrimitiveFieldGenerator::
328GenerateSerializedSizeCode(io::Printer* printer) const {
329  if (descriptor_->is_required()) {
330    printer->Print(variables_,
331      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
332      "    .compute$capitalized_type$Size($number$, $name$);\n");
333  } else {
334    if (IsArrayType(GetJavaType(descriptor_))) {
335      printer->Print(variables_,
336        "if (!java.util.Arrays.equals($name$, $default$)) {\n");
337    } else  if (IsReferenceType(GetJavaType(descriptor_))) {
338      printer->Print(variables_,
339        "if (!$name$.equals($default$)) {\n");
340    } else {
341      printer->Print(variables_,
342        "if ($name$ != $default$) {\n");
343    }
344
345    printer->Print(variables_,
346      "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
347      "      .compute$capitalized_type$Size($number$, $name$);\n"
348      "}\n");
349  }
350}
351
352string PrimitiveFieldGenerator::GetBoxedType() const {
353  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
354}
355
356// ===================================================================
357
358RepeatedPrimitiveFieldGenerator::
359RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
360  : FieldGenerator(params), descriptor_(descriptor) {
361  SetPrimitiveVariables(descriptor, params, &variables_);
362}
363
364RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
365
366void RepeatedPrimitiveFieldGenerator::
367GenerateMembers(io::Printer* printer) const {
368  printer->Print(variables_,
369    "public $type$[] $name$ = $default$;\n");
370  if (descriptor_->options().packed()) {
371    printer->Print(variables_,
372      "private int $name$MemoizedSerializedSize;\n");
373  }
374}
375
376void RepeatedPrimitiveFieldGenerator::
377GenerateMergingCode(io::Printer* printer) const {
378  printer->Print(variables_,
379    "if (other.$name$.length > 0) {\n"
380    "  $type$[] merged = java.util.Arrays.copyOf(result.$name$, result.$name$.length + other.$name$.length);\n"
381    "  java.lang.System.arraycopy(other.$name$, 0, merged, results.$name$.length, other.$name$.length);\n"
382    "  result.$name$ = merged;\n"
383    "}\n");
384}
385
386void RepeatedPrimitiveFieldGenerator::
387GenerateParsingCode(io::Printer* printer) const {
388  // First, figure out the length of the array, then parse.
389  if (descriptor_->options().packed()) {
390    printer->Print(variables_,
391      "int length = input.readRawVarint32();\n"
392      "int limit = input.pushLimit(length);\n"
393      "// First pass to compute array length.\n"
394      "int arrayLength = 0;\n"
395      "int startPos = input.getPosition();\n"
396      "while (input.getBytesUntilLimit() > 0) {\n"
397      "  input.read$capitalized_type$();\n"
398      "  arrayLength++;\n"
399      "}\n"
400      "input.rewindToPosition(startPos);\n"
401      "$name$ = new $type$[arrayLength];\n"
402      "for (int i = 0; i < arrayLength; i++) {\n"
403      "  $name$[i] = input.read$capitalized_type$();\n"
404      "}\n"
405      "input.popLimit(limit);\n");
406  } else {
407    printer->Print(variables_,
408      "int arrayLength = com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, $tag$);\n"
409      "int i = $name$.length;\n"
410      "$name$ = java.util.Arrays.copyOf($name$, $name$.length + arrayLength);\n"
411      "for (; i < $name$.length - 1; i++) {\n"
412      "  $name$[i] = input.read$capitalized_type$();\n"
413      "  input.readTag();\n"
414      "}\n"
415      "// Last one without readTag.\n"
416      "$name$[i] = input.read$capitalized_type$();\n");
417  }
418}
419
420void RepeatedPrimitiveFieldGenerator::
421GenerateSerializationCode(io::Printer* printer) const {
422  if (descriptor_->options().packed()) {
423    printer->Print(variables_,
424      "if ($name$.length > 0) {\n"
425      "  output.writeRawVarint32($tag$);\n"
426      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
427      "}\n");
428    printer->Print(variables_,
429      "for ($type$ element : $name$) {\n"
430      "  output.write$capitalized_type$NoTag(element);\n"
431      "}\n");
432  } else {
433    printer->Print(variables_,
434      "for ($type$ element : $name$) {\n"
435      "  output.write$capitalized_type$($number$, element);\n"
436      "}\n");
437  }
438}
439
440void RepeatedPrimitiveFieldGenerator::
441GenerateSerializedSizeCode(io::Printer* printer) const {
442  printer->Print(variables_,
443    "if ($name$.length > 0) {\n");
444  printer->Indent();
445
446  if (FixedSize(descriptor_->type()) == -1) {
447    printer->Print(variables_,
448      "int dataSize = 0;\n"
449      "for ($type$ element : $name$) {\n"
450      "  dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
451      "    .compute$capitalized_type$SizeNoTag(element);\n"
452      "}\n");
453  } else {
454    printer->Print(variables_,
455      "int dataSize = $fixed_size$ * $name$.length;\n");
456  }
457
458  printer->Print(
459    "size += dataSize;\n");
460  if (descriptor_->options().packed()) {
461    // cache the data size for packed fields.
462    printer->Print(variables_,
463      "size += $tag_size$;\n"
464      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
465      "  .computeRawVarint32Size(dataSize);\n"
466      "$name$MemoizedSerializedSize = dataSize;\n");
467  } else {
468    printer->Print(variables_,
469        "size += $tag_size$ * $name$.length;\n");
470  }
471
472  printer->Outdent();
473
474  // set cached size to 0 for empty packed fields.
475  if (descriptor_->options().packed()) {
476    printer->Print(variables_,
477      "} else {\n"
478      "  $name$MemoizedSerializedSize = 0;\n"
479      "}\n");
480  } else {
481    printer->Print(
482      "}\n");
483  }
484}
485
486string RepeatedPrimitiveFieldGenerator::GetBoxedType() const {
487  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
488}
489
490}  // namespace javanano
491}  // namespace compiler
492}  // namespace protobuf
493}  // namespace google
494