Add Swap(), SwapElements(), and RemoveLast() to Reflection. Patch by Scott Stafford.

pull/3335/head
kenton@google.com 16 years ago
parent f22943c7d0
commit ceb561d65b
  1. 10
      CHANGES.txt
  2. 2
      CONTRIBUTORS.txt
  3. 35
      src/google/protobuf/compiler/cpp/cpp_message.cc
  4. 334
      src/google/protobuf/descriptor.pb.cc
  5. 82
      src/google/protobuf/extension_set.cc
  6. 3
      src/google/protobuf/extension_set.h
  7. 89
      src/google/protobuf/generated_message_reflection.cc
  8. 4
      src/google/protobuf/generated_message_reflection.h
  9. 116
      src/google/protobuf/generated_message_reflection_unittest.cc
  10. 21
      src/google/protobuf/message.h
  11. 57
      src/google/protobuf/repeated_field.h
  12. 315
      src/google/protobuf/test_util.cc
  13. 14
      src/google/protobuf/test_util.h

@ -1,3 +1,13 @@
????-??-?? version 2.1.1:
C++
* Fixed bug where Message.Swap(Message) was only implemented for
optimize_for_speed. Swap now properly implemented in both modes
(Issue 91).
* Added RemoveLast and SwapElements(index1, index2) to Reflection
interface for repeated elements.
* Added Swap(Message) to Reflection interface.
2009-05-13 version 2.1.0:
General

@ -70,3 +70,5 @@ Patch contributors:
* Small patch improving performance of in Python serialization.
Alexandre Vassalotti <alexandre@peadrop.com>
* Emacs mode for Protocol Buffers (editors/protobuf-mode.el).
Scott Stafford <scott.stafford@gmail.com>
* Added Swap(), SwapElements(), and RemoveLast() to Reflection interface.

@ -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();

@ -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();
}

@ -497,6 +497,88 @@ Message* ExtensionSet::AddMessage(int number, FieldType type,
#undef GOOGLE_DCHECK_TYPE
void ExtensionSet::RemoveLast(int number) {
map<int, Extension>::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<int, Extension>::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() {

@ -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

@ -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<GenericRepeatedField>(message1, field)->GenericSwap(
MutableRaw<GenericRepeatedField>(message2, field));
} else {
switch (field->cpp_type()) {
#define SWAP_VALUES(CPPTYPE, TYPE) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
swap(*MutableRaw<TYPE>(message1, field), \
*MutableRaw<TYPE>(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<GenericRepeatedField>(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<GenericRepeatedField>(message, field)->GenericSwapElements(
index1, index2);
}
}
namespace {
// Comparison functor for sorting FieldDescriptors by field number.
struct FieldNumberSorter {

@ -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<const FieldDescriptor*>* output) const;

@ -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.

@ -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)

@ -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<Element**> iterator;
typedef internal::RepeatedPtrIterator<const Element* const*> 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<Element>::Swap(RepeatedField* other) {
}
}
template <typename Element>
void RepeatedField<Element>::SwapElements(int index1, int index2) {
swap(*Mutable(index1), *Mutable(index2));
}
template <typename Element>
inline typename RepeatedField<Element>::iterator
RepeatedField<Element>::begin() {
@ -443,6 +463,21 @@ void RepeatedField<Element>::GenericClear() {
Clear();
}
template <typename Element>
void RepeatedField<Element>::GenericRemoveLast() {
RemoveLast();
}
template <typename Element>
void RepeatedField<Element>::GenericSwap(GenericRepeatedField *other) {
Swap(down_cast<RepeatedField<Element>*>(other));
}
template <typename Element>
void RepeatedField<Element>::GenericSwapElements(int index1, int index2) {
SwapElements(index1, index2);
}
template <typename Element>
int RepeatedField<Element>::GenericSize() const {
return size();
@ -622,6 +657,11 @@ void RepeatedPtrField<Element>::Swap(RepeatedPtrField* other) {
}
}
template <typename Element>
void RepeatedPtrField<Element>::SwapElements(int index1, int index2) {
swap(elements_[index1], elements_[index2]);
}
template <typename Element>
inline int RepeatedPtrField<Element>::SpaceUsedExcludingSelf() const {
int allocated_bytes =
@ -707,6 +747,21 @@ void RepeatedPtrField<Element>::GenericClear() {
Clear();
}
template <typename Element>
void RepeatedPtrField<Element>::GenericRemoveLast() {
RemoveLast();
}
template <typename Element>
void RepeatedPtrField<Element>::GenericSwap(GenericRepeatedField *other) {
Swap(down_cast<RepeatedPtrField<Element>*>(other));
}
template <typename Element>
void RepeatedPtrField<Element>::GenericSwapElements(int index1, int index2) {
SwapElements(index1, index2);
}
template <typename Element>
int RepeatedPtrField<Element>::GenericSize() const {
return size();
@ -736,7 +791,7 @@ inline Element* RepeatedPtrField<Element>::NewElement() {
return new Element;
}
// RepeatedPtrField<Message> is alowed but requires a prototype since Message
// RepeatedPtrField<Message> is allowed but requires a prototype since Message
// is abstract.
template <>
inline Message* RepeatedPtrField<Message>::NewElement() {

@ -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<const FieldDescriptor*> output;
reflection->ListFields(*message, &output);
for (int i=0; i<output.size(); ++i) {
const FieldDescriptor* field = output[i];
if (!field->is_repeated()) continue;
reflection->RemoveLast(message, field);
}
}
void TestUtil::ReflectionTester::SwapRepeatedsViaReflection(Message* message) {
const Reflection* reflection = message->GetReflection();
vector<const FieldDescriptor*> output;
reflection->ListFields(*message, &output);
for (int i=0; i<output.size(); ++i) {
const FieldDescriptor* field = output[i];
if (!field->is_repeated()) continue;
reflection->SwapElements(message, field, 0, 1);
}
}
} // namespace protobuf
} // namespace google

@ -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);

Loading…
Cancel
Save