1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 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 <google/protobuf/compiler/cpp/cpp_primitive_field.h> 36 #include <google/protobuf/compiler/cpp/cpp_helpers.h> 37 #include <google/protobuf/io/printer.h> 38 #include <google/protobuf/wire_format.h> 39 #include <google/protobuf/stubs/strutil.h> 40 41 namespace google { 42 namespace protobuf { 43 namespace compiler { 44 namespace cpp { 45 46 using internal::WireFormatLite; 47 48 namespace { 49 50 // For encodings with fixed sizes, returns that size in bytes. Otherwise 51 // returns -1. FixedSize(FieldDescriptor::Type type)52 int FixedSize(FieldDescriptor::Type type) { 53 switch (type) { 54 case FieldDescriptor::TYPE_INT32 : return -1; 55 case FieldDescriptor::TYPE_INT64 : return -1; 56 case FieldDescriptor::TYPE_UINT32 : return -1; 57 case FieldDescriptor::TYPE_UINT64 : return -1; 58 case FieldDescriptor::TYPE_SINT32 : return -1; 59 case FieldDescriptor::TYPE_SINT64 : return -1; 60 case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; 61 case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; 62 case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; 63 case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; 64 case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; 65 case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; 66 67 case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; 68 case FieldDescriptor::TYPE_ENUM : return -1; 69 70 case FieldDescriptor::TYPE_STRING : return -1; 71 case FieldDescriptor::TYPE_BYTES : return -1; 72 case FieldDescriptor::TYPE_GROUP : return -1; 73 case FieldDescriptor::TYPE_MESSAGE : return -1; 74 75 // No default because we want the compiler to complain if any new 76 // types are added. 77 } 78 GOOGLE_LOG(FATAL) << "Can't get here."; 79 return -1; 80 } 81 SetPrimitiveVariables(const FieldDescriptor * descriptor,map<string,string> * variables,const Options & options)82 void SetPrimitiveVariables(const FieldDescriptor* descriptor, 83 map<string, string>* variables, 84 const Options& options) { 85 SetCommonFieldVariables(descriptor, variables, options); 86 (*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type()); 87 (*variables)["default"] = DefaultValue(descriptor); 88 (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); 89 int fixed_size = FixedSize(descriptor->type()); 90 if (fixed_size != -1) { 91 (*variables)["fixed_size"] = SimpleItoa(fixed_size); 92 } 93 (*variables)["wire_format_field_type"] = 94 "::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name( 95 static_cast<FieldDescriptorProto_Type>(descriptor->type())); 96 (*variables)["full_name"] = descriptor->full_name(); 97 } 98 99 } // namespace 100 101 // =================================================================== 102 PrimitiveFieldGenerator(const FieldDescriptor * descriptor,const Options & options)103 PrimitiveFieldGenerator::PrimitiveFieldGenerator( 104 const FieldDescriptor* descriptor, const Options& options) 105 : FieldGenerator(options), descriptor_(descriptor) { 106 SetPrimitiveVariables(descriptor, &variables_, options); 107 } 108 ~PrimitiveFieldGenerator()109 PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} 110 111 void PrimitiveFieldGenerator:: GeneratePrivateMembers(io::Printer * printer) const112 GeneratePrivateMembers(io::Printer* printer) const { 113 printer->Print(variables_, "$type$ $name$_;\n"); 114 } 115 116 void PrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer * printer) const117 GenerateAccessorDeclarations(io::Printer* printer) const { 118 printer->Print(variables_, 119 "$deprecated_attr$$type$ $name$() const;\n" 120 "$deprecated_attr$void set_$name$($type$ value);\n"); 121 } 122 123 void PrimitiveFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer * printer,bool is_inline) const124 GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { 125 map<string, string> variables(variables_); 126 variables["inline"] = is_inline ? "inline" : ""; 127 printer->Print(variables, 128 "$inline$ $type$ $classname$::$name$() const {\n" 129 " // @@protoc_insertion_point(field_get:$full_name$)\n" 130 " return $name$_;\n" 131 "}\n" 132 "$inline$ void $classname$::set_$name$($type$ value) {\n" 133 " $set_hasbit$\n" 134 " $name$_ = value;\n" 135 " // @@protoc_insertion_point(field_set:$full_name$)\n" 136 "}\n"); 137 } 138 139 void PrimitiveFieldGenerator:: GenerateClearingCode(io::Printer * printer) const140 GenerateClearingCode(io::Printer* printer) const { 141 printer->Print(variables_, "$name$_ = $default$;\n"); 142 } 143 144 void PrimitiveFieldGenerator:: GenerateMergingCode(io::Printer * printer) const145 GenerateMergingCode(io::Printer* printer) const { 146 printer->Print(variables_, "set_$name$(from.$name$());\n"); 147 } 148 149 void PrimitiveFieldGenerator:: GenerateSwappingCode(io::Printer * printer) const150 GenerateSwappingCode(io::Printer* printer) const { 151 printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); 152 } 153 154 void PrimitiveFieldGenerator:: GenerateConstructorCode(io::Printer * printer) const155 GenerateConstructorCode(io::Printer* printer) const { 156 printer->Print(variables_, "$name$_ = $default$;\n"); 157 } 158 159 void PrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer * printer) const160 GenerateMergeFromCodedStream(io::Printer* printer) const { 161 printer->Print(variables_, 162 "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" 163 " $type$, $wire_format_field_type$>(\n" 164 " input, &$name$_)));\n" 165 "$set_hasbit$\n"); 166 } 167 168 void PrimitiveFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer * printer) const169 GenerateSerializeWithCachedSizes(io::Printer* printer) const { 170 printer->Print(variables_, 171 "::google::protobuf::internal::WireFormatLite::Write$declared_type$(" 172 "$number$, this->$name$(), output);\n"); 173 } 174 175 void PrimitiveFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const176 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { 177 printer->Print(variables_, 178 "target = ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray(" 179 "$number$, this->$name$(), target);\n"); 180 } 181 182 void PrimitiveFieldGenerator:: GenerateByteSize(io::Printer * printer) const183 GenerateByteSize(io::Printer* printer) const { 184 int fixed_size = FixedSize(descriptor_->type()); 185 if (fixed_size == -1) { 186 printer->Print(variables_, 187 "total_size += $tag_size$ +\n" 188 " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" 189 " this->$name$());\n"); 190 } else { 191 printer->Print(variables_, 192 "total_size += $tag_size$ + $fixed_size$;\n"); 193 } 194 } 195 196 // =================================================================== 197 198 PrimitiveOneofFieldGenerator:: PrimitiveOneofFieldGenerator(const FieldDescriptor * descriptor,const Options & options)199 PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, 200 const Options& options) 201 : PrimitiveFieldGenerator(descriptor, options) { 202 SetCommonOneofFieldVariables(descriptor, &variables_); 203 } 204 ~PrimitiveOneofFieldGenerator()205 PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {} 206 207 void PrimitiveOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer * printer,bool is_inline) const208 GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { 209 map<string, string> variables(variables_); 210 variables["inline"] = is_inline ? "inline" : ""; 211 printer->Print(variables, 212 "$inline$ $type$ $classname$::$name$() const {\n" 213 " // @@protoc_insertion_point(field_get:$full_name$)\n" 214 " if (has_$name$()) {\n" 215 " return $oneof_prefix$$name$_;\n" 216 " }\n" 217 " return $default$;\n" 218 "}\n" 219 "$inline$ void $classname$::set_$name$($type$ value) {\n" 220 " if (!has_$name$()) {\n" 221 " clear_$oneof_name$();\n" 222 " set_has_$name$();\n" 223 " }\n" 224 " $oneof_prefix$$name$_ = value;\n" 225 " // @@protoc_insertion_point(field_set:$full_name$)\n" 226 "}\n"); 227 } 228 229 void PrimitiveOneofFieldGenerator:: GenerateClearingCode(io::Printer * printer) const230 GenerateClearingCode(io::Printer* printer) const { 231 printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n"); 232 } 233 234 void PrimitiveOneofFieldGenerator:: GenerateSwappingCode(io::Printer * printer) const235 GenerateSwappingCode(io::Printer* printer) const { 236 // Don't print any swapping code. Swapping the union will swap this field. 237 } 238 239 void PrimitiveOneofFieldGenerator:: GenerateConstructorCode(io::Printer * printer) const240 GenerateConstructorCode(io::Printer* printer) const { 241 printer->Print( 242 variables_, 243 " $classname$_default_oneof_instance_->$name$_ = $default$;\n"); 244 } 245 246 void PrimitiveOneofFieldGenerator:: GenerateMergeFromCodedStream(io::Printer * printer) const247 GenerateMergeFromCodedStream(io::Printer* printer) const { 248 printer->Print(variables_, 249 "clear_$oneof_name$();\n" 250 "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" 251 " $type$, $wire_format_field_type$>(\n" 252 " input, &$oneof_prefix$$name$_)));\n" 253 "set_has_$name$();\n"); 254 } 255 256 // =================================================================== 257 RepeatedPrimitiveFieldGenerator(const FieldDescriptor * descriptor,const Options & options)258 RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( 259 const FieldDescriptor* descriptor, const Options& options) 260 : FieldGenerator(options), descriptor_(descriptor) { 261 SetPrimitiveVariables(descriptor, &variables_, options); 262 263 if (descriptor->is_packed()) { 264 variables_["packed_reader"] = "ReadPackedPrimitive"; 265 variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline"; 266 } else { 267 variables_["packed_reader"] = "ReadPackedPrimitiveNoInline"; 268 variables_["repeated_reader"] = "ReadRepeatedPrimitive"; 269 } 270 } 271 ~RepeatedPrimitiveFieldGenerator()272 RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} 273 274 void RepeatedPrimitiveFieldGenerator:: GeneratePrivateMembers(io::Printer * printer) const275 GeneratePrivateMembers(io::Printer* printer) const { 276 printer->Print(variables_, 277 "::google::protobuf::RepeatedField< $type$ > $name$_;\n"); 278 if (descriptor_->is_packed() && 279 HasGeneratedMethods(descriptor_->file(), options_)) { 280 printer->Print(variables_, 281 "mutable int _$name$_cached_byte_size_;\n"); 282 } 283 } 284 285 void RepeatedPrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer * printer) const286 GenerateAccessorDeclarations(io::Printer* printer) const { 287 printer->Print(variables_, 288 "$deprecated_attr$$type$ $name$(int index) const;\n" 289 "$deprecated_attr$void set_$name$(int index, $type$ value);\n" 290 "$deprecated_attr$void add_$name$($type$ value);\n"); 291 printer->Print(variables_, 292 "$deprecated_attr$const ::google::protobuf::RepeatedField< $type$ >&\n" 293 " $name$() const;\n" 294 "$deprecated_attr$::google::protobuf::RepeatedField< $type$ >*\n" 295 " mutable_$name$();\n"); 296 } 297 298 void RepeatedPrimitiveFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer * printer,bool is_inline) const299 GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { 300 map<string, string> variables(variables_); 301 variables["inline"] = is_inline ? "inline" : ""; 302 printer->Print(variables, 303 "$inline$ $type$ $classname$::$name$(int index) const {\n" 304 " // @@protoc_insertion_point(field_get:$full_name$)\n" 305 " return $name$_.Get(index);\n" 306 "}\n" 307 "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n" 308 " $name$_.Set(index, value);\n" 309 " // @@protoc_insertion_point(field_set:$full_name$)\n" 310 "}\n" 311 "$inline$ void $classname$::add_$name$($type$ value) {\n" 312 " $name$_.Add(value);\n" 313 " // @@protoc_insertion_point(field_add:$full_name$)\n" 314 "}\n"); 315 printer->Print(variables, 316 "$inline$ const ::google::protobuf::RepeatedField< $type$ >&\n" 317 "$classname$::$name$() const {\n" 318 " // @@protoc_insertion_point(field_list:$full_name$)\n" 319 " return $name$_;\n" 320 "}\n" 321 "$inline$ ::google::protobuf::RepeatedField< $type$ >*\n" 322 "$classname$::mutable_$name$() {\n" 323 " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" 324 " return &$name$_;\n" 325 "}\n"); 326 } 327 328 void RepeatedPrimitiveFieldGenerator:: GenerateClearingCode(io::Printer * printer) const329 GenerateClearingCode(io::Printer* printer) const { 330 printer->Print(variables_, "$name$_.Clear();\n"); 331 } 332 333 void RepeatedPrimitiveFieldGenerator:: GenerateMergingCode(io::Printer * printer) const334 GenerateMergingCode(io::Printer* printer) const { 335 printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); 336 } 337 338 void RepeatedPrimitiveFieldGenerator:: GenerateSwappingCode(io::Printer * printer) const339 GenerateSwappingCode(io::Printer* printer) const { 340 printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n"); 341 } 342 343 void RepeatedPrimitiveFieldGenerator:: GenerateConstructorCode(io::Printer * printer) const344 GenerateConstructorCode(io::Printer* printer) const { 345 // Not needed for repeated fields. 346 } 347 348 void RepeatedPrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer * printer) const349 GenerateMergeFromCodedStream(io::Printer* printer) const { 350 printer->Print(variables_, 351 "DO_((::google::protobuf::internal::WireFormatLite::$repeated_reader$<\n" 352 " $type$, $wire_format_field_type$>(\n" 353 " $tag_size$, $tag$, input, this->mutable_$name$())));\n"); 354 } 355 356 void RepeatedPrimitiveFieldGenerator:: GenerateMergeFromCodedStreamWithPacking(io::Printer * printer) const357 GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { 358 printer->Print(variables_, 359 "DO_((::google::protobuf::internal::WireFormatLite::$packed_reader$<\n" 360 " $type$, $wire_format_field_type$>(\n" 361 " input, this->mutable_$name$())));\n"); 362 } 363 364 void RepeatedPrimitiveFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer * printer) const365 GenerateSerializeWithCachedSizes(io::Printer* printer) const { 366 if (descriptor_->is_packed()) { 367 // Write the tag and the size. 368 printer->Print(variables_, 369 "if (this->$name$_size() > 0) {\n" 370 " ::google::protobuf::internal::WireFormatLite::WriteTag(" 371 "$number$, " 372 "::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, " 373 "output);\n" 374 " output->WriteVarint32(_$name$_cached_byte_size_);\n" 375 "}\n"); 376 } 377 printer->Print(variables_, 378 "for (int i = 0; i < this->$name$_size(); i++) {\n"); 379 if (descriptor_->is_packed()) { 380 printer->Print(variables_, 381 " ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n" 382 " this->$name$(i), output);\n"); 383 } else { 384 printer->Print(variables_, 385 " ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n" 386 " $number$, this->$name$(i), output);\n"); 387 } 388 printer->Print("}\n"); 389 } 390 391 void RepeatedPrimitiveFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const392 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { 393 if (descriptor_->is_packed()) { 394 // Write the tag and the size. 395 printer->Print(variables_, 396 "if (this->$name$_size() > 0) {\n" 397 " target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n" 398 " $number$,\n" 399 " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" 400 " target);\n" 401 " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n" 402 " _$name$_cached_byte_size_, target);\n" 403 "}\n"); 404 } 405 printer->Print(variables_, 406 "for (int i = 0; i < this->$name$_size(); i++) {\n"); 407 if (descriptor_->is_packed()) { 408 printer->Print(variables_, 409 " target = ::google::protobuf::internal::WireFormatLite::\n" 410 " Write$declared_type$NoTagToArray(this->$name$(i), target);\n"); 411 } else { 412 printer->Print(variables_, 413 " target = ::google::protobuf::internal::WireFormatLite::\n" 414 " Write$declared_type$ToArray($number$, this->$name$(i), target);\n"); 415 } 416 printer->Print("}\n"); 417 } 418 419 void RepeatedPrimitiveFieldGenerator:: GenerateByteSize(io::Printer * printer) const420 GenerateByteSize(io::Printer* printer) const { 421 printer->Print(variables_, 422 "{\n" 423 " int data_size = 0;\n"); 424 printer->Indent(); 425 int fixed_size = FixedSize(descriptor_->type()); 426 if (fixed_size == -1) { 427 printer->Print(variables_, 428 "for (int i = 0; i < this->$name$_size(); i++) {\n" 429 " data_size += ::google::protobuf::internal::WireFormatLite::\n" 430 " $declared_type$Size(this->$name$(i));\n" 431 "}\n"); 432 } else { 433 printer->Print(variables_, 434 "data_size = $fixed_size$ * this->$name$_size();\n"); 435 } 436 437 if (descriptor_->is_packed()) { 438 printer->Print(variables_, 439 "if (data_size > 0) {\n" 440 " total_size += $tag_size$ +\n" 441 " ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n" 442 "}\n" 443 "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" 444 "_$name$_cached_byte_size_ = data_size;\n" 445 "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" 446 "total_size += data_size;\n"); 447 } else { 448 printer->Print(variables_, 449 "total_size += $tag_size$ * this->$name$_size() + data_size;\n"); 450 } 451 printer->Outdent(); 452 printer->Print("}\n"); 453 } 454 455 } // namespace cpp 456 } // namespace compiler 457 } // namespace protobuf 458 } // namespace google 459