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