javanano_primitive_field.cc revision 710ca66fdd31db8f3920b122292bdc3250d5aada
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_primitive_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#include <google/protobuf/stubs/substitute.h> 45 46namespace google { 47namespace protobuf { 48namespace compiler { 49namespace javanano { 50 51using internal::WireFormat; 52using internal::WireFormatLite; 53 54namespace { 55 56const char* PrimitiveTypeName(JavaType type) { 57 switch (type) { 58 case JAVATYPE_INT : return "int"; 59 case JAVATYPE_LONG : return "long"; 60 case JAVATYPE_FLOAT : return "float"; 61 case JAVATYPE_DOUBLE : return "double"; 62 case JAVATYPE_BOOLEAN: return "boolean"; 63 case JAVATYPE_STRING : return "java.lang.String"; 64 case JAVATYPE_BYTES : return "byte[]"; 65 case JAVATYPE_ENUM : return NULL; 66 case JAVATYPE_MESSAGE: return NULL; 67 68 // No default because we want the compiler to complain if any new 69 // JavaTypes are added. 70 } 71 72 GOOGLE_LOG(FATAL) << "Can't get here."; 73 return NULL; 74} 75 76bool IsReferenceType(JavaType type) { 77 switch (type) { 78 case JAVATYPE_INT : return false; 79 case JAVATYPE_LONG : return false; 80 case JAVATYPE_FLOAT : return false; 81 case JAVATYPE_DOUBLE : return false; 82 case JAVATYPE_BOOLEAN: return false; 83 case JAVATYPE_STRING : return true; 84 case JAVATYPE_BYTES : return true; 85 case JAVATYPE_ENUM : return false; 86 case JAVATYPE_MESSAGE: return true; 87 88 // No default because we want the compiler to complain if any new 89 // JavaTypes are added. 90 } 91 92 GOOGLE_LOG(FATAL) << "Can't get here."; 93 return false; 94} 95 96bool IsArrayType(JavaType type) { 97 switch (type) { 98 case JAVATYPE_INT : return false; 99 case JAVATYPE_LONG : return false; 100 case JAVATYPE_FLOAT : return false; 101 case JAVATYPE_DOUBLE : return false; 102 case JAVATYPE_BOOLEAN: return false; 103 case JAVATYPE_STRING : return false; 104 case JAVATYPE_BYTES : return true; 105 case JAVATYPE_ENUM : return false; 106 case JAVATYPE_MESSAGE: return false; 107 108 // No default because we want the compiler to complain if any new 109 // JavaTypes are added. 110 } 111 112 GOOGLE_LOG(FATAL) << "Can't get here."; 113 return false; 114} 115 116const char* GetCapitalizedType(const FieldDescriptor* field) { 117 switch (field->type()) { 118 case FieldDescriptor::TYPE_INT32 : return "Int32" ; 119 case FieldDescriptor::TYPE_UINT32 : return "UInt32" ; 120 case FieldDescriptor::TYPE_SINT32 : return "SInt32" ; 121 case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ; 122 case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; 123 case FieldDescriptor::TYPE_INT64 : return "Int64" ; 124 case FieldDescriptor::TYPE_UINT64 : return "UInt64" ; 125 case FieldDescriptor::TYPE_SINT64 : return "SInt64" ; 126 case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ; 127 case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; 128 case FieldDescriptor::TYPE_FLOAT : return "Float" ; 129 case FieldDescriptor::TYPE_DOUBLE : return "Double" ; 130 case FieldDescriptor::TYPE_BOOL : return "Bool" ; 131 case FieldDescriptor::TYPE_STRING : return "String" ; 132 case FieldDescriptor::TYPE_BYTES : return "Bytes" ; 133 case FieldDescriptor::TYPE_ENUM : return "Enum" ; 134 case FieldDescriptor::TYPE_GROUP : return "Group" ; 135 case FieldDescriptor::TYPE_MESSAGE : return "Message" ; 136 137 // No default because we want the compiler to complain if any new 138 // types are added. 139 } 140 141 GOOGLE_LOG(FATAL) << "Can't get here."; 142 return NULL; 143} 144 145// For encodings with fixed sizes, returns that size in bytes. Otherwise 146// returns -1. 147int FixedSize(FieldDescriptor::Type type) { 148 switch (type) { 149 case FieldDescriptor::TYPE_INT32 : return -1; 150 case FieldDescriptor::TYPE_INT64 : return -1; 151 case FieldDescriptor::TYPE_UINT32 : return -1; 152 case FieldDescriptor::TYPE_UINT64 : return -1; 153 case FieldDescriptor::TYPE_SINT32 : return -1; 154 case FieldDescriptor::TYPE_SINT64 : return -1; 155 case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; 156 case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; 157 case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; 158 case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; 159 case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; 160 case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; 161 162 case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; 163 case FieldDescriptor::TYPE_ENUM : return -1; 164 165 case FieldDescriptor::TYPE_STRING : return -1; 166 case FieldDescriptor::TYPE_BYTES : return -1; 167 case FieldDescriptor::TYPE_GROUP : return -1; 168 case FieldDescriptor::TYPE_MESSAGE : return -1; 169 170 // No default because we want the compiler to complain if any new 171 // types are added. 172 } 173 GOOGLE_LOG(FATAL) << "Can't get here."; 174 return -1; 175} 176 177// Return true if the type is a that has variable length 178// for instance String's. 179bool IsVariableLenType(JavaType type) { 180 switch (type) { 181 case JAVATYPE_INT : return false; 182 case JAVATYPE_LONG : return false; 183 case JAVATYPE_FLOAT : return false; 184 case JAVATYPE_DOUBLE : return false; 185 case JAVATYPE_BOOLEAN: return false; 186 case JAVATYPE_STRING : return true; 187 case JAVATYPE_BYTES : return true; 188 case JAVATYPE_ENUM : return false; 189 case JAVATYPE_MESSAGE: return true; 190 191 // No default because we want the compiler to complain if any new 192 // JavaTypes are added. 193 } 194 195 GOOGLE_LOG(FATAL) << "Can't get here."; 196 return false; 197} 198 199bool AllAscii(const string& text) { 200 for (int i = 0; i < text.size(); i++) { 201 if ((text[i] & 0x80) != 0) { 202 return false; 203 } 204 } 205 return true; 206} 207 208void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params params, 209 map<string, string>* variables) { 210 (*variables)["name"] = 211 UnderscoresToCamelCase(descriptor); 212 (*variables)["capitalized_name"] = 213 UnderscoresToCapitalizedCamelCase(descriptor); 214 (*variables)["number"] = SimpleItoa(descriptor->number()); 215 (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor)); 216 (*variables)["default"] = DefaultValue(params, descriptor); 217 (*variables)["default_constant"] = FieldDefaultConstantName(descriptor); 218 // For C++-string types (string and bytes), we might need to have 219 // the generated code do the unicode decoding (see comments in 220 // InternalNano.java for gory details.). We would like to do this 221 // once into a "private static final" field and re-use that from 222 // then on. 223 if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING && 224 !descriptor->default_value_string().empty()) { 225 string default_value; 226 if (descriptor->type() == FieldDescriptor::TYPE_BYTES) { 227 default_value = strings::Substitute( 228 "com.google.protobuf.nano.InternalNano.bytesDefaultValue(\"$0\")", 229 CEscape(descriptor->default_value_string())); 230 } else { 231 if (AllAscii(descriptor->default_value_string())) { 232 // All chars are ASCII. In this case CEscape() works fine. 233 default_value = "\"" + CEscape(descriptor->default_value_string()) + "\""; 234 } else { 235 default_value = strings::Substitute( 236 "com.google.protobuf.nano.InternalNano.stringDefaultValue(\"$0\")", 237 CEscape(descriptor->default_value_string())); 238 } 239 } 240 (*variables)["default_constant_value"] = default_value; 241 } 242 (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor)); 243 (*variables)["capitalized_type"] = GetCapitalizedType(descriptor); 244 (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); 245 (*variables)["tag_size"] = SimpleItoa( 246 WireFormat::TagSize(descriptor->number(), descriptor->type())); 247 if (IsReferenceType(GetJavaType(descriptor))) { 248 (*variables)["null_check"] = 249 " if (value == null) {\n" 250 " throw new NullPointerException();\n" 251 " }\n"; 252 } else { 253 (*variables)["null_check"] = ""; 254 } 255 int fixed_size = FixedSize(descriptor->type()); 256 if (fixed_size != -1) { 257 (*variables)["fixed_size"] = SimpleItoa(fixed_size); 258 } 259 (*variables)["message_name"] = descriptor->containing_type()->name(); 260 (*variables)["empty_array_name"] = EmptyArrayName(params, descriptor); 261} 262} // namespace 263 264// =================================================================== 265 266PrimitiveFieldGenerator:: 267PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params) 268 : FieldGenerator(params), descriptor_(descriptor) { 269 SetPrimitiveVariables(descriptor, params, &variables_); 270} 271 272PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} 273 274void PrimitiveFieldGenerator:: 275GenerateMembers(io::Printer* printer) const { 276 if (variables_.find("default_constant_value") != variables_.end()) { 277 // Those primitive types that need a saved default. 278 printer->Print(variables_, 279 "private static final $type$ $default_constant$ = $default_constant_value$;\n"); 280 if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { 281 printer->Print(variables_, 282 "public $type$ $name$ = $default$.clone();\n"); 283 } else { 284 printer->Print(variables_, 285 "public $type$ $name$ = $default$;\n"); 286 } 287 } else { 288 printer->Print(variables_, 289 "public $type$ $name$ = $default$;\n"); 290 } 291} 292 293void PrimitiveFieldGenerator:: 294GenerateParsingCode(io::Printer* printer) const { 295 printer->Print(variables_, 296 "this.$name$ = input.read$capitalized_type$();\n"); 297} 298 299void PrimitiveFieldGenerator:: 300GenerateSerializationCode(io::Printer* printer) const { 301 if (descriptor_->is_required()) { 302 printer->Print(variables_, 303 "output.write$capitalized_type$($number$, this.$name$);\n"); 304 } else { 305 if (IsArrayType(GetJavaType(descriptor_))) { 306 printer->Print(variables_, 307 "if (!java.util.Arrays.equals(this.$name$, $default$)) {\n"); 308 } else if (IsReferenceType(GetJavaType(descriptor_))) { 309 printer->Print(variables_, 310 "if (!this.$name$.equals($default$)) {\n"); 311 } else { 312 printer->Print(variables_, 313 "if (this.$name$ != $default$) {\n"); 314 } 315 316 printer->Print(variables_, 317 " output.write$capitalized_type$($number$, this.$name$);\n" 318 "}\n"); 319 } 320} 321 322void PrimitiveFieldGenerator:: 323GenerateSerializedSizeCode(io::Printer* printer) const { 324 if (descriptor_->is_required()) { 325 printer->Print(variables_, 326 "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 327 " .compute$capitalized_type$Size($number$, this.$name$);\n"); 328 } else { 329 if (IsArrayType(GetJavaType(descriptor_))) { 330 printer->Print(variables_, 331 "if (!java.util.Arrays.equals(this.$name$, $default$)) {\n"); 332 } else if (IsReferenceType(GetJavaType(descriptor_))) { 333 printer->Print(variables_, 334 "if (!this.$name$.equals($default$)) {\n"); 335 } else { 336 printer->Print(variables_, 337 "if (this.$name$ != $default$) {\n"); 338 } 339 340 printer->Print(variables_, 341 " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 342 " .compute$capitalized_type$Size($number$, this.$name$);\n" 343 "}\n"); 344 } 345} 346 347string PrimitiveFieldGenerator::GetBoxedType() const { 348 return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); 349} 350 351// =================================================================== 352 353RepeatedPrimitiveFieldGenerator:: 354RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params) 355 : FieldGenerator(params), descriptor_(descriptor) { 356 SetPrimitiveVariables(descriptor, params, &variables_); 357} 358 359RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} 360 361void RepeatedPrimitiveFieldGenerator:: 362GenerateMembers(io::Printer* printer) const { 363 printer->Print(variables_, 364 "public $type$[] $name$ = $default$;\n"); 365 if (descriptor_->options().packed()) { 366 printer->Print(variables_, 367 "private int $name$MemoizedSerializedSize;\n"); 368 } 369} 370 371void RepeatedPrimitiveFieldGenerator:: 372GenerateParsingCode(io::Printer* printer) const { 373 // First, figure out the length of the array, then parse. 374 if (descriptor_->options().packed()) { 375 printer->Print(variables_, 376 "int length = input.readRawVarint32();\n" 377 "int limit = input.pushLimit(length);\n" 378 "// First pass to compute array length.\n" 379 "int arrayLength = 0;\n" 380 "int startPos = input.getPosition();\n" 381 "while (input.getBytesUntilLimit() > 0) {\n" 382 " input.read$capitalized_type$();\n" 383 " arrayLength++;\n" 384 "}\n" 385 "input.rewindToPosition(startPos);\n" 386 "this.$name$ = new $type$[arrayLength];\n" 387 "for (int i = 0; i < arrayLength; i++) {\n" 388 " this.$name$[i] = input.read$capitalized_type$();\n" 389 "}\n" 390 "input.popLimit(limit);\n"); 391 } else { 392 printer->Print(variables_, 393 "int arrayLength = com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, $tag$);\n" 394 "int i = this.$name$.length;\n"); 395 396 if (GetJavaType(descriptor_) == JAVATYPE_BYTES) { 397 printer->Print(variables_, 398 "byte[][] newArray = new byte[i + arrayLength][];\n" 399 "System.arraycopy(this.$name$, 0, newArray, 0, i);\n" 400 "this.$name$ = newArray;\n"); 401 } else { 402 printer->Print(variables_, 403 "$type$[] newArray = new $type$[i + arrayLength];\n" 404 "System.arraycopy(this.$name$, 0, newArray, 0, i);\n" 405 "this.$name$ = newArray;\n"); 406 } 407 printer->Print(variables_, 408 "for (; i < this.$name$.length - 1; i++) {\n" 409 " this.$name$[i] = input.read$capitalized_type$();\n" 410 " input.readTag();\n" 411 "}\n" 412 "// Last one without readTag.\n" 413 "this.$name$[i] = input.read$capitalized_type$();\n"); 414 } 415} 416 417void RepeatedPrimitiveFieldGenerator:: 418GenerateSerializationCode(io::Printer* printer) const { 419 if (descriptor_->options().packed()) { 420 printer->Print(variables_, 421 "if (this.$name$.length > 0) {\n" 422 " output.writeRawVarint32($tag$);\n" 423 " output.writeRawVarint32($name$MemoizedSerializedSize);\n" 424 "}\n"); 425 printer->Print(variables_, 426 "for ($type$ element : this.$name$) {\n" 427 " output.write$capitalized_type$NoTag(element);\n" 428 "}\n"); 429 } else { 430 printer->Print(variables_, 431 "for ($type$ element : this.$name$) {\n" 432 " output.write$capitalized_type$($number$, element);\n" 433 "}\n"); 434 } 435} 436 437void RepeatedPrimitiveFieldGenerator:: 438GenerateSerializedSizeCode(io::Printer* printer) const { 439 printer->Print(variables_, 440 "if (this.$name$.length > 0) {\n"); 441 printer->Indent(); 442 443 if (FixedSize(descriptor_->type()) == -1) { 444 printer->Print(variables_, 445 "int dataSize = 0;\n" 446 "for ($type$ element : this.$name$) {\n" 447 " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 448 " .compute$capitalized_type$SizeNoTag(element);\n" 449 "}\n"); 450 } else { 451 printer->Print(variables_, 452 "int dataSize = $fixed_size$ * this.$name$.length;\n"); 453 } 454 455 printer->Print( 456 "size += dataSize;\n"); 457 if (descriptor_->options().packed()) { 458 // cache the data size for packed fields. 459 printer->Print(variables_, 460 "size += $tag_size$;\n" 461 "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 462 " .computeRawVarint32Size(dataSize);\n" 463 "$name$MemoizedSerializedSize = dataSize;\n"); 464 } else { 465 printer->Print(variables_, 466 "size += $tag_size$ * this.$name$.length;\n"); 467 } 468 469 printer->Outdent(); 470 471 // set cached size to 0 for empty packed fields. 472 if (descriptor_->options().packed()) { 473 printer->Print(variables_, 474 "} else {\n" 475 " $name$MemoizedSerializedSize = 0;\n" 476 "}\n"); 477 } else { 478 printer->Print( 479 "}\n"); 480 } 481} 482 483string RepeatedPrimitiveFieldGenerator::GetBoxedType() const { 484 return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); 485} 486 487} // namespace javanano 488} // namespace compiler 489} // namespace protobuf 490} // namespace google 491