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 <google/protobuf/compiler/cpp/cpp_enum_field.h> 36#include <google/protobuf/compiler/cpp/cpp_helpers.h> 37#include <google/protobuf/io/printer.h> 38#include <google/protobuf/descriptor.pb.h> 39#include <google/protobuf/stubs/strutil.h> 40 41namespace google { 42namespace protobuf { 43namespace compiler { 44namespace cpp { 45 46namespace { 47 48void SetEnumVariables(const FieldDescriptor* descriptor, 49 map<string, string>* variables) { 50 SetCommonFieldVariables(descriptor, variables); 51 const EnumValueDescriptor* default_value = descriptor->default_value_enum(); 52 (*variables)["type"] = ClassName(descriptor->enum_type(), true); 53 (*variables)["default"] = SimpleItoa(default_value->number()); 54} 55 56} // namespace 57 58// =================================================================== 59 60EnumFieldGenerator:: 61EnumFieldGenerator(const FieldDescriptor* descriptor) 62 : descriptor_(descriptor) { 63 SetEnumVariables(descriptor, &variables_); 64} 65 66EnumFieldGenerator::~EnumFieldGenerator() {} 67 68void EnumFieldGenerator:: 69GeneratePrivateMembers(io::Printer* printer) const { 70 printer->Print(variables_, "int $name$_;\n"); 71} 72 73void EnumFieldGenerator:: 74GenerateAccessorDeclarations(io::Printer* printer) const { 75 printer->Print(variables_, 76 "inline $type$ $name$() const$deprecation$;\n" 77 "inline void set_$name$($type$ value)$deprecation$;\n"); 78} 79 80void EnumFieldGenerator:: 81GenerateInlineAccessorDefinitions(io::Printer* printer) const { 82 printer->Print(variables_, 83 "inline $type$ $classname$::$name$() const {\n" 84 " return static_cast< $type$ >($name$_);\n" 85 "}\n" 86 "inline void $classname$::set_$name$($type$ value) {\n" 87 " GOOGLE_DCHECK($type$_IsValid(value));\n" 88 " _set_bit($index$);\n" 89 " $name$_ = value;\n" 90 "}\n"); 91} 92 93void EnumFieldGenerator:: 94GenerateClearingCode(io::Printer* printer) const { 95 printer->Print(variables_, "$name$_ = $default$;\n"); 96} 97 98void EnumFieldGenerator:: 99GenerateMergingCode(io::Printer* printer) const { 100 printer->Print(variables_, "set_$name$(from.$name$());\n"); 101} 102 103void EnumFieldGenerator:: 104GenerateSwappingCode(io::Printer* printer) const { 105 printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); 106} 107 108void EnumFieldGenerator:: 109GenerateConstructorCode(io::Printer* printer) const { 110 printer->Print(variables_, "$name$_ = $default$;\n"); 111} 112 113void EnumFieldGenerator:: 114GenerateMergeFromCodedStream(io::Printer* printer) const { 115 printer->Print(variables_, 116 "int value;\n" 117 "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" 118 " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" 119 " input, &value)));\n" 120 "if ($type$_IsValid(value)) {\n" 121 " set_$name$(static_cast< $type$ >(value));\n"); 122 if (HasUnknownFields(descriptor_->file())) { 123 printer->Print(variables_, 124 "} else {\n" 125 " mutable_unknown_fields()->AddVarint($number$, value);\n"); 126 } 127 printer->Print(variables_, 128 "}\n"); 129} 130 131void EnumFieldGenerator:: 132GenerateSerializeWithCachedSizes(io::Printer* printer) const { 133 printer->Print(variables_, 134 "::google::protobuf::internal::WireFormatLite::WriteEnum(\n" 135 " $number$, this->$name$(), output);\n"); 136} 137 138void EnumFieldGenerator:: 139GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { 140 printer->Print(variables_, 141 "target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n" 142 " $number$, this->$name$(), target);\n"); 143} 144 145void EnumFieldGenerator:: 146GenerateByteSize(io::Printer* printer) const { 147 printer->Print(variables_, 148 "total_size += $tag_size$ +\n" 149 " ::google::protobuf::internal::WireFormatLite::EnumSize(this->$name$());\n"); 150} 151 152// =================================================================== 153 154RepeatedEnumFieldGenerator:: 155RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor) 156 : descriptor_(descriptor) { 157 SetEnumVariables(descriptor, &variables_); 158} 159 160RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} 161 162void RepeatedEnumFieldGenerator:: 163GeneratePrivateMembers(io::Printer* printer) const { 164 printer->Print(variables_, 165 "::google::protobuf::RepeatedField<int> $name$_;\n"); 166 if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) { 167 printer->Print(variables_, 168 "mutable int _$name$_cached_byte_size_;\n"); 169 } 170} 171 172void RepeatedEnumFieldGenerator:: 173GenerateAccessorDeclarations(io::Printer* printer) const { 174 printer->Print(variables_, 175 "inline $type$ $name$(int index) const$deprecation$;\n" 176 "inline void set_$name$(int index, $type$ value)$deprecation$;\n" 177 "inline void add_$name$($type$ value)$deprecation$;\n"); 178 printer->Print(variables_, 179 "inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n" 180 "inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n"); 181} 182 183void RepeatedEnumFieldGenerator:: 184GenerateInlineAccessorDefinitions(io::Printer* printer) const { 185 printer->Print(variables_, 186 "inline $type$ $classname$::$name$(int index) const {\n" 187 " return static_cast< $type$ >($name$_.Get(index));\n" 188 "}\n" 189 "inline void $classname$::set_$name$(int index, $type$ value) {\n" 190 " GOOGLE_DCHECK($type$_IsValid(value));\n" 191 " $name$_.Set(index, value);\n" 192 "}\n" 193 "inline void $classname$::add_$name$($type$ value) {\n" 194 " GOOGLE_DCHECK($type$_IsValid(value));\n" 195 " $name$_.Add(value);\n" 196 "}\n"); 197 printer->Print(variables_, 198 "inline const ::google::protobuf::RepeatedField<int>&\n" 199 "$classname$::$name$() const {\n" 200 " return $name$_;\n" 201 "}\n" 202 "inline ::google::protobuf::RepeatedField<int>*\n" 203 "$classname$::mutable_$name$() {\n" 204 " return &$name$_;\n" 205 "}\n"); 206} 207 208void RepeatedEnumFieldGenerator:: 209GenerateClearingCode(io::Printer* printer) const { 210 printer->Print(variables_, "$name$_.Clear();\n"); 211} 212 213void RepeatedEnumFieldGenerator:: 214GenerateMergingCode(io::Printer* printer) const { 215 printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); 216} 217 218void RepeatedEnumFieldGenerator:: 219GenerateSwappingCode(io::Printer* printer) const { 220 printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); 221} 222 223void RepeatedEnumFieldGenerator:: 224GenerateConstructorCode(io::Printer* printer) const { 225 // Not needed for repeated fields. 226} 227 228void RepeatedEnumFieldGenerator:: 229GenerateMergeFromCodedStream(io::Printer* printer) const { 230 // Don't use ReadRepeatedPrimitive here so that the enum can be validated. 231 printer->Print(variables_, 232 "int value;\n" 233 "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" 234 " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" 235 " input, &value)));\n" 236 "if ($type$_IsValid(value)) {\n" 237 " add_$name$(static_cast< $type$ >(value));\n"); 238 if (HasUnknownFields(descriptor_->file())) { 239 printer->Print(variables_, 240 "} else {\n" 241 " mutable_unknown_fields()->AddVarint($number$, value);\n"); 242 } 243 printer->Print("}\n"); 244} 245 246void RepeatedEnumFieldGenerator:: 247GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { 248 if (!descriptor_->options().packed()) { 249 // We use a non-inlined implementation in this case, since this path will 250 // rarely be executed. 251 printer->Print(variables_, 252 "DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n" 253 " input,\n" 254 " &$type$_IsValid,\n" 255 " this->mutable_$name$())));\n"); 256 } else { 257 printer->Print(variables_, 258 "::google::protobuf::uint32 length;\n" 259 "DO_(input->ReadVarint32(&length));\n" 260 "::google::protobuf::io::CodedInputStream::Limit limit = " 261 "input->PushLimit(length);\n" 262 "while (input->BytesUntilLimit() > 0) {\n" 263 " int value;\n" 264 " DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" 265 " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" 266 " input, &value)));\n" 267 " if ($type$_IsValid(value)) {\n" 268 " add_$name$(static_cast< $type$ >(value));\n" 269 " }\n" 270 "}\n" 271 "input->PopLimit(limit);\n"); 272 } 273} 274 275void RepeatedEnumFieldGenerator:: 276GenerateSerializeWithCachedSizes(io::Printer* printer) const { 277 if (descriptor_->options().packed()) { 278 // Write the tag and the size. 279 printer->Print(variables_, 280 "if (this->$name$_size() > 0) {\n" 281 " ::google::protobuf::internal::WireFormatLite::WriteTag(\n" 282 " $number$,\n" 283 " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" 284 " output);\n" 285 " output->WriteVarint32(_$name$_cached_byte_size_);\n" 286 "}\n"); 287 } 288 printer->Print(variables_, 289 "for (int i = 0; i < this->$name$_size(); i++) {\n"); 290 if (descriptor_->options().packed()) { 291 printer->Print(variables_, 292 " ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n" 293 " this->$name$(i), output);\n"); 294 } else { 295 printer->Print(variables_, 296 " ::google::protobuf::internal::WireFormatLite::WriteEnum(\n" 297 " $number$, this->$name$(i), output);\n"); 298 } 299 printer->Print("}\n"); 300} 301 302void RepeatedEnumFieldGenerator:: 303GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { 304 if (descriptor_->options().packed()) { 305 // Write the tag and the size. 306 printer->Print(variables_, 307 "if (this->$name$_size() > 0) {\n" 308 " target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n" 309 " $number$,\n" 310 " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" 311 " target);\n" 312 " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(" 313 " _$name$_cached_byte_size_, target);\n" 314 "}\n"); 315 } 316 printer->Print(variables_, 317 "for (int i = 0; i < this->$name$_size(); i++) {\n"); 318 if (descriptor_->options().packed()) { 319 printer->Print(variables_, 320 " target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n" 321 " this->$name$(i), target);\n"); 322 } else { 323 printer->Print(variables_, 324 " target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n" 325 " $number$, this->$name$(i), target);\n"); 326 } 327 printer->Print("}\n"); 328} 329 330void RepeatedEnumFieldGenerator:: 331GenerateByteSize(io::Printer* printer) const { 332 printer->Print(variables_, 333 "{\n" 334 " int data_size = 0;\n"); 335 printer->Indent(); 336 printer->Print(variables_, 337 "for (int i = 0; i < this->$name$_size(); i++) {\n" 338 " data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(\n" 339 " this->$name$(i));\n" 340 "}\n"); 341 342 if (descriptor_->options().packed()) { 343 printer->Print(variables_, 344 "if (data_size > 0) {\n" 345 " total_size += $tag_size$ +\n" 346 " ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n" 347 "}\n" 348 "_$name$_cached_byte_size_ = data_size;\n" 349 "total_size += data_size;\n"); 350 } else { 351 printer->Print(variables_, 352 "total_size += $tag_size$ * this->$name$_size() + data_size;\n"); 353 } 354 printer->Outdent(); 355 printer->Print("}\n"); 356} 357 358} // namespace cpp 359} // namespace compiler 360} // namespace protobuf 361} // namespace google 362