javanano_primitive_field.cc revision 0f1c4eb967517e21701a3b425d115baff5d15b4f
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 "this.$name$ = java.util.Arrays.copyOf(this.$name$, this.$name$.length + arrayLength);\n" 396 "for (; i < this.$name$.length - 1; i++) {\n" 397 " this.$name$[i] = input.read$capitalized_type$();\n" 398 " input.readTag();\n" 399 "}\n" 400 "// Last one without readTag.\n" 401 "this.$name$[i] = input.read$capitalized_type$();\n"); 402 } 403} 404 405void RepeatedPrimitiveFieldGenerator:: 406GenerateSerializationCode(io::Printer* printer) const { 407 if (descriptor_->options().packed()) { 408 printer->Print(variables_, 409 "if (this.$name$.length > 0) {\n" 410 " output.writeRawVarint32($tag$);\n" 411 " output.writeRawVarint32($name$MemoizedSerializedSize);\n" 412 "}\n"); 413 printer->Print(variables_, 414 "for ($type$ element : this.$name$) {\n" 415 " output.write$capitalized_type$NoTag(element);\n" 416 "}\n"); 417 } else { 418 printer->Print(variables_, 419 "for ($type$ element : this.$name$) {\n" 420 " output.write$capitalized_type$($number$, element);\n" 421 "}\n"); 422 } 423} 424 425void RepeatedPrimitiveFieldGenerator:: 426GenerateSerializedSizeCode(io::Printer* printer) const { 427 printer->Print(variables_, 428 "if (this.$name$.length > 0) {\n"); 429 printer->Indent(); 430 431 if (FixedSize(descriptor_->type()) == -1) { 432 printer->Print(variables_, 433 "int dataSize = 0;\n" 434 "for ($type$ element : this.$name$) {\n" 435 " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 436 " .compute$capitalized_type$SizeNoTag(element);\n" 437 "}\n"); 438 } else { 439 printer->Print(variables_, 440 "int dataSize = $fixed_size$ * this.$name$.length;\n"); 441 } 442 443 printer->Print( 444 "size += dataSize;\n"); 445 if (descriptor_->options().packed()) { 446 // cache the data size for packed fields. 447 printer->Print(variables_, 448 "size += $tag_size$;\n" 449 "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 450 " .computeRawVarint32Size(dataSize);\n" 451 "$name$MemoizedSerializedSize = dataSize;\n"); 452 } else { 453 printer->Print(variables_, 454 "size += $tag_size$ * this.$name$.length;\n"); 455 } 456 457 printer->Outdent(); 458 459 // set cached size to 0 for empty packed fields. 460 if (descriptor_->options().packed()) { 461 printer->Print(variables_, 462 "} else {\n" 463 " $name$MemoizedSerializedSize = 0;\n" 464 "}\n"); 465 } else { 466 printer->Print( 467 "}\n"); 468 } 469} 470 471string RepeatedPrimitiveFieldGenerator::GetBoxedType() const { 472 return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); 473} 474 475} // namespace javanano 476} // namespace compiler 477} // namespace protobuf 478} // namespace google 479