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 #include <google/protobuf/compiler/cpp/cpp_map_field.h> 32 #include <google/protobuf/compiler/cpp/cpp_helpers.h> 33 #include <google/protobuf/io/printer.h> 34 #include <google/protobuf/wire_format.h> 35 #include <google/protobuf/stubs/strutil.h> 36 37 namespace google { 38 namespace protobuf { 39 namespace compiler { 40 namespace cpp { 41 IsProto3Field(const FieldDescriptor * field_descriptor)42 bool IsProto3Field(const FieldDescriptor* field_descriptor) { 43 const FileDescriptor* file_descriptor = field_descriptor->file(); 44 return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3; 45 } 46 SetMessageVariables(const FieldDescriptor * descriptor,map<string,string> * variables,const Options & options)47 void SetMessageVariables(const FieldDescriptor* descriptor, 48 map<string, string>* variables, 49 const Options& options) { 50 SetCommonFieldVariables(descriptor, variables, options); 51 (*variables)["type"] = FieldMessageTypeName(descriptor); 52 (*variables)["stream_writer"] = 53 (*variables)["declared_type"] + 54 (HasFastArraySerialization(descriptor->message_type()->file(), options) 55 ? "MaybeToArray" 56 : ""); 57 (*variables)["full_name"] = descriptor->full_name(); 58 59 const FieldDescriptor* key = 60 descriptor->message_type()->FindFieldByName("key"); 61 const FieldDescriptor* val = 62 descriptor->message_type()->FindFieldByName("value"); 63 (*variables)["key_cpp"] = PrimitiveTypeName(key->cpp_type()); 64 switch (val->cpp_type()) { 65 case FieldDescriptor::CPPTYPE_MESSAGE: 66 (*variables)["val_cpp"] = FieldMessageTypeName(val); 67 (*variables)["wrapper"] = "EntryWrapper"; 68 break; 69 case FieldDescriptor::CPPTYPE_ENUM: 70 (*variables)["val_cpp"] = ClassName(val->enum_type(), true); 71 (*variables)["wrapper"] = "EnumEntryWrapper"; 72 break; 73 default: 74 (*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type()); 75 (*variables)["wrapper"] = "EntryWrapper"; 76 } 77 (*variables)["key_wire_type"] = 78 "::google::protobuf::internal::WireFormatLite::TYPE_" + 79 ToUpper(DeclaredTypeMethodName(key->type())); 80 (*variables)["val_wire_type"] = 81 "::google::protobuf::internal::WireFormatLite::TYPE_" + 82 ToUpper(DeclaredTypeMethodName(val->type())); 83 (*variables)["map_classname"] = ClassName(descriptor->message_type(), false); 84 (*variables)["number"] = SimpleItoa(descriptor->number()); 85 (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); 86 87 if (HasDescriptorMethods(descriptor->file(), options)) { 88 (*variables)["lite"] = ""; 89 } else { 90 (*variables)["lite"] = "Lite"; 91 } 92 93 if (!IsProto3Field(descriptor) && 94 val->type() == FieldDescriptor::TYPE_ENUM) { 95 const EnumValueDescriptor* default_value = val->default_value_enum(); 96 (*variables)["default_enum_value"] = Int32ToString(default_value->number()); 97 } else { 98 (*variables)["default_enum_value"] = "0"; 99 } 100 } 101 MapFieldGenerator(const FieldDescriptor * descriptor,const Options & options)102 MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, 103 const Options& options) 104 : FieldGenerator(options), 105 descriptor_(descriptor), 106 dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { 107 SetMessageVariables(descriptor, &variables_, options); 108 } 109 ~MapFieldGenerator()110 MapFieldGenerator::~MapFieldGenerator() {} 111 112 void MapFieldGenerator:: GeneratePrivateMembers(io::Printer * printer) const113 GeneratePrivateMembers(io::Printer* printer) const { 114 printer->Print(variables_, 115 "typedef ::google::protobuf::internal::MapEntryLite<\n" 116 " $key_cpp$, $val_cpp$,\n" 117 " $key_wire_type$,\n" 118 " $val_wire_type$,\n" 119 " $default_enum_value$ >\n" 120 " $map_classname$;\n" 121 "::google::protobuf::internal::MapField$lite$<\n" 122 " $key_cpp$, $val_cpp$,\n" 123 " $key_wire_type$,\n" 124 " $val_wire_type$,\n" 125 " $default_enum_value$ > $name$_;\n"); 126 } 127 128 void MapFieldGenerator:: GenerateAccessorDeclarations(io::Printer * printer) const129 GenerateAccessorDeclarations(io::Printer* printer) const { 130 printer->Print(variables_, 131 "$deprecated_attr$const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" 132 " $name$() const;\n" 133 "$deprecated_attr$::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" 134 " mutable_$name$();\n"); 135 } 136 137 void MapFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer * printer,bool is_inline) const138 GenerateInlineAccessorDefinitions(io::Printer* printer, 139 bool is_inline) const { 140 map<string, string> variables(variables_); 141 variables["inline"] = is_inline ? "inline" : ""; 142 printer->Print(variables, 143 "$inline$ const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" 144 "$classname$::$name$() const {\n" 145 " // @@protoc_insertion_point(field_map:$full_name$)\n" 146 " return $name$_.GetMap();\n" 147 "}\n" 148 "$inline$ ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" 149 "$classname$::mutable_$name$() {\n" 150 " // @@protoc_insertion_point(field_mutable_map:$full_name$)\n" 151 " return $name$_.MutableMap();\n" 152 "}\n"); 153 } 154 155 void MapFieldGenerator:: GenerateClearingCode(io::Printer * printer) const156 GenerateClearingCode(io::Printer* printer) const { 157 map<string, string> variables(variables_); 158 variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; 159 printer->Print(variables, "$this_message$$name$_.Clear();\n"); 160 } 161 162 void MapFieldGenerator:: GenerateMergingCode(io::Printer * printer) const163 GenerateMergingCode(io::Printer* printer) const { 164 printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); 165 } 166 167 void MapFieldGenerator:: GenerateSwappingCode(io::Printer * printer) const168 GenerateSwappingCode(io::Printer* printer) const { 169 printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); 170 } 171 172 void MapFieldGenerator:: GenerateConstructorCode(io::Printer * printer) const173 GenerateConstructorCode(io::Printer* printer) const { 174 if (HasDescriptorMethods(descriptor_->file(), options_)) { 175 printer->Print(variables_, 176 "$name$_.SetAssignDescriptorCallback(\n" 177 " protobuf_AssignDescriptorsOnce);\n" 178 "$name$_.SetEntryDescriptor(\n" 179 " &$type$_descriptor_);\n"); 180 } 181 } 182 183 void MapFieldGenerator:: GenerateMergeFromCodedStream(io::Printer * printer) const184 GenerateMergeFromCodedStream(io::Printer* printer) const { 185 const FieldDescriptor* value_field = 186 descriptor_->message_type()->FindFieldByName("value"); 187 printer->Print(variables_, 188 "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n"); 189 190 if (IsProto3Field(descriptor_) || 191 value_field->type() != FieldDescriptor::TYPE_ENUM) { 192 printer->Print(variables_, 193 "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n" 194 " input, entry.get()));\n"); 195 switch (value_field->cpp_type()) { 196 case FieldDescriptor::CPPTYPE_MESSAGE: 197 printer->Print(variables_, 198 "(*mutable_$name$())[entry->key()].Swap(" 199 "entry->mutable_value());\n"); 200 break; 201 case FieldDescriptor::CPPTYPE_ENUM: 202 printer->Print(variables_, 203 "(*mutable_$name$())[entry->key()] =\n" 204 " static_cast< $val_cpp$ >(*entry->mutable_value());\n"); 205 break; 206 default: 207 printer->Print(variables_, 208 "(*mutable_$name$())[entry->key()] = *entry->mutable_value();\n"); 209 break; 210 } 211 } else { 212 printer->Print(variables_, 213 "{\n" 214 " ::std::string data;\n" 215 " DO_(::google::protobuf::internal::WireFormatLite::ReadString(input, &data));\n" 216 " DO_(entry->ParseFromString(data));\n" 217 " if ($val_cpp$_IsValid(*entry->mutable_value())) {\n" 218 " (*mutable_$name$())[entry->key()] =\n" 219 " static_cast< $val_cpp$ >(*entry->mutable_value());\n" 220 " } else {\n"); 221 if (HasDescriptorMethods(descriptor_->file(), options_)) { 222 printer->Print(variables_, 223 " mutable_unknown_fields()" 224 "->AddLengthDelimited($number$, data);\n"); 225 } else { 226 printer->Print(variables_, 227 " unknown_fields_stream.WriteVarint32($tag$);\n" 228 " unknown_fields_stream.WriteVarint32(data.size());\n" 229 " unknown_fields_stream.WriteString(data);\n"); 230 } 231 232 233 printer->Print(variables_, 234 " }\n" 235 "}\n"); 236 } 237 238 const FieldDescriptor* key_field = 239 descriptor_->message_type()->FindFieldByName("key"); 240 if (key_field->type() == FieldDescriptor::TYPE_STRING) { 241 GenerateUtf8CheckCodeForString( 242 key_field, options_, true, variables_, 243 "entry->key().data(), entry->key().length(),\n", printer); 244 } 245 if (value_field->type() == FieldDescriptor::TYPE_STRING) { 246 GenerateUtf8CheckCodeForString(value_field, options_, true, variables_, 247 "entry->mutable_value()->data(),\n" 248 "entry->mutable_value()->length(),\n", 249 printer); 250 } 251 252 // If entry is allocated by arena, its desctructor should be avoided. 253 if (SupportsArenas(descriptor_)) { 254 printer->Print(variables_, 255 "if (entry->GetArena() != NULL) entry.release();\n"); 256 } 257 } 258 259 void MapFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer * printer) const260 GenerateSerializeWithCachedSizes(io::Printer* printer) const { 261 printer->Print(variables_, 262 "{\n" 263 " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" 264 " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" 265 " it = this->$name$().begin();\n" 266 " it != this->$name$().end(); ++it) {\n"); 267 268 // If entry is allocated by arena, its desctructor should be avoided. 269 if (SupportsArenas(descriptor_)) { 270 printer->Print(variables_, 271 " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" 272 " entry.release();\n" 273 " }\n"); 274 } 275 276 printer->Print(variables_, 277 " entry.reset($name$_.New$wrapper$(it->first, it->second));\n" 278 " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" 279 " $number$, *entry, output);\n"); 280 281 printer->Indent(); 282 printer->Indent(); 283 284 const FieldDescriptor* key_field = 285 descriptor_->message_type()->FindFieldByName("key"); 286 const FieldDescriptor* value_field = 287 descriptor_->message_type()->FindFieldByName("value"); 288 if (key_field->type() == FieldDescriptor::TYPE_STRING) { 289 GenerateUtf8CheckCodeForString(key_field, options_, false, variables_, 290 "it->first.data(), it->first.length(),\n", 291 printer); 292 } 293 if (value_field->type() == FieldDescriptor::TYPE_STRING) { 294 GenerateUtf8CheckCodeForString(value_field, options_, false, variables_, 295 "it->second.data(), it->second.length(),\n", 296 printer); 297 } 298 299 printer->Outdent(); 300 printer->Outdent(); 301 302 printer->Print( 303 " }\n"); 304 305 // If entry is allocated by arena, its desctructor should be avoided. 306 if (SupportsArenas(descriptor_)) { 307 printer->Print(variables_, 308 " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" 309 " entry.release();\n" 310 " }\n"); 311 } 312 313 printer->Print("}\n"); 314 } 315 316 void MapFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer * printer) const317 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { 318 printer->Print(variables_, 319 "{\n" 320 " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" 321 " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" 322 " it = this->$name$().begin();\n" 323 " it != this->$name$().end(); ++it) {\n"); 324 325 // If entry is allocated by arena, its desctructor should be avoided. 326 if (SupportsArenas(descriptor_)) { 327 printer->Print(variables_, 328 " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" 329 " entry.release();\n" 330 " }\n"); 331 } 332 333 printer->Print(variables_, 334 " entry.reset($name$_.New$wrapper$(it->first, it->second));\n" 335 " target = ::google::protobuf::internal::WireFormatLite::\n" 336 " Write$declared_type$NoVirtualToArray(\n" 337 " $number$, *entry, target);\n"); 338 339 printer->Indent(); 340 printer->Indent(); 341 342 const FieldDescriptor* key_field = 343 descriptor_->message_type()->FindFieldByName("key"); 344 const FieldDescriptor* value_field = 345 descriptor_->message_type()->FindFieldByName("value"); 346 if (key_field->type() == FieldDescriptor::TYPE_STRING) { 347 GenerateUtf8CheckCodeForString(key_field, options_, false, variables_, 348 "it->first.data(), it->first.length(),\n", 349 printer); 350 } 351 if (value_field->type() == FieldDescriptor::TYPE_STRING) { 352 GenerateUtf8CheckCodeForString(value_field, options_, false, variables_, 353 "it->second.data(), it->second.length(),\n", 354 printer); 355 } 356 357 printer->Outdent(); 358 printer->Outdent(); 359 printer->Print( 360 " }\n"); 361 362 // If entry is allocated by arena, its desctructor should be avoided. 363 if (SupportsArenas(descriptor_)) { 364 printer->Print(variables_, 365 " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" 366 " entry.release();\n" 367 " }\n"); 368 } 369 370 printer->Print("}\n"); 371 } 372 373 void MapFieldGenerator:: GenerateByteSize(io::Printer * printer) const374 GenerateByteSize(io::Printer* printer) const { 375 printer->Print(variables_, 376 "total_size += $tag_size$ * this->$name$_size();\n" 377 "{\n" 378 " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" 379 " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" 380 " it = this->$name$().begin();\n" 381 " it != this->$name$().end(); ++it) {\n"); 382 383 // If entry is allocated by arena, its desctructor should be avoided. 384 if (SupportsArenas(descriptor_)) { 385 printer->Print(variables_, 386 " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" 387 " entry.release();\n" 388 " }\n"); 389 } 390 391 printer->Print(variables_, 392 " entry.reset($name$_.New$wrapper$(it->first, it->second));\n" 393 " total_size += ::google::protobuf::internal::WireFormatLite::\n" 394 " $declared_type$SizeNoVirtual(*entry);\n" 395 " }\n"); 396 397 // If entry is allocated by arena, its desctructor should be avoided. 398 if (SupportsArenas(descriptor_)) { 399 printer->Print(variables_, 400 " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" 401 " entry.release();\n" 402 " }\n"); 403 } 404 405 printer->Print("}\n"); 406 } 407 408 } // namespace cpp 409 } // namespace compiler 410 } // namespace protobuf 411 } // namespace google 412