From ceb561d65bfe234a301979a7e3f7ddc244d349b3 Mon Sep 17 00:00:00 2001 From: "kenton@google.com" Date: Thu, 25 Jun 2009 19:05:36 +0000 Subject: Add Swap(), SwapElements(), and RemoveLast() to Reflection. Patch by Scott Stafford. --- src/google/protobuf/compiler/cpp/cpp_message.cc | 35 ++- src/google/protobuf/descriptor.pb.cc | 334 ++++++++++----------- src/google/protobuf/extension_set.cc | 82 +++++ src/google/protobuf/extension_set.h | 3 + .../protobuf/generated_message_reflection.cc | 89 +++++- src/google/protobuf/generated_message_reflection.h | 4 + .../generated_message_reflection_unittest.cc | 116 +++++++ src/google/protobuf/message.h | 21 +- src/google/protobuf/repeated_field.h | 57 +++- src/google/protobuf/test_util.cc | 315 +++++++++++++++++++ src/google/protobuf/test_util.h | 14 + 11 files changed, 884 insertions(+), 186 deletions(-) (limited to 'src/google/protobuf') diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 95f20a60..9852ee91 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -684,13 +684,13 @@ GenerateClassMethods(io::Printer* printer) { GenerateCopyFrom(printer); printer->Print("\n"); - GenerateSwap(printer); - printer->Print("\n"); - GenerateIsInitialized(printer); printer->Print("\n"); } + GenerateSwap(printer); + printer->Print("\n"); + printer->Print( "const ::google::protobuf::Descriptor* $classname$::GetDescriptor() const {\n" " return descriptor();\n" @@ -967,22 +967,27 @@ GenerateSwap(io::Printer* printer) { printer->Print("if (other != this) {\n"); printer->Indent(); - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - field_generators_.get(field).GenerateSwappingCode(printer); - } + if ( descriptor_->file()->options().optimize_for() == FileOptions::SPEED ) { + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + field_generators_.get(field).GenerateSwappingCode(printer); + } - for (int i = 0; i < (descriptor_->field_count() + 31) / 32; ++i) { - printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n", - "i", SimpleItoa(i)); - } + for (int i = 0; i < (descriptor_->field_count() + 31) / 32; ++i) { + printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n", + "i", SimpleItoa(i)); + } - printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); - printer->Print("std::swap(_cached_size_, other->_cached_size_);\n"); - if (descriptor_->extension_range_count() > 0) { - printer->Print("_extensions_.Swap(&other->_extensions_);\n"); + printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); + printer->Print("std::swap(_cached_size_, other->_cached_size_);\n"); + if (descriptor_->extension_range_count() > 0) { + printer->Print("_extensions_.Swap(&other->_extensions_);\n"); + } + } else { + printer->Print("GetReflection()->Swap(this, other);"); } + printer->Outdent(); printer->Print("}\n"); printer->Outdent(); diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index d4a7666b..0caed839 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -807,6 +807,14 @@ void FileDescriptorSet::CopyFrom(const FileDescriptorSet& from) { MergeFrom(from); } +bool FileDescriptorSet::IsInitialized() const { + + for (int i = 0; i < file_size(); i++) { + if (!this->file(i).IsInitialized()) return false; + } + return true; +} + void FileDescriptorSet::Swap(FileDescriptorSet* other) { if (other != this) { file_.Swap(&other->file_); @@ -816,14 +824,6 @@ void FileDescriptorSet::Swap(FileDescriptorSet* other) { } } -bool FileDescriptorSet::IsInitialized() const { - - for (int i = 0; i < file_size(); i++) { - if (!this->file(i).IsInitialized()) return false; - } - return true; -} - const ::google::protobuf::Descriptor* FileDescriptorSet::GetDescriptor() const { return descriptor(); } @@ -1274,22 +1274,6 @@ void FileDescriptorProto::CopyFrom(const FileDescriptorProto& from) { MergeFrom(from); } -void FileDescriptorProto::Swap(FileDescriptorProto* other) { - if (other != this) { - std::swap(name_, other->name_); - std::swap(package_, other->package_); - dependency_.Swap(&other->dependency_); - message_type_.Swap(&other->message_type_); - enum_type_.Swap(&other->enum_type_); - service_.Swap(&other->service_); - extension_.Swap(&other->extension_); - std::swap(options_, other->options_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - } -} - bool FileDescriptorProto::IsInitialized() const { for (int i = 0; i < message_type_size(); i++) { @@ -1310,6 +1294,22 @@ bool FileDescriptorProto::IsInitialized() const { return true; } +void FileDescriptorProto::Swap(FileDescriptorProto* other) { + if (other != this) { + std::swap(name_, other->name_); + std::swap(package_, other->package_); + dependency_.Swap(&other->dependency_); + message_type_.Swap(&other->message_type_); + enum_type_.Swap(&other->enum_type_); + service_.Swap(&other->service_); + extension_.Swap(&other->extension_); + std::swap(options_, other->options_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + const ::google::protobuf::Descriptor* FileDescriptorProto::GetDescriptor() const { return descriptor(); } @@ -1536,6 +1536,11 @@ void DescriptorProto_ExtensionRange::CopyFrom(const DescriptorProto_ExtensionRan MergeFrom(from); } +bool DescriptorProto_ExtensionRange::IsInitialized() const { + + return true; +} + void DescriptorProto_ExtensionRange::Swap(DescriptorProto_ExtensionRange* other) { if (other != this) { std::swap(start_, other->start_); @@ -1546,11 +1551,6 @@ void DescriptorProto_ExtensionRange::Swap(DescriptorProto_ExtensionRange* other) } } -bool DescriptorProto_ExtensionRange::IsInitialized() const { - - return true; -} - const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange::GetDescriptor() const { return descriptor(); } @@ -1960,21 +1960,6 @@ void DescriptorProto::CopyFrom(const DescriptorProto& from) { MergeFrom(from); } -void DescriptorProto::Swap(DescriptorProto* other) { - if (other != this) { - std::swap(name_, other->name_); - field_.Swap(&other->field_); - extension_.Swap(&other->extension_); - nested_type_.Swap(&other->nested_type_); - enum_type_.Swap(&other->enum_type_); - extension_range_.Swap(&other->extension_range_); - std::swap(options_, other->options_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - } -} - bool DescriptorProto::IsInitialized() const { for (int i = 0; i < field_size(); i++) { @@ -1995,6 +1980,21 @@ bool DescriptorProto::IsInitialized() const { return true; } +void DescriptorProto::Swap(DescriptorProto* other) { + if (other != this) { + std::swap(name_, other->name_); + field_.Swap(&other->field_); + extension_.Swap(&other->extension_); + nested_type_.Swap(&other->nested_type_); + enum_type_.Swap(&other->enum_type_); + extension_range_.Swap(&other->extension_range_); + std::swap(options_, other->options_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + const ::google::protobuf::Descriptor* DescriptorProto::GetDescriptor() const { return descriptor(); } @@ -2546,6 +2546,14 @@ void FieldDescriptorProto::CopyFrom(const FieldDescriptorProto& from) { MergeFrom(from); } +bool FieldDescriptorProto::IsInitialized() const { + + if (has_options()) { + if (!this->options().IsInitialized()) return false; + } + return true; +} + void FieldDescriptorProto::Swap(FieldDescriptorProto* other) { if (other != this) { std::swap(name_, other->name_); @@ -2562,14 +2570,6 @@ void FieldDescriptorProto::Swap(FieldDescriptorProto* other) { } } -bool FieldDescriptorProto::IsInitialized() const { - - if (has_options()) { - if (!this->options().IsInitialized()) return false; - } - return true; -} - const ::google::protobuf::Descriptor* FieldDescriptorProto::GetDescriptor() const { return descriptor(); } @@ -2839,17 +2839,6 @@ void EnumDescriptorProto::CopyFrom(const EnumDescriptorProto& from) { MergeFrom(from); } -void EnumDescriptorProto::Swap(EnumDescriptorProto* other) { - if (other != this) { - std::swap(name_, other->name_); - value_.Swap(&other->value_); - std::swap(options_, other->options_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - } -} - bool EnumDescriptorProto::IsInitialized() const { for (int i = 0; i < value_size(); i++) { @@ -2861,6 +2850,17 @@ bool EnumDescriptorProto::IsInitialized() const { return true; } +void EnumDescriptorProto::Swap(EnumDescriptorProto* other) { + if (other != this) { + std::swap(name_, other->name_); + value_.Swap(&other->value_); + std::swap(options_, other->options_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + const ::google::protobuf::Descriptor* EnumDescriptorProto::GetDescriptor() const { return descriptor(); } @@ -3132,6 +3132,14 @@ void EnumValueDescriptorProto::CopyFrom(const EnumValueDescriptorProto& from) { MergeFrom(from); } +bool EnumValueDescriptorProto::IsInitialized() const { + + if (has_options()) { + if (!this->options().IsInitialized()) return false; + } + return true; +} + void EnumValueDescriptorProto::Swap(EnumValueDescriptorProto* other) { if (other != this) { std::swap(name_, other->name_); @@ -3143,14 +3151,6 @@ void EnumValueDescriptorProto::Swap(EnumValueDescriptorProto* other) { } } -bool EnumValueDescriptorProto::IsInitialized() const { - - if (has_options()) { - if (!this->options().IsInitialized()) return false; - } - return true; -} - const ::google::protobuf::Descriptor* EnumValueDescriptorProto::GetDescriptor() const { return descriptor(); } @@ -3420,17 +3420,6 @@ void ServiceDescriptorProto::CopyFrom(const ServiceDescriptorProto& from) { MergeFrom(from); } -void ServiceDescriptorProto::Swap(ServiceDescriptorProto* other) { - if (other != this) { - std::swap(name_, other->name_); - method_.Swap(&other->method_); - std::swap(options_, other->options_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - } -} - bool ServiceDescriptorProto::IsInitialized() const { for (int i = 0; i < method_size(); i++) { @@ -3442,6 +3431,17 @@ bool ServiceDescriptorProto::IsInitialized() const { return true; } +void ServiceDescriptorProto::Swap(ServiceDescriptorProto* other) { + if (other != this) { + std::swap(name_, other->name_); + method_.Swap(&other->method_); + std::swap(options_, other->options_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + const ::google::protobuf::Descriptor* ServiceDescriptorProto::GetDescriptor() const { return descriptor(); } @@ -3760,6 +3760,14 @@ void MethodDescriptorProto::CopyFrom(const MethodDescriptorProto& from) { MergeFrom(from); } +bool MethodDescriptorProto::IsInitialized() const { + + if (has_options()) { + if (!this->options().IsInitialized()) return false; + } + return true; +} + void MethodDescriptorProto::Swap(MethodDescriptorProto* other) { if (other != this) { std::swap(name_, other->name_); @@ -3772,14 +3780,6 @@ void MethodDescriptorProto::Swap(MethodDescriptorProto* other) { } } -bool MethodDescriptorProto::IsInitialized() const { - - if (has_options()) { - if (!this->options().IsInitialized()) return false; - } - return true; -} - const ::google::protobuf::Descriptor* MethodDescriptorProto::GetDescriptor() const { return descriptor(); } @@ -4163,6 +4163,15 @@ void FileOptions::CopyFrom(const FileOptions& from) { MergeFrom(from); } +bool FileOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + void FileOptions::Swap(FileOptions* other) { if (other != this) { std::swap(java_package_, other->java_package_); @@ -4177,15 +4186,6 @@ void FileOptions::Swap(FileOptions* other) { } } -bool FileOptions::IsInitialized() const { - - for (int i = 0; i < uninterpreted_option_size(); i++) { - if (!this->uninterpreted_option(i).IsInitialized()) return false; - } - - if (!_extensions_.IsInitialized()) return false; return true; -} - const ::google::protobuf::Descriptor* FileOptions::GetDescriptor() const { return descriptor(); } @@ -4425,6 +4425,15 @@ void MessageOptions::CopyFrom(const MessageOptions& from) { MergeFrom(from); } +bool MessageOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + void MessageOptions::Swap(MessageOptions* other) { if (other != this) { std::swap(message_set_wire_format_, other->message_set_wire_format_); @@ -4436,15 +4445,6 @@ void MessageOptions::Swap(MessageOptions* other) { } } -bool MessageOptions::IsInitialized() const { - - for (int i = 0; i < uninterpreted_option_size(); i++) { - if (!this->uninterpreted_option(i).IsInitialized()) return false; - } - - if (!_extensions_.IsInitialized()) return false; return true; -} - const ::google::protobuf::Descriptor* MessageOptions::GetDescriptor() const { return descriptor(); } @@ -4821,6 +4821,15 @@ void FieldOptions::CopyFrom(const FieldOptions& from) { MergeFrom(from); } +bool FieldOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + void FieldOptions::Swap(FieldOptions* other) { if (other != this) { std::swap(ctype_, other->ctype_); @@ -4835,15 +4844,6 @@ void FieldOptions::Swap(FieldOptions* other) { } } -bool FieldOptions::IsInitialized() const { - - for (int i = 0; i < uninterpreted_option_size(); i++) { - if (!this->uninterpreted_option(i).IsInitialized()) return false; - } - - if (!_extensions_.IsInitialized()) return false; return true; -} - const ::google::protobuf::Descriptor* FieldOptions::GetDescriptor() const { return descriptor(); } @@ -5043,6 +5043,15 @@ void EnumOptions::CopyFrom(const EnumOptions& from) { MergeFrom(from); } +bool EnumOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + void EnumOptions::Swap(EnumOptions* other) { if (other != this) { uninterpreted_option_.Swap(&other->uninterpreted_option_); @@ -5053,15 +5062,6 @@ void EnumOptions::Swap(EnumOptions* other) { } } -bool EnumOptions::IsInitialized() const { - - for (int i = 0; i < uninterpreted_option_size(); i++) { - if (!this->uninterpreted_option(i).IsInitialized()) return false; - } - - if (!_extensions_.IsInitialized()) return false; return true; -} - const ::google::protobuf::Descriptor* EnumOptions::GetDescriptor() const { return descriptor(); } @@ -5261,6 +5261,15 @@ void EnumValueOptions::CopyFrom(const EnumValueOptions& from) { MergeFrom(from); } +bool EnumValueOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + void EnumValueOptions::Swap(EnumValueOptions* other) { if (other != this) { uninterpreted_option_.Swap(&other->uninterpreted_option_); @@ -5271,15 +5280,6 @@ void EnumValueOptions::Swap(EnumValueOptions* other) { } } -bool EnumValueOptions::IsInitialized() const { - - for (int i = 0; i < uninterpreted_option_size(); i++) { - if (!this->uninterpreted_option(i).IsInitialized()) return false; - } - - if (!_extensions_.IsInitialized()) return false; return true; -} - const ::google::protobuf::Descriptor* EnumValueOptions::GetDescriptor() const { return descriptor(); } @@ -5479,6 +5479,15 @@ void ServiceOptions::CopyFrom(const ServiceOptions& from) { MergeFrom(from); } +bool ServiceOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + void ServiceOptions::Swap(ServiceOptions* other) { if (other != this) { uninterpreted_option_.Swap(&other->uninterpreted_option_); @@ -5489,15 +5498,6 @@ void ServiceOptions::Swap(ServiceOptions* other) { } } -bool ServiceOptions::IsInitialized() const { - - for (int i = 0; i < uninterpreted_option_size(); i++) { - if (!this->uninterpreted_option(i).IsInitialized()) return false; - } - - if (!_extensions_.IsInitialized()) return false; return true; -} - const ::google::protobuf::Descriptor* ServiceOptions::GetDescriptor() const { return descriptor(); } @@ -5697,6 +5697,15 @@ void MethodOptions::CopyFrom(const MethodOptions& from) { MergeFrom(from); } +bool MethodOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + void MethodOptions::Swap(MethodOptions* other) { if (other != this) { uninterpreted_option_.Swap(&other->uninterpreted_option_); @@ -5707,15 +5716,6 @@ void MethodOptions::Swap(MethodOptions* other) { } } -bool MethodOptions::IsInitialized() const { - - for (int i = 0; i < uninterpreted_option_size(); i++) { - if (!this->uninterpreted_option(i).IsInitialized()) return false; - } - - if (!_extensions_.IsInitialized()) return false; return true; -} - const ::google::protobuf::Descriptor* MethodOptions::GetDescriptor() const { return descriptor(); } @@ -5945,6 +5945,12 @@ void UninterpretedOption_NamePart::CopyFrom(const UninterpretedOption_NamePart& MergeFrom(from); } +bool UninterpretedOption_NamePart::IsInitialized() const { + if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false; + + return true; +} + void UninterpretedOption_NamePart::Swap(UninterpretedOption_NamePart* other) { if (other != this) { std::swap(name_part_, other->name_part_); @@ -5955,12 +5961,6 @@ void UninterpretedOption_NamePart::Swap(UninterpretedOption_NamePart* other) { } } -bool UninterpretedOption_NamePart::IsInitialized() const { - if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false; - - return true; -} - const ::google::protobuf::Descriptor* UninterpretedOption_NamePart::GetDescriptor() const { return descriptor(); } @@ -6342,6 +6342,14 @@ void UninterpretedOption::CopyFrom(const UninterpretedOption& from) { MergeFrom(from); } +bool UninterpretedOption::IsInitialized() const { + + for (int i = 0; i < name_size(); i++) { + if (!this->name(i).IsInitialized()) return false; + } + return true; +} + void UninterpretedOption::Swap(UninterpretedOption* other) { if (other != this) { name_.Swap(&other->name_); @@ -6356,14 +6364,6 @@ void UninterpretedOption::Swap(UninterpretedOption* other) { } } -bool UninterpretedOption::IsInitialized() const { - - for (int i = 0; i < name_size(); i++) { - if (!this->name(i).IsInitialized()) return false; - } - return true; -} - const ::google::protobuf::Descriptor* UninterpretedOption::GetDescriptor() const { return descriptor(); } diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index f45eafa5..61b8daae 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -497,6 +497,88 @@ Message* ExtensionSet::AddMessage(int number, FieldType type, #undef GOOGLE_DCHECK_TYPE +void ExtensionSet::RemoveLast(int number) { + map::iterator iter = extensions_.find(number); + GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; + + Extension* extension = &iter->second; + GOOGLE_DCHECK(extension->is_repeated); + + switch(cpp_type(extension->type)) { + case FieldDescriptor::CPPTYPE_INT32: + extension->repeated_int32_value->RemoveLast(); + break; + case FieldDescriptor::CPPTYPE_INT64: + extension->repeated_int64_value->RemoveLast(); + break; + case FieldDescriptor::CPPTYPE_UINT32: + extension->repeated_uint32_value->RemoveLast(); + break; + case FieldDescriptor::CPPTYPE_UINT64: + extension->repeated_uint64_value->RemoveLast(); + break; + case FieldDescriptor::CPPTYPE_FLOAT: + extension->repeated_float_value->RemoveLast(); + break; + case FieldDescriptor::CPPTYPE_DOUBLE: + extension->repeated_double_value->RemoveLast(); + break; + case FieldDescriptor::CPPTYPE_BOOL: + extension->repeated_bool_value->RemoveLast(); + break; + case FieldDescriptor::CPPTYPE_ENUM: + extension->repeated_enum_value->RemoveLast(); + break; + case FieldDescriptor::CPPTYPE_STRING: + extension->repeated_string_value->RemoveLast(); + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + extension->repeated_message_value->RemoveLast(); + break; + } +} + +void ExtensionSet::SwapElements(int number, int index1, int index2) { + map::iterator iter = extensions_.find(number); + GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; + + Extension* extension = &iter->second; + GOOGLE_DCHECK(extension->is_repeated); + + switch(cpp_type(extension->type)) { + case FieldDescriptor::CPPTYPE_INT32: + extension->repeated_int32_value->SwapElements(index1, index2); + break; + case FieldDescriptor::CPPTYPE_INT64: + extension->repeated_int64_value->SwapElements(index1, index2); + break; + case FieldDescriptor::CPPTYPE_UINT32: + extension->repeated_uint32_value->SwapElements(index1, index2); + break; + case FieldDescriptor::CPPTYPE_UINT64: + extension->repeated_uint64_value->SwapElements(index1, index2); + break; + case FieldDescriptor::CPPTYPE_FLOAT: + extension->repeated_float_value->SwapElements(index1, index2); + break; + case FieldDescriptor::CPPTYPE_DOUBLE: + extension->repeated_double_value->SwapElements(index1, index2); + break; + case FieldDescriptor::CPPTYPE_BOOL: + extension->repeated_bool_value->SwapElements(index1, index2); + break; + case FieldDescriptor::CPPTYPE_ENUM: + extension->repeated_enum_value->SwapElements(index1, index2); + break; + case FieldDescriptor::CPPTYPE_STRING: + extension->repeated_string_value->SwapElements(index1, index2); + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + extension->repeated_message_value->SwapElements(index1, index2); + break; + } +} + // =================================================================== void ExtensionSet::Clear() { diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index a99b17cb..e04614cc 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -228,6 +228,9 @@ class LIBPROTOBUF_EXPORT ExtensionSet { const Descriptor* message_type, MessageFactory* factory); + void RemoveLast(int number); + void SwapElements(int number, int index1, int index2); + // ----------------------------------------------------------------- // TODO(kenton): Hardcore memory management accessors diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index ffeaf62d..0cd367de 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -269,6 +269,61 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { return total_size; } +void GeneratedMessageReflection::Swap( + Message* message1, + Message* message2) const { + if (message1 == message2) return; + + GOOGLE_CHECK_EQ(message1->GetReflection(), this) + << "Tried to swap using reflection object incompatible with message1."; + + GOOGLE_CHECK_EQ(message2->GetReflection(), this) + << "Tried to swap using reflection object incompatible with message2."; + + uint32* has_bits1 = MutableHasBits(message1); + uint32* has_bits2 = MutableHasBits(message2); + int has_bits_size = (descriptor_->field_count() + 31) / 32; + + for (int i = 0; i < has_bits_size; i++) { + std::swap(has_bits1[i], has_bits2[i]); + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (field->is_repeated()) { + MutableRaw(message1, field)->GenericSwap( + MutableRaw(message2, field)); + } else { + switch (field->cpp_type()) { +#define SWAP_VALUES(CPPTYPE, TYPE) \ + case FieldDescriptor::CPPTYPE_##CPPTYPE: \ + swap(*MutableRaw(message1, field), \ + *MutableRaw(message2, field)); \ + break; + SWAP_VALUES(INT32 , int32 ); + SWAP_VALUES(INT64 , int64 ); + SWAP_VALUES(UINT32, uint32); + SWAP_VALUES(UINT64, uint64); + SWAP_VALUES(FLOAT , float ); + SWAP_VALUES(DOUBLE, double); + SWAP_VALUES(BOOL , bool ); + SWAP_VALUES(ENUM , int32 ); + SWAP_VALUES(STRING, string*); + SWAP_VALUES(MESSAGE, Message*); +#undef SWAP_PRIMITIVE_VALUES + default: + GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type(); + } + } + } + + if (extensions_offset_ != -1) { + MutableExtensionSet(message1)->Swap(MutableExtensionSet(message2)); + } + + MutableUnknownFields(message1)->Swap(MutableUnknownFields(message2)); +} + // ------------------------------------------------------------------- bool GeneratedMessageReflection::HasField(const Message& message, @@ -285,8 +340,8 @@ bool GeneratedMessageReflection::HasField(const Message& message, int GeneratedMessageReflection::FieldSize(const Message& message, const FieldDescriptor* field) const { - USAGE_CHECK_MESSAGE_TYPE(HasField); - USAGE_CHECK_REPEATED(HasField); + USAGE_CHECK_MESSAGE_TYPE(FieldSize); + USAGE_CHECK_REPEATED(FieldSize); if (field->is_extension()) { return GetExtensionSet(message).ExtensionSize(field->number()); @@ -350,6 +405,36 @@ void GeneratedMessageReflection::ClearField( } } +void GeneratedMessageReflection::RemoveLast( + Message* message, + const FieldDescriptor* field) const { + USAGE_CHECK_MESSAGE_TYPE(RemoveLast); + USAGE_CHECK_REPEATED(RemoveLast); + + if (field->is_extension()) { + MutableExtensionSet(message)->RemoveLast(field->number()); + } else { + MutableRaw(message, field)->GenericRemoveLast(); + } +} + +void GeneratedMessageReflection::SwapElements( + Message* message, + const FieldDescriptor* field, + int index1, + int index2) const { + USAGE_CHECK_MESSAGE_TYPE(Swap); + USAGE_CHECK_REPEATED(Swap); + + if (field->is_extension()) { + MutableExtensionSet(message)->SwapElements( + field->number(), index1, index2); + } else { + MutableRaw(message, field)->GenericSwapElements( + index1, index2); + } +} + namespace { // Comparison functor for sorting FieldDescriptors by field number. struct FieldNumberSorter { diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index 66f8c474..702f189e 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -140,6 +140,10 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { bool HasField(const Message& message, const FieldDescriptor* field) const; int FieldSize(const Message& message, const FieldDescriptor* field) const; void ClearField(Message* message, const FieldDescriptor* field) const; + void RemoveLast(Message* message, const FieldDescriptor* field) const; + void Swap(Message* message1, Message* message2) const; + void SwapElements(Message* message, const FieldDescriptor* field, + int index1, int index2) const; void ListFields(const Message& message, vector* output) const; diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc index 8e4ae96f..a03bcdb7 100644 --- a/src/google/protobuf/generated_message_reflection_unittest.cc +++ b/src/google/protobuf/generated_message_reflection_unittest.cc @@ -146,6 +146,122 @@ TEST(GeneratedMessageReflectionTest, DefaultsAfterClear) { &reflection->GetMessage(message, F("optional_import_message"))); } + +TEST(GeneratedMessageReflectionTest, Swap) { + unittest::TestAllTypes message1; + unittest::TestAllTypes message2; + + TestUtil::SetAllFields(&message1); + + const Reflection* reflection = message1.GetReflection(); + reflection->Swap(&message1, &message2); + + TestUtil::ExpectClear(message1); + TestUtil::ExpectAllFieldsSet(message2); +} + +TEST(GeneratedMessageReflectionTest, SwapWithBothSet) { + unittest::TestAllTypes message1; + unittest::TestAllTypes message2; + + TestUtil::SetAllFields(&message1); + TestUtil::SetAllFields(&message2); + TestUtil::ModifyRepeatedFields(&message2); + + const Reflection* reflection = message1.GetReflection(); + reflection->Swap(&message1, &message2); + + TestUtil::ExpectRepeatedFieldsModified(message1); + TestUtil::ExpectAllFieldsSet(message2); + + message1.set_optional_int32(532819); + + reflection->Swap(&message1, &message2); + + EXPECT_EQ(532819, message2.optional_int32()); +} + +TEST(GeneratedMessageReflectionTest, SwapExtensions) { + unittest::TestAllExtensions message1; + unittest::TestAllExtensions message2; + + TestUtil::SetAllExtensions(&message1); + + const Reflection* reflection = message1.GetReflection(); + reflection->Swap(&message1, &message2); + + TestUtil::ExpectExtensionsClear(message1); + TestUtil::ExpectAllExtensionsSet(message2); +} + +TEST(GeneratedMessageReflectionTest, SwapUnknown) { + unittest::TestEmptyMessage message1, message2; + + message1.mutable_unknown_fields()->AddVarint(1234, 1); + + EXPECT_EQ(1, message1.unknown_fields().field_count()); + EXPECT_EQ(0, message2.unknown_fields().field_count()); + const Reflection* reflection = message1.GetReflection(); + reflection->Swap(&message1, &message2); + EXPECT_EQ(0, message1.unknown_fields().field_count()); + EXPECT_EQ(1, message2.unknown_fields().field_count()); +} + +TEST(GeneratedMessageReflectionTest, RemoveLast) { + unittest::TestAllTypes message; + TestUtil::ReflectionTester reflection_tester( + unittest::TestAllTypes::descriptor()); + + TestUtil::SetAllFields(&message); + + reflection_tester.RemoveLastRepeatedsViaReflection(&message); + + TestUtil::ExpectLastRepeatedsRemoved(message); +} + +TEST(GeneratedMessageReflectionTest, RemoveLastExtensions) { + unittest::TestAllExtensions message; + TestUtil::ReflectionTester reflection_tester( + unittest::TestAllExtensions::descriptor()); + + TestUtil::SetAllExtensions(&message); + reflection_tester.RemoveLastRepeatedsViaReflection(&message); + + TestUtil::ExpectLastRepeatedExtensionsRemoved(message); +} + +TEST(GeneratedMessageReflectionTest, SwapRepeatedElements) { + unittest::TestAllTypes message; + TestUtil::ReflectionTester reflection_tester( + unittest::TestAllTypes::descriptor()); + + TestUtil::SetAllFields(&message); + + // Swap and test that fields are all swapped. + reflection_tester.SwapRepeatedsViaReflection(&message); + TestUtil::ExpectRepeatedsSwapped(message); + + // Swap back and test that fields are all back to original values. + reflection_tester.SwapRepeatedsViaReflection(&message); + TestUtil::ExpectAllFieldsSet(message); +} + +TEST(GeneratedMessageReflectionTest, SwapRepeatedElementsExtension) { + unittest::TestAllExtensions message; + TestUtil::ReflectionTester reflection_tester( + unittest::TestAllExtensions::descriptor()); + + TestUtil::SetAllExtensions(&message); + + // Swap and test that fields are all swapped. + reflection_tester.SwapRepeatedsViaReflection(&message); + TestUtil::ExpectRepeatedExtensionsSwapped(message); + + // Swap back and test that fields are all back to original values. + reflection_tester.SwapRepeatedsViaReflection(&message); + TestUtil::ExpectAllExtensionsSet(message); +} + TEST(GeneratedMessageReflectionTest, Extensions) { // Set every extension to a unique value then go back and check all those // values. diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index b05ea954..0f0ef887 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -97,7 +97,7 @@ // // Use the reflection interface to examine the contents. // const Reflection* reflection = foo->GetReflection(); // assert(reflection->GetString(foo, text_field) == "Hello World!"); -// assert(reflection->CountField(foo, numbers_field) == 3); +// assert(reflection->FieldSize(foo, numbers_field) == 3); // assert(reflection->GetInt32(foo, numbers_field, 0) == 1); // assert(reflection->GetInt32(foo, numbers_field, 1) == 5); // assert(reflection->GetInt32(foo, numbers_field, 2) == 42); @@ -494,6 +494,25 @@ class LIBPROTOBUF_EXPORT Reflection { virtual void ClearField(Message* message, const FieldDescriptor* field) const = 0; + // Remove the last element of a repeated field. + // We don't provide a way to remove any element other than the last + // because it invites inefficient use, such as O(n^2) filtering loops + // that should have been O(n). If you want to remove an element other + // than the last, the best way to do it is to re-arrange the elements + // (using Swap()) so that the one you want removed is at the end, then + // call RemoveLast(). + virtual void RemoveLast(Message* message, + const FieldDescriptor* field) const = 0; + + // Swap the complete contents of two messages. + virtual void Swap(Message* message1, Message* message2) const = 0; + + // Swap two elements of a repeated field. + virtual void SwapElements(Message* message, + const FieldDescriptor* field, + int index1, + int index2) const = 0; + // List all fields of the message which are currently set. This includes // extensions. Singular fields will only be listed if HasField(field) would // return true and repeated fields will only be listed if FieldSize(field) diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index e12224fb..4446eaf7 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -86,6 +86,9 @@ class LIBPROTOBUF_EXPORT GenericRepeatedField { virtual void* GenericMutable(int index) = 0; virtual void* GenericAdd() = 0; virtual void GenericClear() = 0; + virtual void GenericRemoveLast() = 0; + virtual void GenericSwap(GenericRepeatedField *other) = 0; + virtual void GenericSwapElements(int index1, int index2) = 0; virtual int GenericSize() const = 0; virtual int GenericSpaceUsedExcludingSelf() const = 0; @@ -135,6 +138,9 @@ class RepeatedField : public internal::GenericRepeatedField { // Swap entire contents with "other". void Swap(RepeatedField* other); + // Swap two elements of a repeated field. + void SwapElements(int index1, int index2); + // STL-like iterator support typedef Element* iterator; typedef const Element* const_iterator; @@ -154,6 +160,9 @@ class RepeatedField : public internal::GenericRepeatedField { void* GenericMutable(int index); void* GenericAdd(); void GenericClear(); + void GenericRemoveLast(); + void GenericSwap(GenericRepeatedField *other); + void GenericSwapElements(int index1, int index2); int GenericSize() const; int GenericSpaceUsedExcludingSelf() const; @@ -214,6 +223,9 @@ class RepeatedPtrField : public internal::GenericRepeatedField { // Swap entire contents with "other". void Swap(RepeatedPtrField* other); + // Swap two elements of a repeated field. + void SwapElements(int index1, int index2); + // STL-like iterator support typedef internal::RepeatedPtrIterator iterator; typedef internal::RepeatedPtrIterator const_iterator; @@ -266,6 +278,9 @@ class RepeatedPtrField : public internal::GenericRepeatedField { void* GenericMutable(int index); void* GenericAdd(); void GenericClear(); + void GenericRemoveLast(); + void GenericSwap(GenericRepeatedField *other); + void GenericSwapElements(int index1, int index2); int GenericSize() const; int GenericSpaceUsedExcludingSelf() const; @@ -395,6 +410,11 @@ void RepeatedField::Swap(RepeatedField* other) { } } +template +void RepeatedField::SwapElements(int index1, int index2) { + swap(*Mutable(index1), *Mutable(index2)); +} + template inline typename RepeatedField::iterator RepeatedField::begin() { @@ -443,6 +463,21 @@ void RepeatedField::GenericClear() { Clear(); } +template +void RepeatedField::GenericRemoveLast() { + RemoveLast(); +} + +template +void RepeatedField::GenericSwap(GenericRepeatedField *other) { + Swap(down_cast*>(other)); +} + +template +void RepeatedField::GenericSwapElements(int index1, int index2) { + SwapElements(index1, index2); +} + template int RepeatedField::GenericSize() const { return size(); @@ -622,6 +657,11 @@ void RepeatedPtrField::Swap(RepeatedPtrField* other) { } } +template +void RepeatedPtrField::SwapElements(int index1, int index2) { + swap(elements_[index1], elements_[index2]); +} + template inline int RepeatedPtrField::SpaceUsedExcludingSelf() const { int allocated_bytes = @@ -707,6 +747,21 @@ void RepeatedPtrField::GenericClear() { Clear(); } +template +void RepeatedPtrField::GenericRemoveLast() { + RemoveLast(); +} + +template +void RepeatedPtrField::GenericSwap(GenericRepeatedField *other) { + Swap(down_cast*>(other)); +} + +template +void RepeatedPtrField::GenericSwapElements(int index1, int index2) { + SwapElements(index1, index2); +} + template int RepeatedPtrField::GenericSize() const { return size(); @@ -736,7 +791,7 @@ inline Element* RepeatedPtrField::NewElement() { return new Element; } -// RepeatedPtrField is alowed but requires a prototype since Message +// RepeatedPtrField is allowed but requires a prototype since Message // is abstract. template <> inline Message* RepeatedPtrField::NewElement() { diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc index 7cf5cc2f..e3e67f67 100644 --- a/src/google/protobuf/test_util.cc +++ b/src/google/protobuf/test_util.cc @@ -1644,6 +1644,295 @@ void TestUtil::ExpectAllFieldsAndExtensionsInOrder(const string& serialized) { EXPECT_TRUE(serialized == expected); } +void TestUtil::ExpectLastRepeatedsRemoved( + const unittest::TestAllTypes& message) { + ASSERT_EQ(1, message.repeated_int32_size ()); + ASSERT_EQ(1, message.repeated_int64_size ()); + ASSERT_EQ(1, message.repeated_uint32_size ()); + ASSERT_EQ(1, message.repeated_uint64_size ()); + ASSERT_EQ(1, message.repeated_sint32_size ()); + ASSERT_EQ(1, message.repeated_sint64_size ()); + ASSERT_EQ(1, message.repeated_fixed32_size ()); + ASSERT_EQ(1, message.repeated_fixed64_size ()); + ASSERT_EQ(1, message.repeated_sfixed32_size()); + ASSERT_EQ(1, message.repeated_sfixed64_size()); + ASSERT_EQ(1, message.repeated_float_size ()); + ASSERT_EQ(1, message.repeated_double_size ()); + ASSERT_EQ(1, message.repeated_bool_size ()); + ASSERT_EQ(1, message.repeated_string_size ()); + ASSERT_EQ(1, message.repeated_bytes_size ()); + + ASSERT_EQ(1, message.repeatedgroup_size ()); + ASSERT_EQ(1, message.repeated_nested_message_size ()); + ASSERT_EQ(1, message.repeated_foreign_message_size()); + ASSERT_EQ(1, message.repeated_import_message_size ()); + ASSERT_EQ(1, message.repeated_nested_enum_size ()); + ASSERT_EQ(1, message.repeated_foreign_enum_size ()); + ASSERT_EQ(1, message.repeated_import_enum_size ()); + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + ASSERT_EQ(1, message.repeated_string_piece_size()); + ASSERT_EQ(1, message.repeated_cord_size()); +#endif + + // Test that the remaining element is the correct one. + EXPECT_EQ(201 , message.repeated_int32 (0)); + EXPECT_EQ(202 , message.repeated_int64 (0)); + EXPECT_EQ(203 , message.repeated_uint32 (0)); + EXPECT_EQ(204 , message.repeated_uint64 (0)); + EXPECT_EQ(205 , message.repeated_sint32 (0)); + EXPECT_EQ(206 , message.repeated_sint64 (0)); + EXPECT_EQ(207 , message.repeated_fixed32 (0)); + EXPECT_EQ(208 , message.repeated_fixed64 (0)); + EXPECT_EQ(209 , message.repeated_sfixed32(0)); + EXPECT_EQ(210 , message.repeated_sfixed64(0)); + EXPECT_EQ(211 , message.repeated_float (0)); + EXPECT_EQ(212 , message.repeated_double (0)); + EXPECT_EQ(true , message.repeated_bool (0)); + EXPECT_EQ("215", message.repeated_string (0)); + EXPECT_EQ("216", message.repeated_bytes (0)); + + EXPECT_EQ(217, message.repeatedgroup (0).a()); + EXPECT_EQ(218, message.repeated_nested_message (0).bb()); + EXPECT_EQ(219, message.repeated_foreign_message(0).c()); + EXPECT_EQ(220, message.repeated_import_message (0).d()); + + EXPECT_EQ(unittest::TestAllTypes::BAR, message.repeated_nested_enum (0)); + EXPECT_EQ(unittest::FOREIGN_BAR , message.repeated_foreign_enum(0)); + EXPECT_EQ(unittest_import::IMPORT_BAR, message.repeated_import_enum (0)); +} + +void TestUtil::ExpectLastRepeatedExtensionsRemoved( + const unittest::TestAllExtensions& message) { + + // Test that one element was removed. + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_int32_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_int64_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_uint32_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_uint64_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_sint32_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_sint64_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_fixed32_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_fixed64_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_sfixed32_extension)); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_sfixed64_extension)); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_float_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_double_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_bool_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_string_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_bytes_extension )); + + ASSERT_EQ(1, message.ExtensionSize(unittest::repeatedgroup_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_nested_message_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_foreign_message_extension)); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_import_message_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_nested_enum_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_foreign_enum_extension )); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_import_enum_extension )); + + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_string_piece_extension)); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_cord_extension)); + + // Test that the remaining element is the correct one. + EXPECT_EQ(201 , message.GetExtension(unittest::repeated_int32_extension , 0)); + EXPECT_EQ(202 , message.GetExtension(unittest::repeated_int64_extension , 0)); + EXPECT_EQ(203 , message.GetExtension(unittest::repeated_uint32_extension , 0)); + EXPECT_EQ(204 , message.GetExtension(unittest::repeated_uint64_extension , 0)); + EXPECT_EQ(205 , message.GetExtension(unittest::repeated_sint32_extension , 0)); + EXPECT_EQ(206 , message.GetExtension(unittest::repeated_sint64_extension , 0)); + EXPECT_EQ(207 , message.GetExtension(unittest::repeated_fixed32_extension , 0)); + EXPECT_EQ(208 , message.GetExtension(unittest::repeated_fixed64_extension , 0)); + EXPECT_EQ(209 , message.GetExtension(unittest::repeated_sfixed32_extension, 0)); + EXPECT_EQ(210 , message.GetExtension(unittest::repeated_sfixed64_extension, 0)); + EXPECT_EQ(211 , message.GetExtension(unittest::repeated_float_extension , 0)); + EXPECT_EQ(212 , message.GetExtension(unittest::repeated_double_extension , 0)); + EXPECT_EQ(true , message.GetExtension(unittest::repeated_bool_extension , 0)); + EXPECT_EQ("215", message.GetExtension(unittest::repeated_string_extension , 0)); + EXPECT_EQ("216", message.GetExtension(unittest::repeated_bytes_extension , 0)); + + EXPECT_EQ(217, message.GetExtension(unittest::repeatedgroup_extension , 0).a()); + EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension , 0).bb()); + EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension, 0).c()); + EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension , 0).d()); + + EXPECT_EQ(unittest::TestAllTypes::BAR, message.GetExtension(unittest::repeated_nested_enum_extension , 0)); + EXPECT_EQ(unittest::FOREIGN_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension, 0)); + EXPECT_EQ(unittest_import::IMPORT_BAR, message.GetExtension(unittest::repeated_import_enum_extension , 0)); + + EXPECT_EQ("224", message.GetExtension(unittest::repeated_string_piece_extension, 0)); + EXPECT_EQ("225", message.GetExtension(unittest::repeated_cord_extension, 0)); +} + +void TestUtil::ExpectRepeatedsSwapped( + const unittest::TestAllTypes& message) { + ASSERT_EQ(2, message.repeated_int32_size ()); + ASSERT_EQ(2, message.repeated_int64_size ()); + ASSERT_EQ(2, message.repeated_uint32_size ()); + ASSERT_EQ(2, message.repeated_uint64_size ()); + ASSERT_EQ(2, message.repeated_sint32_size ()); + ASSERT_EQ(2, message.repeated_sint64_size ()); + ASSERT_EQ(2, message.repeated_fixed32_size ()); + ASSERT_EQ(2, message.repeated_fixed64_size ()); + ASSERT_EQ(2, message.repeated_sfixed32_size()); + ASSERT_EQ(2, message.repeated_sfixed64_size()); + ASSERT_EQ(2, message.repeated_float_size ()); + ASSERT_EQ(2, message.repeated_double_size ()); + ASSERT_EQ(2, message.repeated_bool_size ()); + ASSERT_EQ(2, message.repeated_string_size ()); + ASSERT_EQ(2, message.repeated_bytes_size ()); + + ASSERT_EQ(2, message.repeatedgroup_size ()); + ASSERT_EQ(2, message.repeated_nested_message_size ()); + ASSERT_EQ(2, message.repeated_foreign_message_size()); + ASSERT_EQ(2, message.repeated_import_message_size ()); + ASSERT_EQ(2, message.repeated_nested_enum_size ()); + ASSERT_EQ(2, message.repeated_foreign_enum_size ()); + ASSERT_EQ(2, message.repeated_import_enum_size ()); + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + ASSERT_EQ(2, message.repeated_string_piece_size()); + ASSERT_EQ(2, message.repeated_cord_size()); +#endif + + // Test that the first element and second element are flipped. + EXPECT_EQ(201 , message.repeated_int32 (1)); + EXPECT_EQ(202 , message.repeated_int64 (1)); + EXPECT_EQ(203 , message.repeated_uint32 (1)); + EXPECT_EQ(204 , message.repeated_uint64 (1)); + EXPECT_EQ(205 , message.repeated_sint32 (1)); + EXPECT_EQ(206 , message.repeated_sint64 (1)); + EXPECT_EQ(207 , message.repeated_fixed32 (1)); + EXPECT_EQ(208 , message.repeated_fixed64 (1)); + EXPECT_EQ(209 , message.repeated_sfixed32(1)); + EXPECT_EQ(210 , message.repeated_sfixed64(1)); + EXPECT_EQ(211 , message.repeated_float (1)); + EXPECT_EQ(212 , message.repeated_double (1)); + EXPECT_EQ(true , message.repeated_bool (1)); + EXPECT_EQ("215", message.repeated_string (1)); + EXPECT_EQ("216", message.repeated_bytes (1)); + + EXPECT_EQ(217, message.repeatedgroup (1).a()); + EXPECT_EQ(218, message.repeated_nested_message (1).bb()); + EXPECT_EQ(219, message.repeated_foreign_message(1).c()); + EXPECT_EQ(220, message.repeated_import_message (1).d()); + + EXPECT_EQ(unittest::TestAllTypes::BAR, message.repeated_nested_enum (1)); + EXPECT_EQ(unittest::FOREIGN_BAR , message.repeated_foreign_enum(1)); + EXPECT_EQ(unittest_import::IMPORT_BAR, message.repeated_import_enum (1)); + + EXPECT_EQ(301 , message.repeated_int32 (0)); + EXPECT_EQ(302 , message.repeated_int64 (0)); + EXPECT_EQ(303 , message.repeated_uint32 (0)); + EXPECT_EQ(304 , message.repeated_uint64 (0)); + EXPECT_EQ(305 , message.repeated_sint32 (0)); + EXPECT_EQ(306 , message.repeated_sint64 (0)); + EXPECT_EQ(307 , message.repeated_fixed32 (0)); + EXPECT_EQ(308 , message.repeated_fixed64 (0)); + EXPECT_EQ(309 , message.repeated_sfixed32(0)); + EXPECT_EQ(310 , message.repeated_sfixed64(0)); + EXPECT_EQ(311 , message.repeated_float (0)); + EXPECT_EQ(312 , message.repeated_double (0)); + EXPECT_EQ(false, message.repeated_bool (0)); + EXPECT_EQ("315", message.repeated_string (0)); + EXPECT_EQ("316", message.repeated_bytes (0)); + + EXPECT_EQ(317, message.repeatedgroup (0).a()); + EXPECT_EQ(318, message.repeated_nested_message (0).bb()); + EXPECT_EQ(319, message.repeated_foreign_message(0).c()); + EXPECT_EQ(320, message.repeated_import_message (0).d()); + + EXPECT_EQ(unittest::TestAllTypes::BAZ, message.repeated_nested_enum (0)); + EXPECT_EQ(unittest::FOREIGN_BAZ , message.repeated_foreign_enum(0)); + EXPECT_EQ(unittest_import::IMPORT_BAZ, message.repeated_import_enum (0)); +} + +void TestUtil::ExpectRepeatedExtensionsSwapped( + const unittest::TestAllExtensions& message) { + + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_int32_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_int64_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_uint32_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_uint64_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_sint32_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_sint64_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_fixed32_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_fixed64_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_sfixed32_extension)); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_sfixed64_extension)); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_float_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_double_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_bool_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_string_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_bytes_extension )); + + ASSERT_EQ(2, message.ExtensionSize(unittest::repeatedgroup_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_message_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_message_extension)); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_message_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_nested_enum_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_foreign_enum_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_import_enum_extension )); + + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_string_piece_extension)); + ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_cord_extension)); + + EXPECT_EQ(201 , message.GetExtension(unittest::repeated_int32_extension , 1)); + EXPECT_EQ(202 , message.GetExtension(unittest::repeated_int64_extension , 1)); + EXPECT_EQ(203 , message.GetExtension(unittest::repeated_uint32_extension , 1)); + EXPECT_EQ(204 , message.GetExtension(unittest::repeated_uint64_extension , 1)); + EXPECT_EQ(205 , message.GetExtension(unittest::repeated_sint32_extension , 1)); + EXPECT_EQ(206 , message.GetExtension(unittest::repeated_sint64_extension , 1)); + EXPECT_EQ(207 , message.GetExtension(unittest::repeated_fixed32_extension , 1)); + EXPECT_EQ(208 , message.GetExtension(unittest::repeated_fixed64_extension , 1)); + EXPECT_EQ(209 , message.GetExtension(unittest::repeated_sfixed32_extension, 1)); + EXPECT_EQ(210 , message.GetExtension(unittest::repeated_sfixed64_extension, 1)); + EXPECT_EQ(211 , message.GetExtension(unittest::repeated_float_extension , 1)); + EXPECT_EQ(212 , message.GetExtension(unittest::repeated_double_extension , 1)); + EXPECT_EQ(true , message.GetExtension(unittest::repeated_bool_extension , 1)); + EXPECT_EQ("215", message.GetExtension(unittest::repeated_string_extension , 1)); + EXPECT_EQ("216", message.GetExtension(unittest::repeated_bytes_extension , 1)); + + EXPECT_EQ(217, message.GetExtension(unittest::repeatedgroup_extension , 1).a()); + EXPECT_EQ(218, message.GetExtension(unittest::repeated_nested_message_extension , 1).bb()); + EXPECT_EQ(219, message.GetExtension(unittest::repeated_foreign_message_extension, 1).c()); + EXPECT_EQ(220, message.GetExtension(unittest::repeated_import_message_extension , 1).d()); + + EXPECT_EQ(unittest::TestAllTypes::BAR, message.GetExtension(unittest::repeated_nested_enum_extension , 1)); + EXPECT_EQ(unittest::FOREIGN_BAR , message.GetExtension(unittest::repeated_foreign_enum_extension, 1)); + EXPECT_EQ(unittest_import::IMPORT_BAR, message.GetExtension(unittest::repeated_import_enum_extension , 1)); + + EXPECT_EQ("224", message.GetExtension(unittest::repeated_string_piece_extension, 1)); + EXPECT_EQ("225", message.GetExtension(unittest::repeated_cord_extension, 1)); + + EXPECT_EQ(301 , message.GetExtension(unittest::repeated_int32_extension , 0)); + EXPECT_EQ(302 , message.GetExtension(unittest::repeated_int64_extension , 0)); + EXPECT_EQ(303 , message.GetExtension(unittest::repeated_uint32_extension , 0)); + EXPECT_EQ(304 , message.GetExtension(unittest::repeated_uint64_extension , 0)); + EXPECT_EQ(305 , message.GetExtension(unittest::repeated_sint32_extension , 0)); + EXPECT_EQ(306 , message.GetExtension(unittest::repeated_sint64_extension , 0)); + EXPECT_EQ(307 , message.GetExtension(unittest::repeated_fixed32_extension , 0)); + EXPECT_EQ(308 , message.GetExtension(unittest::repeated_fixed64_extension , 0)); + EXPECT_EQ(309 , message.GetExtension(unittest::repeated_sfixed32_extension, 0)); + EXPECT_EQ(310 , message.GetExtension(unittest::repeated_sfixed64_extension, 0)); + EXPECT_EQ(311 , message.GetExtension(unittest::repeated_float_extension , 0)); + EXPECT_EQ(312 , message.GetExtension(unittest::repeated_double_extension , 0)); + EXPECT_EQ(false, message.GetExtension(unittest::repeated_bool_extension , 0)); + EXPECT_EQ("315", message.GetExtension(unittest::repeated_string_extension , 0)); + EXPECT_EQ("316", message.GetExtension(unittest::repeated_bytes_extension , 0)); + + EXPECT_EQ(317, message.GetExtension(unittest::repeatedgroup_extension , 0).a()); + EXPECT_EQ(318, message.GetExtension(unittest::repeated_nested_message_extension , 0).bb()); + EXPECT_EQ(319, message.GetExtension(unittest::repeated_foreign_message_extension, 0).c()); + EXPECT_EQ(320, message.GetExtension(unittest::repeated_import_message_extension , 0).d()); + + EXPECT_EQ(unittest::TestAllTypes::BAZ, message.GetExtension(unittest::repeated_nested_enum_extension , 0)); + EXPECT_EQ(unittest::FOREIGN_BAZ , message.GetExtension(unittest::repeated_foreign_enum_extension, 0)); + EXPECT_EQ(unittest_import::IMPORT_BAZ, message.GetExtension(unittest::repeated_import_enum_extension , 0)); + + EXPECT_EQ("324", message.GetExtension(unittest::repeated_string_piece_extension, 0)); + EXPECT_EQ("325", message.GetExtension(unittest::repeated_cord_extension, 0)); +} + // =================================================================== TestUtil::ReflectionTester::ReflectionTester( @@ -2451,5 +2740,31 @@ void TestUtil::ReflectionTester::ModifyPackedFieldsViaReflection( reflection->SetRepeatedEnum (message, F("packed_enum" ), 1, foreign_foo_); } +void TestUtil::ReflectionTester::RemoveLastRepeatedsViaReflection(Message* message) { + const Reflection* reflection = message->GetReflection(); + + vector output; + reflection->ListFields(*message, &output); + for (int i=0; iis_repeated()) continue; + + reflection->RemoveLast(message, field); + } +} + +void TestUtil::ReflectionTester::SwapRepeatedsViaReflection(Message* message) { + const Reflection* reflection = message->GetReflection(); + + vector output; + reflection->ListFields(*message, &output); + for (int i=0; iis_repeated()) continue; + + reflection->SwapElements(message, field, 0, 1); + } +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h index 1bedb788..e581f419 100644 --- a/src/google/protobuf/test_util.h +++ b/src/google/protobuf/test_util.h @@ -96,6 +96,17 @@ class TestUtil { // SetAllFieldsAndExtensions(). static void ExpectAllFieldsAndExtensionsInOrder(const string& serialized); + // Check that all repeated fields have had their last elements removed. + static void ExpectLastRepeatedsRemoved( + const unittest::TestAllTypes& message); + static void ExpectLastRepeatedExtensionsRemoved( + const unittest::TestAllExtensions& message); + + // Check that all repeated fields have had their first and last elements swapped. + static void ExpectRepeatedsSwapped(const unittest::TestAllTypes& message); + static void ExpectRepeatedExtensionsSwapped( + const unittest::TestAllExtensions& message); + // Like above, but use the reflection interface. class ReflectionTester { public: @@ -116,6 +127,9 @@ class TestUtil { void ExpectPackedFieldsSetViaReflection(const Message& message); void ExpectPackedClearViaReflection(const Message& message); + void RemoveLastRepeatedsViaReflection(Message* message); + void SwapRepeatedsViaReflection(Message* message); + private: const FieldDescriptor* F(const string& name); -- cgit v1.2.3