java_enum_field.cc revision fbaaef999ba563838ebd00874ed8a1c01fbf286d
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Protocol Buffers - Google's data interchange format 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Copyright 2008 Google Inc. All rights reserved. 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// http://code.google.com/p/protobuf/ 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Redistribution and use in source and binary forms, with or without 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// modification, are permitted provided that the following conditions are 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// met: 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// * Redistributions of source code must retain the above copyright 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// notice, this list of conditions and the following disclaimer. 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// * Redistributions in binary form must reproduce the above 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// in the documentation and/or other materials provided with the 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// distribution. 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// * Neither the name of Google Inc. nor the names of its 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// contributors may be used to endorse or promote products derived from 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// this software without specific prior written permission. 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 31e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)// Author: kenton@google.com (Kenton Varda) 32e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)// Based on original Protocol Buffers design by 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Sanjay Ghemawat, Jeff Dean, and others. 34e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) 35e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)#include <map> 365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <string> 3751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <google/protobuf/compiler/java/java_enum_field.h> 398abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)#include <google/protobuf/stubs/common.h> 40e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)#include <google/protobuf/compiler/java/java_helpers.h> 415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <google/protobuf/io/printer.h> 42e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)#include <google/protobuf/wire_format.h> 435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <google/protobuf/stubs/strutil.h> 44e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) 455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace google { 46e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)namespace protobuf { 47e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)namespace compiler { 488abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)namespace java { 498abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace { 51e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) 52e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of 53e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)// repeat code between this and the other field types. 54e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)void SetEnumVariables(const FieldDescriptor* descriptor, 555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) map<string, string>* variables) { 565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) (*variables)["name"] = 5751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) UnderscoresToCamelCase(descriptor); 585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) (*variables)["capitalized_name"] = 59e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) UnderscoresToCapitalizedCamelCase(descriptor); 60 (*variables)["number"] = SimpleItoa(descriptor->number()); 61 (*variables)["type"] = ClassName(descriptor->enum_type()); 62 (*variables)["default"] = DefaultValue(descriptor); 63 (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); 64 (*variables)["tag_size"] = SimpleItoa( 65 internal::WireFormat::TagSize(descriptor->number(), descriptor->type())); 66} 67 68} // namespace 69 70// =================================================================== 71 72EnumFieldGenerator:: 73EnumFieldGenerator(const FieldDescriptor* descriptor) 74 : descriptor_(descriptor) { 75 SetEnumVariables(descriptor, &variables_); 76} 77 78EnumFieldGenerator::~EnumFieldGenerator() {} 79 80void EnumFieldGenerator:: 81GenerateMembers(io::Printer* printer) const { 82 printer->Print(variables_, 83 "private boolean has$capitalized_name$;\n" 84 "private $type$ $name$_ = $default$;\n" 85 "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" 86 "public $type$ get$capitalized_name$() { return $name$_; }\n"); 87} 88 89void EnumFieldGenerator:: 90GenerateBuilderMembers(io::Printer* printer) const { 91 printer->Print(variables_, 92 "public boolean has$capitalized_name$() {\n" 93 " return result.has$capitalized_name$();\n" 94 "}\n" 95 "public $type$ get$capitalized_name$() {\n" 96 " return result.get$capitalized_name$();\n" 97 "}\n" 98 "public Builder set$capitalized_name$($type$ value) {\n" 99 " if (value == null) {\n" 100 " throw new NullPointerException();\n" 101 " }\n" 102 " result.has$capitalized_name$ = true;\n" 103 " result.$name$_ = value;\n" 104 " return this;\n" 105 "}\n" 106 "public Builder clear$capitalized_name$() {\n" 107 " result.has$capitalized_name$ = false;\n" 108 " result.$name$_ = $default$;\n" 109 " return this;\n" 110 "}\n"); 111} 112 113void EnumFieldGenerator:: 114GenerateMergingCode(io::Printer* printer) const { 115 printer->Print(variables_, 116 "if (other.has$capitalized_name$()) {\n" 117 " set$capitalized_name$(other.get$capitalized_name$());\n" 118 "}\n"); 119} 120 121void EnumFieldGenerator:: 122GenerateBuildingCode(io::Printer* printer) const { 123 // Nothing to do here for enum types. 124} 125 126void EnumFieldGenerator:: 127GenerateParsingCode(io::Printer* printer) const { 128 printer->Print(variables_, 129 "int rawValue = input.readEnum();\n" 130 "$type$ value = $type$.valueOf(rawValue);\n"); 131 if (HasUnknownFields(descriptor_->containing_type())) { 132 printer->Print(variables_, 133 "if (value == null) {\n" 134 " unknownFields.mergeVarintField($number$, rawValue);\n" 135 "} else {\n"); 136 } else { 137 printer->Print(variables_, 138 "if (value != null) {\n"); 139 } 140 printer->Print(variables_, 141 " set$capitalized_name$(value);\n" 142 "}\n"); 143} 144 145void EnumFieldGenerator:: 146GenerateSerializationCode(io::Printer* printer) const { 147 printer->Print(variables_, 148 "if (has$capitalized_name$()) {\n" 149 " output.writeEnum($number$, get$capitalized_name$().getNumber());\n" 150 "}\n"); 151} 152 153void EnumFieldGenerator:: 154GenerateSerializedSizeCode(io::Printer* printer) const { 155 printer->Print(variables_, 156 "if (has$capitalized_name$()) {\n" 157 " size += com.google.protobuf.CodedOutputStream\n" 158 " .computeEnumSize($number$, get$capitalized_name$().getNumber());\n" 159 "}\n"); 160} 161 162string EnumFieldGenerator::GetBoxedType() const { 163 return ClassName(descriptor_->enum_type()); 164} 165 166// =================================================================== 167 168RepeatedEnumFieldGenerator:: 169RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor) 170 : descriptor_(descriptor) { 171 SetEnumVariables(descriptor, &variables_); 172} 173 174RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} 175 176void RepeatedEnumFieldGenerator:: 177GenerateMembers(io::Printer* printer) const { 178 printer->Print(variables_, 179 "private java.util.List<$type$> $name$_ =\n" 180 " java.util.Collections.emptyList();\n" 181 "public java.util.List<$type$> get$capitalized_name$List() {\n" 182 " return $name$_;\n" // note: unmodifiable list 183 "}\n" 184 "public int get$capitalized_name$Count() { return $name$_.size(); }\n" 185 "public $type$ get$capitalized_name$(int index) {\n" 186 " return $name$_.get(index);\n" 187 "}\n"); 188 189 if (descriptor_->options().packed() && 190 HasGeneratedMethods(descriptor_->containing_type())) { 191 printer->Print(variables_, 192 "private int $name$MemoizedSerializedSize;\n"); 193 } 194} 195 196void RepeatedEnumFieldGenerator:: 197GenerateBuilderMembers(io::Printer* printer) const { 198 printer->Print(variables_, 199 // Note: We return an unmodifiable list because otherwise the caller 200 // could hold on to the returned list and modify it after the message 201 // has been built, thus mutating the message which is supposed to be 202 // immutable. 203 "public java.util.List<$type$> get$capitalized_name$List() {\n" 204 " return java.util.Collections.unmodifiableList(result.$name$_);\n" 205 "}\n" 206 "public int get$capitalized_name$Count() {\n" 207 " return result.get$capitalized_name$Count();\n" 208 "}\n" 209 "public $type$ get$capitalized_name$(int index) {\n" 210 " return result.get$capitalized_name$(index);\n" 211 "}\n" 212 "public Builder set$capitalized_name$(int index, $type$ value) {\n" 213 " if (value == null) {\n" 214 " throw new NullPointerException();\n" 215 " }\n" 216 " result.$name$_.set(index, value);\n" 217 " return this;\n" 218 "}\n" 219 "public Builder add$capitalized_name$($type$ value) {\n" 220 " if (value == null) {\n" 221 " throw new NullPointerException();\n" 222 " }\n" 223 " if (result.$name$_.isEmpty()) {\n" 224 " result.$name$_ = new java.util.ArrayList<$type$>();\n" 225 " }\n" 226 " result.$name$_.add(value);\n" 227 " return this;\n" 228 "}\n" 229 "public Builder addAll$capitalized_name$(\n" 230 " java.lang.Iterable<? extends $type$> values) {\n" 231 " if (result.$name$_.isEmpty()) {\n" 232 " result.$name$_ = new java.util.ArrayList<$type$>();\n" 233 " }\n" 234 " super.addAll(values, result.$name$_);\n" 235 " return this;\n" 236 "}\n" 237 "public Builder clear$capitalized_name$() {\n" 238 " result.$name$_ = java.util.Collections.emptyList();\n" 239 " return this;\n" 240 "}\n"); 241} 242 243void RepeatedEnumFieldGenerator:: 244GenerateMergingCode(io::Printer* printer) const { 245 printer->Print(variables_, 246 "if (!other.$name$_.isEmpty()) {\n" 247 " if (result.$name$_.isEmpty()) {\n" 248 " result.$name$_ = new java.util.ArrayList<$type$>();\n" 249 " }\n" 250 " result.$name$_.addAll(other.$name$_);\n" 251 "}\n"); 252} 253 254void RepeatedEnumFieldGenerator:: 255GenerateBuildingCode(io::Printer* printer) const { 256 printer->Print(variables_, 257 "if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n" 258 " result.$name$_ =\n" 259 " java.util.Collections.unmodifiableList(result.$name$_);\n" 260 "}\n"); 261} 262 263void RepeatedEnumFieldGenerator:: 264GenerateParsingCode(io::Printer* printer) const { 265 // If packed, set up the while loop 266 if (descriptor_->options().packed()) { 267 printer->Print(variables_, 268 "int length = input.readRawVarint32();\n" 269 "int oldLimit = input.pushLimit(length);\n" 270 "while(input.getBytesUntilLimit() > 0) {\n"); 271 printer->Indent(); 272 } 273 274 // Read and store the enum 275 printer->Print(variables_, 276 "int rawValue = input.readEnum();\n" 277 "$type$ value = $type$.valueOf(rawValue);\n"); 278 if (HasUnknownFields(descriptor_->containing_type())) { 279 printer->Print(variables_, 280 "if (value == null) {\n" 281 " unknownFields.mergeVarintField($number$, rawValue);\n" 282 "} else {\n"); 283 } else { 284 printer->Print(variables_, 285 "if (value != null) {\n"); 286 } 287 printer->Print(variables_, 288 " add$capitalized_name$(value);\n" 289 "}\n"); 290 291 if (descriptor_->options().packed()) { 292 printer->Outdent(); 293 printer->Print(variables_, 294 "}\n" 295 "input.popLimit(oldLimit);\n"); 296 } 297} 298 299void RepeatedEnumFieldGenerator:: 300GenerateSerializationCode(io::Printer* printer) const { 301 if (descriptor_->options().packed()) { 302 printer->Print(variables_, 303 "if (get$capitalized_name$List().size() > 0) {\n" 304 " output.writeRawVarint32($tag$);\n" 305 " output.writeRawVarint32($name$MemoizedSerializedSize);\n" 306 "}\n" 307 "for ($type$ element : get$capitalized_name$List()) {\n" 308 " output.writeEnumNoTag(element.getNumber());\n" 309 "}\n"); 310 } else { 311 printer->Print(variables_, 312 "for ($type$ element : get$capitalized_name$List()) {\n" 313 " output.writeEnum($number$, element.getNumber());\n" 314 "}\n"); 315 } 316} 317 318void RepeatedEnumFieldGenerator:: 319GenerateSerializedSizeCode(io::Printer* printer) const { 320 printer->Print(variables_, 321 "{\n" 322 " int dataSize = 0;\n"); 323 printer->Indent(); 324 325 printer->Print(variables_, 326 "for ($type$ element : get$capitalized_name$List()) {\n" 327 " dataSize += com.google.protobuf.CodedOutputStream\n" 328 " .computeEnumSizeNoTag(element.getNumber());\n" 329 "}\n"); 330 printer->Print( 331 "size += dataSize;\n"); 332 if (descriptor_->options().packed()) { 333 printer->Print(variables_, 334 "if (!get$capitalized_name$List().isEmpty()) {" 335 " size += $tag_size$;\n" 336 " size += com.google.protobuf.CodedOutputStream\n" 337 " .computeRawVarint32Size(dataSize);\n" 338 "}"); 339 } else { 340 printer->Print(variables_, 341 "size += $tag_size$ * get$capitalized_name$List().size();\n"); 342 } 343 344 // cache the data size for packed fields. 345 if (descriptor_->options().packed()) { 346 printer->Print(variables_, 347 "$name$MemoizedSerializedSize = dataSize;\n"); 348 } 349 350 printer->Outdent(); 351 printer->Print("}\n"); 352} 353 354string RepeatedEnumFieldGenerator::GetBoxedType() const { 355 return ClassName(descriptor_->enum_type()); 356} 357 358} // namespace java 359} // namespace compiler 360} // namespace protobuf 361} // namespace google 362