javanano_enum_field.cc revision e74fe623e115237968a3de1143d7cdb4df710858
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  if (params_.generate_has()) {
87    printer->Print(variables_,
88      "public boolean has$capitalized_name$ = false;\n");
89  }
90}
91
92void EnumFieldGenerator::
93GenerateClearCode(io::Printer* printer) const {
94  printer->Print(variables_,
95    "$name$ = $default$;\n");
96
97  if (params_.generate_has()) {
98    printer->Print(variables_,
99      "has$capitalized_name$ = false;\n");
100  }
101}
102
103void EnumFieldGenerator::
104GenerateMergingCode(io::Printer* printer) const {
105  printer->Print(variables_,
106    "  this.$name$ = input.readInt32();\n");
107
108  if (params_.generate_has()) {
109    printer->Print(variables_,
110      "  has$capitalized_name$ = true;\n");
111  }
112}
113
114void EnumFieldGenerator::
115GenerateSerializationCode(io::Printer* printer) const {
116  if (descriptor_->is_required()) {
117    printer->Print(variables_,
118      "output.writeInt32($number$, this.$name$);\n");
119  } else {
120    if (params_.generate_has()) {
121      printer->Print(variables_,
122        "if (this.$name$ != $default$ || has$capitalized_name$) {\n");
123    } else {
124      printer->Print(variables_,
125        "if (this.$name$ != $default$) {\n");
126    }
127    printer->Print(variables_,
128      "  output.writeInt32($number$, this.$name$);\n"
129      "}\n");
130  }
131}
132
133void EnumFieldGenerator::
134GenerateSerializedSizeCode(io::Printer* printer) const {
135  if (descriptor_->is_required()) {
136    printer->Print(variables_,
137      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
138      "  .computeInt32Size($number$, this.$name$);\n");
139  } else {
140    if (params_.generate_has()) {
141      printer->Print(variables_,
142        "if (this.$name$ != $default$ || has$capitalized_name$) {\n");
143    } else {
144      printer->Print(variables_,
145        "if (this.$name$ != $default$) {\n");
146    }
147    printer->Print(variables_,
148      "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
149      "    .computeInt32Size($number$, this.$name$);\n"
150      "}\n");
151  }
152}
153
154string EnumFieldGenerator::GetBoxedType() const {
155  return ClassName(params_, descriptor_->enum_type());
156}
157
158// ===================================================================
159
160AccessorEnumFieldGenerator::
161AccessorEnumFieldGenerator(const FieldDescriptor* descriptor,
162    const Params& params, int has_bit_index)
163  : FieldGenerator(params), descriptor_(descriptor) {
164  SetEnumVariables(params, descriptor, &variables_);
165  SetBitOperationVariables("has", has_bit_index, &variables_);
166}
167
168AccessorEnumFieldGenerator::~AccessorEnumFieldGenerator() {}
169
170void AccessorEnumFieldGenerator::
171GenerateMembers(io::Printer* printer) const {
172  printer->Print(variables_,
173    "private int $name$_ = $default$;\n"
174    "public int get$capitalized_name$() {\n"
175    "  return $name$_;\n"
176    "}\n"
177    "public void set$capitalized_name$(int value) {\n"
178    "  $name$_ = value;\n"
179    "  $set_has$;\n"
180    "}\n"
181    "public boolean has$capitalized_name$() {\n"
182    "  return $get_has$;\n"
183    "}\n"
184    "public void clear$capitalized_name$() {\n"
185    "  $name$_ = $default$;\n"
186    "  $clear_has$;\n"
187    "}\n");
188}
189
190void AccessorEnumFieldGenerator::
191GenerateClearCode(io::Printer* printer) const {
192  printer->Print(variables_,
193    "$name$_ = $default$;\n");
194}
195
196void AccessorEnumFieldGenerator::
197GenerateMergingCode(io::Printer* printer) const {
198  printer->Print(variables_,
199    "set$capitalized_name$(input.readInt32());\n");
200}
201
202void AccessorEnumFieldGenerator::
203GenerateSerializationCode(io::Printer* printer) const {
204  printer->Print(variables_,
205    "if (has$capitalized_name$()) {\n"
206    "  output.writeInt32($number$, $name$_);\n"
207    "}\n");
208}
209
210void AccessorEnumFieldGenerator::
211GenerateSerializedSizeCode(io::Printer* printer) const {
212  printer->Print(variables_,
213    "if (has$capitalized_name$()) {\n"
214    "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
215    "    .computeInt32Size($number$, $name$_);\n"
216    "}\n");
217}
218
219string AccessorEnumFieldGenerator::GetBoxedType() const {
220  return ClassName(params_, descriptor_->enum_type());
221}
222
223// ===================================================================
224
225RepeatedEnumFieldGenerator::
226RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
227  : FieldGenerator(params), descriptor_(descriptor) {
228  SetEnumVariables(params, descriptor, &variables_);
229}
230
231RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
232
233void RepeatedEnumFieldGenerator::
234GenerateMembers(io::Printer* printer) const {
235  printer->Print(variables_,
236    "public int[] $name$ = com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY;\n");
237  if (descriptor_->options().packed()) {
238    printer->Print(variables_,
239      "private int $name$MemoizedSerializedSize;\n");
240  }
241}
242
243void RepeatedEnumFieldGenerator::
244GenerateClearCode(io::Printer* printer) const {
245  printer->Print(variables_,
246    "$name$ = com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY;\n");
247}
248
249void RepeatedEnumFieldGenerator::
250GenerateMergingCode(io::Printer* printer) const {
251  // First, figure out the length of the array, then parse.
252  if (descriptor_->options().packed()) {
253    printer->Print(variables_,
254      "int length = input.readRawVarint32();\n"
255      "int limit = input.pushLimit(length);\n"
256      "// First pass to compute array length.\n"
257      "int arrayLength = 0;\n"
258      "int startPos = input.getPosition();\n"
259      "while (input.getBytesUntilLimit() > 0) {\n"
260      "  input.readInt32();\n"
261      "  arrayLength++;\n"
262      "}\n"
263      "input.rewindToPosition(startPos);\n"
264      "this.$name$ = new $type$[arrayLength];\n"
265      "for (int i = 0; i < arrayLength; i++) {\n"
266      "  this.$name$[i] = input.readInt32();\n"
267      "}\n"
268      "input.popLimit(limit);\n");
269  } else {
270    printer->Print(variables_,
271      "int arrayLength = com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, $tag$);\n"
272      "int i = this.$name$.length;\n"
273      "int[] newArray = new int[i + arrayLength];\n"
274      "System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
275      "this.$name$ = newArray;\n"
276      "for (; i < this.$name$.length - 1; i++) {\n"
277      "  this.$name$[i] = input.readInt32();\n"
278      "  input.readTag();\n"
279      "}\n"
280      "// Last one without readTag.\n"
281      "this.$name$[i] = input.readInt32();\n");
282  }
283}
284
285void RepeatedEnumFieldGenerator::
286GenerateSerializationCode(io::Printer* printer) const {
287  printer->Print(variables_,
288    "if (this.$name$.length > 0) {\n");
289  printer->Indent();
290
291  if (descriptor_->options().packed()) {
292    printer->Print(variables_,
293      "output.writeRawVarint32($tag$);\n"
294      "output.writeRawVarint32($name$MemoizedSerializedSize);\n"
295      "for (int element : this.$name$) {\n"
296      "  output.writeRawVarint32(element);\n"
297      "}\n");
298  } else {
299    printer->Print(variables_,
300      "for (int element : this.$name$) {\n"
301      "  output.writeInt32($number$, element);\n"
302      "}\n");
303  }
304  printer->Outdent();
305  printer->Print(variables_,
306    "}\n");
307}
308
309void RepeatedEnumFieldGenerator::
310GenerateSerializedSizeCode(io::Printer* printer) const {
311  printer->Print(variables_,
312    "if (this.$name$.length > 0) {\n");
313  printer->Indent();
314
315  printer->Print(variables_,
316    "int dataSize = 0;\n"
317    "for (int element : this.$name$) {\n"
318    "  dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
319    "    .computeInt32SizeNoTag(element);\n"
320    "}\n");
321
322  printer->Print(
323    "size += dataSize;\n");
324  if (descriptor_->options().packed()) {
325    // cache the data size for packed fields.
326    printer->Print(variables_,
327      "size += $tag_size$;\n"
328      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
329      "  .computeRawVarint32Size(dataSize);\n"
330      "$name$MemoizedSerializedSize = dataSize;\n");
331  } else {
332    printer->Print(variables_,
333        "size += $tag_size$ * this.$name$.length;\n");
334  }
335
336  printer->Outdent();
337
338  // set cached size to 0 for empty packed fields.
339  if (descriptor_->options().packed()) {
340    printer->Print(variables_,
341      "} else {\n"
342      "  $name$MemoizedSerializedSize = 0;\n"
343      "}\n");
344  } else {
345    printer->Print(
346      "}\n");
347  }
348}
349
350string RepeatedEnumFieldGenerator::GetBoxedType() const {
351  return ClassName(params_, descriptor_->enum_type());
352}
353
354}  // namespace javanano
355}  // namespace compiler
356}  // namespace protobuf
357}  // namespace google
358