javanano_enum_field.cc revision 286271f75aa6ff1f3746379b77d6dc55415baa16
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      "int i = this.$name$ == null ? 0 : this.$name$.length;\n"
273      "int[] newArray = new int[i + arrayLength];\n"
274      "if (i != 0) {\n"
275      "  java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
276      "}\n"
277      "for (; i < newArray.length; i++) {\n"
278      "  newArray[i] = input.readInt32();\n"
279      "}\n"
280      "this.$name$ = newArray;\n"
281      "input.popLimit(limit);\n");
282  } else {
283    printer->Print(variables_,
284      "int arrayLength = com.google.protobuf.nano.WireFormatNano\n"
285      "    .getRepeatedFieldArrayLength(input, $tag$);\n"
286      "int i = this.$name$ == null ? 0 : this.$name$.length;\n"
287      "int[] newArray = new int[i + arrayLength];\n"
288      "if (i != 0) {\n"
289      "  java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
290      "}\n"
291      "for (; i < newArray.length - 1; i++) {\n"
292      "  newArray[i] = input.readInt32();\n"
293      "  input.readTag();\n"
294      "}\n"
295      "// Last one without readTag.\n"
296      "newArray[i] = input.readInt32();\n"
297      "this.$name$ = newArray;\n");
298  }
299}
300
301void RepeatedEnumFieldGenerator::
302GenerateSerializationCode(io::Printer* printer) const {
303  printer->Print(variables_,
304    "if (this.$name$ != null && this.$name$.length > 0) {\n");
305  printer->Indent();
306
307  if (descriptor_->options().packed()) {
308    printer->Print(variables_,
309      "output.writeRawVarint32($tag$);\n"
310      "output.writeRawVarint32($name$MemoizedSerializedSize);\n"
311      "for (int element : this.$name$) {\n"
312      "  output.writeRawVarint32(element);\n"
313      "}\n");
314  } else {
315    printer->Print(variables_,
316      "for (int element : this.$name$) {\n"
317      "  output.writeInt32($number$, element);\n"
318      "}\n");
319  }
320  printer->Outdent();
321  printer->Print(variables_,
322    "}\n");
323}
324
325void RepeatedEnumFieldGenerator::
326GenerateSerializedSizeCode(io::Printer* printer) const {
327  printer->Print(variables_,
328    "if (this.$name$ != null && this.$name$.length > 0) {\n");
329  printer->Indent();
330
331  printer->Print(variables_,
332    "int dataSize = 0;\n"
333    "for (int element : this.$name$) {\n"
334    "  dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
335    "    .computeInt32SizeNoTag(element);\n"
336    "}\n");
337
338  printer->Print(
339    "size += dataSize;\n");
340  if (descriptor_->options().packed()) {
341    // cache the data size for packed fields.
342    printer->Print(variables_,
343      "size += $tag_size$;\n"
344      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
345      "  .computeRawVarint32Size(dataSize);\n"
346      "$name$MemoizedSerializedSize = dataSize;\n");
347  } else {
348    printer->Print(variables_,
349        "size += $tag_size$ * this.$name$.length;\n");
350  }
351
352  printer->Outdent();
353
354  // set cached size to 0 for empty packed fields.
355  if (descriptor_->options().packed()) {
356    printer->Print(variables_,
357      "} else {\n"
358      "  $name$MemoizedSerializedSize = 0;\n"
359      "}\n");
360  } else {
361    printer->Print(
362      "}\n");
363  }
364}
365
366string RepeatedEnumFieldGenerator::GetBoxedType() const {
367  return ClassName(params_, descriptor_->enum_type());
368}
369
370}  // namespace javanano
371}  // namespace compiler
372}  // namespace protobuf
373}  // namespace google
374