javanano_enum_field.cc revision 0f1c4eb967517e21701a3b425d115baff5d15b4f
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    UnderscoresToCamelCase(descriptor);
58  (*variables)["capitalized_name"] =
59    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      "this.$name$ = java.util.Arrays.copyOf(this.$name$, this.$name$.length + arrayLength);\n"
170      "for (; i < this.$name$.length - 1; i++) {\n"
171      "  this.$name$[i] = input.readInt32();\n"
172      "  input.readTag();\n"
173      "}\n"
174      "// Last one without readTag.\n"
175      "this.$name$[i] = input.readInt32();\n");
176  }
177}
178
179void RepeatedEnumFieldGenerator::
180GenerateSerializationCode(io::Printer* printer) const {
181  printer->Print(variables_,
182    "if (this.$name$.length > 0) {\n");
183  printer->Indent();
184
185  if (descriptor_->options().packed()) {
186    printer->Print(variables_,
187      "output.writeRawVarint32($tag$);\n"
188      "output.writeRawVarint32($name$MemoizedSerializedSize);\n"
189      "for (int element : this.$name$) {\n"
190      "  output.writeRawVarint32(element);\n"
191      "}\n");
192  } else {
193    printer->Print(variables_,
194      "for (int element : this.$name$) {\n"
195      "  output.writeInt32($number$, element);\n"
196      "}\n");
197  }
198  printer->Outdent();
199  printer->Print(variables_,
200    "}\n");
201}
202
203void RepeatedEnumFieldGenerator::
204GenerateSerializedSizeCode(io::Printer* printer) const {
205  printer->Print(variables_,
206    "if (this.$name$.length > 0) {\n");
207  printer->Indent();
208
209  printer->Print(variables_,
210    "int dataSize = 0;\n"
211    "for (int element : this.$name$) {\n"
212    "  dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
213    "    .computeInt32SizeNoTag(element);\n"
214    "}\n");
215
216  printer->Print(
217    "size += dataSize;\n");
218  if (descriptor_->options().packed()) {
219    // cache the data size for packed fields.
220    printer->Print(variables_,
221      "size += $tag_size$;\n"
222      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
223      "  .computeRawVarint32Size(dataSize);\n"
224      "$name$MemoizedSerializedSize = dataSize;\n");
225  } else {
226    printer->Print(variables_,
227        "size += $tag_size$ * this.$name$.length;\n");
228  }
229
230  printer->Outdent();
231
232  // set cached size to 0 for empty packed fields.
233  if (descriptor_->options().packed()) {
234    printer->Print(variables_,
235      "} else {\n"
236      "  $name$MemoizedSerializedSize = 0;\n"
237      "}\n");
238  } else {
239    printer->Print(
240      "}\n");
241  }
242}
243
244string RepeatedEnumFieldGenerator::GetBoxedType() const {
245  return ClassName(params_, descriptor_->enum_type());
246}
247
248}  // namespace javanano
249}  // namespace compiler
250}  // namespace protobuf
251}  // namespace google
252