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 41namespace google { 42namespace protobuf { 43namespace compiler { 44namespace cpp { 45 46using internal::WireFormatLite; 47 48namespace { 49 50// For encodings with fixed sizes, returns that size in bytes. Otherwise 51// returns -1. 52int 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 82void 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 103PrimitiveFieldGenerator::PrimitiveFieldGenerator( 104 const FieldDescriptor* descriptor, const Options& options) 105 : FieldGenerator(options), descriptor_(descriptor) { 106 SetPrimitiveVariables(descriptor, &variables_, options); 107} 108 109PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} 110 111void PrimitiveFieldGenerator:: 112GeneratePrivateMembers(io::Printer* printer) const { 113 printer->Print(variables_, "$type$ $name$_;\n"); 114} 115 116void PrimitiveFieldGenerator:: 117GenerateAccessorDeclarations(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 123void PrimitiveFieldGenerator:: 124GenerateInlineAccessorDefinitions(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 139void PrimitiveFieldGenerator:: 140GenerateClearingCode(io::Printer* printer) const { 141 printer->Print(variables_, "$name$_ = $default$;\n"); 142} 143 144void PrimitiveFieldGenerator:: 145GenerateMergingCode(io::Printer* printer) const { 146 printer->Print(variables_, "set_$name$(from.$name$());\n"); 147} 148 149void PrimitiveFieldGenerator:: 150GenerateSwappingCode(io::Printer* printer) const { 151 printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); 152} 153 154void PrimitiveFieldGenerator:: 155GenerateConstructorCode(io::Printer* printer) const { 156 printer->Print(variables_, "$name$_ = $default$;\n"); 157} 158 159void PrimitiveFieldGenerator:: 160GenerateMergeFromCodedStream(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 168void PrimitiveFieldGenerator:: 169GenerateSerializeWithCachedSizes(io::Printer* printer) const { 170 printer->Print(variables_, 171 "::google::protobuf::internal::WireFormatLite::Write$declared_type$(" 172 "$number$, this->$name$(), output);\n"); 173} 174 175void PrimitiveFieldGenerator:: 176GenerateSerializeWithCachedSizesToArray(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 182void PrimitiveFieldGenerator:: 183GenerateByteSize(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 198PrimitiveOneofFieldGenerator:: 199PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, 200 const Options& options) 201 : PrimitiveFieldGenerator(descriptor, options) { 202 SetCommonOneofFieldVariables(descriptor, &variables_); 203} 204 205PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {} 206 207void PrimitiveOneofFieldGenerator:: 208GenerateInlineAccessorDefinitions(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 229void PrimitiveOneofFieldGenerator:: 230GenerateClearingCode(io::Printer* printer) const { 231 printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n"); 232} 233 234void PrimitiveOneofFieldGenerator:: 235GenerateSwappingCode(io::Printer* printer) const { 236 // Don't print any swapping code. Swapping the union will swap this field. 237} 238 239void PrimitiveOneofFieldGenerator:: 240GenerateConstructorCode(io::Printer* printer) const { 241 printer->Print( 242 variables_, 243 " $classname$_default_oneof_instance_->$name$_ = $default$;\n"); 244} 245 246void PrimitiveOneofFieldGenerator:: 247GenerateMergeFromCodedStream(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 258RepeatedPrimitiveFieldGenerator::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 272RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} 273 274void RepeatedPrimitiveFieldGenerator:: 275GeneratePrivateMembers(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 285void RepeatedPrimitiveFieldGenerator:: 286GenerateAccessorDeclarations(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 298void RepeatedPrimitiveFieldGenerator:: 299GenerateInlineAccessorDefinitions(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 328void RepeatedPrimitiveFieldGenerator:: 329GenerateClearingCode(io::Printer* printer) const { 330 printer->Print(variables_, "$name$_.Clear();\n"); 331} 332 333void RepeatedPrimitiveFieldGenerator:: 334GenerateMergingCode(io::Printer* printer) const { 335 printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); 336} 337 338void RepeatedPrimitiveFieldGenerator:: 339GenerateSwappingCode(io::Printer* printer) const { 340 printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n"); 341} 342 343void RepeatedPrimitiveFieldGenerator:: 344GenerateConstructorCode(io::Printer* printer) const { 345 // Not needed for repeated fields. 346} 347 348void RepeatedPrimitiveFieldGenerator:: 349GenerateMergeFromCodedStream(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 356void RepeatedPrimitiveFieldGenerator:: 357GenerateMergeFromCodedStreamWithPacking(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 364void RepeatedPrimitiveFieldGenerator:: 365GenerateSerializeWithCachedSizes(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 391void RepeatedPrimitiveFieldGenerator:: 392GenerateSerializeWithCachedSizesToArray(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 419void RepeatedPrimitiveFieldGenerator:: 420GenerateByteSize(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