javanano_enum_field.cc revision ccc48faf20dbf3b3cddcffe78d198876d543529b
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 162void EnumFieldGenerator::GenerateEqualsCode(io::Printer* printer) const { 163 if (params_.use_reference_types_for_primitives()) { 164 printer->Print(variables_, 165 "if (this.$name$ == null) {\n" 166 " if (other.$name$ != null) {\n" 167 " return false;\n" 168 " }\n" 169 "} else if (!this.$name$.equals(other.$name$)) {\n" 170 " return false;" 171 "}\n"); 172 } else { 173 // We define equality as serialized form equality. If generate_has(), 174 // then if the field value equals the default value in both messages, 175 // but one's 'has' field is set and the other's is not, the serialized 176 // forms are different and we should return false. 177 printer->Print(variables_, 178 "if (this.$name$ != other.$name$"); 179 if (params_.generate_has()) { 180 printer->Print(variables_, 181 "\n" 182 " || (this.$name$ == $default$\n" 183 " && this.has$capitalized_name$ != other.has$capitalized_name$)"); 184 } 185 printer->Print(") {\n" 186 " return false;\n" 187 "}\n"); 188 } 189} 190 191void EnumFieldGenerator::GenerateHashCodeCode(io::Printer* printer) const { 192 printer->Print( 193 "result = 31 * result + "); 194 if (params_.use_reference_types_for_primitives()) { 195 printer->Print(variables_, 196 "(this.$name$ == null ? 0 : this.$name$)"); 197 } else { 198 printer->Print(variables_, 199 "this.$name$"); 200 } 201 printer->Print(";\n"); 202} 203 204// =================================================================== 205 206AccessorEnumFieldGenerator:: 207AccessorEnumFieldGenerator(const FieldDescriptor* descriptor, 208 const Params& params, int has_bit_index) 209 : FieldGenerator(params), descriptor_(descriptor) { 210 SetEnumVariables(params, descriptor, &variables_); 211 SetBitOperationVariables("has", has_bit_index, &variables_); 212} 213 214AccessorEnumFieldGenerator::~AccessorEnumFieldGenerator() {} 215 216void AccessorEnumFieldGenerator:: 217GenerateMembers(io::Printer* printer) const { 218 printer->Print(variables_, 219 "private int $name$_;\n" 220 "public int get$capitalized_name$() {\n" 221 " return $name$_;\n" 222 "}\n" 223 "public $message_name$ set$capitalized_name$(int value) {\n" 224 " $name$_ = value;\n" 225 " $set_has$;\n" 226 " return this;\n" 227 "}\n" 228 "public boolean has$capitalized_name$() {\n" 229 " return $get_has$;\n" 230 "}\n" 231 "public $message_name$ clear$capitalized_name$() {\n" 232 " $name$_ = $default$;\n" 233 " $clear_has$;\n" 234 " return this;\n" 235 "}\n"); 236} 237 238void AccessorEnumFieldGenerator:: 239GenerateClearCode(io::Printer* printer) const { 240 printer->Print(variables_, 241 "$name$_ = $default$;\n"); 242} 243 244void AccessorEnumFieldGenerator:: 245GenerateMergingCode(io::Printer* printer) const { 246 printer->Print(variables_, 247 "$name$_ = input.readInt32();\n" 248 "$set_has$;\n"); 249} 250 251void AccessorEnumFieldGenerator:: 252GenerateSerializationCode(io::Printer* printer) const { 253 printer->Print(variables_, 254 "if ($get_has$) {\n" 255 " output.writeInt32($number$, $name$_);\n" 256 "}\n"); 257} 258 259void AccessorEnumFieldGenerator:: 260GenerateSerializedSizeCode(io::Printer* printer) const { 261 printer->Print(variables_, 262 "if ($get_has$) {\n" 263 " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 264 " .computeInt32Size($number$, $name$_);\n" 265 "}\n"); 266} 267 268void AccessorEnumFieldGenerator:: 269GenerateEqualsCode(io::Printer* printer) const { 270 printer->Print(variables_, 271 "if ($different_has$\n" 272 " || $name$_ != other.$name$_) {\n" 273 " return false;\n" 274 "}\n"); 275} 276 277void AccessorEnumFieldGenerator:: 278GenerateHashCodeCode(io::Printer* printer) const { 279 printer->Print(variables_, 280 "result = 31 * result + $name$_;\n"); 281} 282 283// =================================================================== 284 285RepeatedEnumFieldGenerator:: 286RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params) 287 : FieldGenerator(params), descriptor_(descriptor) { 288 SetEnumVariables(params, descriptor, &variables_); 289} 290 291RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} 292 293void RepeatedEnumFieldGenerator:: 294GenerateMembers(io::Printer* printer) const { 295 printer->Print(variables_, 296 "public $type$[] $name$;\n"); 297 if (descriptor_->options().packed()) { 298 printer->Print(variables_, 299 "private int $name$MemoizedSerializedSize;\n"); 300 } 301} 302 303void RepeatedEnumFieldGenerator:: 304GenerateClearCode(io::Printer* printer) const { 305 printer->Print(variables_, 306 "$name$ = $repeated_default$;\n"); 307} 308 309void RepeatedEnumFieldGenerator:: 310GenerateMergingCode(io::Printer* printer) const { 311 // First, figure out the length of the array, then parse. 312 if (descriptor_->options().packed()) { 313 printer->Print(variables_, 314 "int length = input.readRawVarint32();\n" 315 "int limit = input.pushLimit(length);\n" 316 "// First pass to compute array length.\n" 317 "int arrayLength = 0;\n" 318 "int startPos = input.getPosition();\n" 319 "while (input.getBytesUntilLimit() > 0) {\n" 320 " input.readInt32();\n" 321 " arrayLength++;\n" 322 "}\n" 323 "input.rewindToPosition(startPos);\n" 324 "int i = this.$name$ == null ? 0 : this.$name$.length;\n" 325 "int[] newArray = new int[i + arrayLength];\n" 326 "if (i != 0) {\n" 327 " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n" 328 "}\n" 329 "for (; i < newArray.length; i++) {\n" 330 " newArray[i] = input.readInt32();\n" 331 "}\n" 332 "this.$name$ = newArray;\n" 333 "input.popLimit(limit);\n"); 334 } else { 335 printer->Print(variables_, 336 "int arrayLength = com.google.protobuf.nano.WireFormatNano\n" 337 " .getRepeatedFieldArrayLength(input, $tag$);\n" 338 "int i = this.$name$ == null ? 0 : this.$name$.length;\n" 339 "int[] newArray = new int[i + arrayLength];\n" 340 "if (i != 0) {\n" 341 " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n" 342 "}\n" 343 "for (; i < newArray.length - 1; i++) {\n" 344 " newArray[i] = input.readInt32();\n" 345 " input.readTag();\n" 346 "}\n" 347 "// Last one without readTag.\n" 348 "newArray[i] = input.readInt32();\n" 349 "this.$name$ = newArray;\n"); 350 } 351} 352 353void RepeatedEnumFieldGenerator:: 354GenerateSerializationCode(io::Printer* printer) const { 355 printer->Print(variables_, 356 "if (this.$name$ != null && this.$name$.length > 0) {\n"); 357 printer->Indent(); 358 359 if (descriptor_->options().packed()) { 360 printer->Print(variables_, 361 "output.writeRawVarint32($tag$);\n" 362 "output.writeRawVarint32($name$MemoizedSerializedSize);\n" 363 "for (int element : this.$name$) {\n" 364 " output.writeRawVarint32(element);\n" 365 "}\n"); 366 } else { 367 printer->Print(variables_, 368 "for (int element : this.$name$) {\n" 369 " output.writeInt32($number$, element);\n" 370 "}\n"); 371 } 372 printer->Outdent(); 373 printer->Print(variables_, 374 "}\n"); 375} 376 377void RepeatedEnumFieldGenerator:: 378GenerateSerializedSizeCode(io::Printer* printer) const { 379 printer->Print(variables_, 380 "if (this.$name$ != null && this.$name$.length > 0) {\n"); 381 printer->Indent(); 382 383 printer->Print(variables_, 384 "int dataSize = 0;\n" 385 "for (int element : this.$name$) {\n" 386 " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 387 " .computeInt32SizeNoTag(element);\n" 388 "}\n"); 389 390 printer->Print( 391 "size += dataSize;\n"); 392 if (descriptor_->options().packed()) { 393 // cache the data size for packed fields. 394 printer->Print(variables_, 395 "size += $tag_size$;\n" 396 "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 397 " .computeRawVarint32Size(dataSize);\n" 398 "$name$MemoizedSerializedSize = dataSize;\n"); 399 } else { 400 printer->Print(variables_, 401 "size += $tag_size$ * this.$name$.length;\n"); 402 } 403 404 printer->Outdent(); 405 406 // set cached size to 0 for empty packed fields. 407 if (descriptor_->options().packed()) { 408 printer->Print(variables_, 409 "} else {\n" 410 " $name$MemoizedSerializedSize = 0;\n" 411 "}\n"); 412 } else { 413 printer->Print( 414 "}\n"); 415 } 416} 417 418void RepeatedEnumFieldGenerator:: 419GenerateEqualsCode(io::Printer* printer) const { 420 printer->Print(variables_, 421 "if (!com.google.protobuf.nano.InternalNano.equals(\n" 422 " this.$name$, other.$name$)) {\n" 423 " return false;\n" 424 "}\n"); 425} 426 427void RepeatedEnumFieldGenerator:: 428GenerateHashCodeCode(io::Printer* printer) const { 429 printer->Print(variables_, 430 "result = 31 * result\n" 431 " + com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n"); 432} 433 434} // namespace javanano 435} // namespace compiler 436} // namespace protobuf 437} // namespace google 438