javanano_enum_field.cc revision f4e01452f159ae6b53f5edd25fa647ca2919ae10
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_enum_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
45namespace google {
46namespace protobuf {
47namespace compiler {
48namespace javanano {
49
50namespace {
51
52// TODO(kenton):  Factor out a "SetCommonFieldVariables()" to get rid of
53//   repeat code between this and the other field types.
54void SetEnumVariables(const Params& params,
55    const FieldDescriptor* descriptor, map<string, string>* variables) {
56  (*variables)["name"] =
57    RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
58  (*variables)["capitalized_name"] =
59    RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor));
60  (*variables)["number"] = SimpleItoa(descriptor->number());
61  (*variables)["type"] = "int";
62  (*variables)["default"] = DefaultValue(params, descriptor);
63  (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
64  (*variables)["tag_size"] = SimpleItoa(
65      internal::WireFormat::TagSize(descriptor->number(), descriptor->type()));
66  (*variables)["message_name"] = descriptor->containing_type()->name();
67}
68
69}  // namespace
70
71// ===================================================================
72
73EnumFieldGenerator::
74EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
75  : FieldGenerator(params), descriptor_(descriptor) {
76  SetEnumVariables(params, descriptor, &variables_);
77}
78
79EnumFieldGenerator::~EnumFieldGenerator() {}
80
81void EnumFieldGenerator::
82GenerateMembers(io::Printer* printer) const {
83  printer->Print(variables_,
84    "public int $name$ = $default$;\n");
85}
86
87void EnumFieldGenerator::
88GenerateParsingCode(io::Printer* printer) const {
89  printer->Print(variables_,
90    "  this.$name$ = input.readInt32();\n");
91}
92
93void EnumFieldGenerator::
94GenerateSerializationCode(io::Printer* printer) const {
95  if (descriptor_->is_required()) {
96    printer->Print(variables_,
97      "output.writeInt32($number$, this.$name$);\n");
98  } else {
99    printer->Print(variables_,
100      "if (this.$name$ != $default$) {\n"
101      "  output.writeInt32($number$, this.$name$);\n"
102      "}\n");
103  }
104}
105
106void EnumFieldGenerator::
107GenerateSerializedSizeCode(io::Printer* printer) const {
108  if (descriptor_->is_required()) {
109    printer->Print(variables_,
110      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
111      "  .computeInt32Size($number$, this.$name$);\n");
112  } else {
113    printer->Print(variables_,
114      "if (this.$name$ != $default$) {\n"
115      "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
116      "    .computeInt32Size($number$, this.$name$);\n"
117      "}\n");
118  }
119}
120
121string EnumFieldGenerator::GetBoxedType() const {
122  return ClassName(params_, descriptor_->enum_type());
123}
124
125// ===================================================================
126
127RepeatedEnumFieldGenerator::
128RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
129  : FieldGenerator(params), descriptor_(descriptor) {
130  SetEnumVariables(params, descriptor, &variables_);
131}
132
133RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
134
135void RepeatedEnumFieldGenerator::
136GenerateMembers(io::Printer* printer) const {
137  printer->Print(variables_,
138    "public int[] $name$ = com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY;\n");
139  if (descriptor_->options().packed()) {
140    printer->Print(variables_,
141      "private int $name$MemoizedSerializedSize;\n");
142  }
143}
144
145void RepeatedEnumFieldGenerator::
146GenerateParsingCode(io::Printer* printer) const {
147  // First, figure out the length of the array, then parse.
148  if (descriptor_->options().packed()) {
149    printer->Print(variables_,
150      "int length = input.readRawVarint32();\n"
151      "int limit = input.pushLimit(length);\n"
152      "// First pass to compute array length.\n"
153      "int arrayLength = 0;\n"
154      "int startPos = input.getPosition();\n"
155      "while (input.getBytesUntilLimit() > 0) {\n"
156      "  input.readInt32();\n"
157      "  arrayLength++;\n"
158      "}\n"
159      "input.rewindToPosition(startPos);\n"
160      "this.$name$ = new $type$[arrayLength];\n"
161      "for (int i = 0; i < arrayLength; i++) {\n"
162      "  this.$name$[i] = input.readInt32();\n"
163      "}\n"
164      "input.popLimit(limit);\n");
165  } else {
166    printer->Print(variables_,
167      "int arrayLength = com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, $tag$);\n"
168      "int i = this.$name$.length;\n"
169      "int[] newArray = new int[i + arrayLength];\n"
170      "System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
171      "this.$name$ = newArray;\n"
172      "for (; i < this.$name$.length - 1; i++) {\n"
173      "  this.$name$[i] = input.readInt32();\n"
174      "  input.readTag();\n"
175      "}\n"
176      "// Last one without readTag.\n"
177      "this.$name$[i] = input.readInt32();\n");
178  }
179}
180
181void RepeatedEnumFieldGenerator::
182GenerateSerializationCode(io::Printer* printer) const {
183  printer->Print(variables_,
184    "if (this.$name$.length > 0) {\n");
185  printer->Indent();
186
187  if (descriptor_->options().packed()) {
188    printer->Print(variables_,
189      "output.writeRawVarint32($tag$);\n"
190      "output.writeRawVarint32($name$MemoizedSerializedSize);\n"
191      "for (int element : this.$name$) {\n"
192      "  output.writeRawVarint32(element);\n"
193      "}\n");
194  } else {
195    printer->Print(variables_,
196      "for (int element : this.$name$) {\n"
197      "  output.writeInt32($number$, element);\n"
198      "}\n");
199  }
200  printer->Outdent();
201  printer->Print(variables_,
202    "}\n");
203}
204
205void RepeatedEnumFieldGenerator::
206GenerateSerializedSizeCode(io::Printer* printer) const {
207  printer->Print(variables_,
208    "if (this.$name$.length > 0) {\n");
209  printer->Indent();
210
211  printer->Print(variables_,
212    "int dataSize = 0;\n"
213    "for (int element : this.$name$) {\n"
214    "  dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
215    "    .computeInt32SizeNoTag(element);\n"
216    "}\n");
217
218  printer->Print(
219    "size += dataSize;\n");
220  if (descriptor_->options().packed()) {
221    // cache the data size for packed fields.
222    printer->Print(variables_,
223      "size += $tag_size$;\n"
224      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
225      "  .computeRawVarint32Size(dataSize);\n"
226      "$name$MemoizedSerializedSize = dataSize;\n");
227  } else {
228    printer->Print(variables_,
229        "size += $tag_size$ * this.$name$.length;\n");
230  }
231
232  printer->Outdent();
233
234  // set cached size to 0 for empty packed fields.
235  if (descriptor_->options().packed()) {
236    printer->Print(variables_,
237      "} else {\n"
238      "  $name$MemoizedSerializedSize = 0;\n"
239      "}\n");
240  } else {
241    printer->Print(
242      "}\n");
243  }
244}
245
246string RepeatedEnumFieldGenerator::GetBoxedType() const {
247  return ClassName(params_, descriptor_->enum_type());
248}
249
250}  // namespace javanano
251}  // namespace compiler
252}  // namespace protobuf
253}  // namespace google
254