Commit ceb561d6 authored by kenton@google.com's avatar kenton@google.com

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

parent f22943c7
????-??-?? 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: 2009-05-13 version 2.1.0:
General General
......
...@@ -70,3 +70,5 @@ Patch contributors: ...@@ -70,3 +70,5 @@ Patch contributors:
* Small patch improving performance of in Python serialization. * Small patch improving performance of in Python serialization.
Alexandre Vassalotti <alexandre@peadrop.com> Alexandre Vassalotti <alexandre@peadrop.com>
* Emacs mode for Protocol Buffers (editors/protobuf-mode.el). * 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) { ...@@ -684,13 +684,13 @@ GenerateClassMethods(io::Printer* printer) {
GenerateCopyFrom(printer); GenerateCopyFrom(printer);
printer->Print("\n"); printer->Print("\n");
GenerateSwap(printer);
printer->Print("\n");
GenerateIsInitialized(printer); GenerateIsInitialized(printer);
printer->Print("\n"); printer->Print("\n");
} }
GenerateSwap(printer);
printer->Print("\n");
printer->Print( printer->Print(
"const ::google::protobuf::Descriptor* $classname$::GetDescriptor() const {\n" "const ::google::protobuf::Descriptor* $classname$::GetDescriptor() const {\n"
" return descriptor();\n" " return descriptor();\n"
...@@ -967,22 +967,27 @@ GenerateSwap(io::Printer* printer) { ...@@ -967,22 +967,27 @@ GenerateSwap(io::Printer* printer) {
printer->Print("if (other != this) {\n"); printer->Print("if (other != this) {\n");
printer->Indent(); printer->Indent();
for (int i = 0; i < descriptor_->field_count(); i++) { if ( descriptor_->file()->options().optimize_for() == FileOptions::SPEED ) {
const FieldDescriptor* field = descriptor_->field(i); for (int i = 0; i < descriptor_->field_count(); i++) {
field_generators_.get(field).GenerateSwappingCode(printer); const FieldDescriptor* field = descriptor_->field(i);
} field_generators_.get(field).GenerateSwappingCode(printer);
}
for (int i = 0; i < (descriptor_->field_count() + 31) / 32; ++i) { for (int i = 0; i < (descriptor_->field_count() + 31) / 32; ++i) {
printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n", printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n",
"i", SimpleItoa(i)); "i", SimpleItoa(i));
} }
printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n");
printer->Print("std::swap(_cached_size_, other->_cached_size_);\n"); printer->Print("std::swap(_cached_size_, other->_cached_size_);\n");
if (descriptor_->extension_range_count() > 0) { if (descriptor_->extension_range_count() > 0) {
printer->Print("_extensions_.Swap(&other->_extensions_);\n"); printer->Print("_extensions_.Swap(&other->_extensions_);\n");
}
} else {
printer->Print("GetReflection()->Swap(this, other);");
} }
printer->Outdent(); printer->Outdent();
printer->Print("}\n"); printer->Print("}\n");
printer->Outdent(); printer->Outdent();
......
This diff is collapsed.
...@@ -497,6 +497,88 @@ Message* ExtensionSet::AddMessage(int number, FieldType type, ...@@ -497,6 +497,88 @@ Message* ExtensionSet::AddMessage(int number, FieldType type,
#undef GOOGLE_DCHECK_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() { void ExtensionSet::Clear() {
......
...@@ -228,6 +228,9 @@ class LIBPROTOBUF_EXPORT ExtensionSet { ...@@ -228,6 +228,9 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
const Descriptor* message_type, const Descriptor* message_type,
MessageFactory* factory); MessageFactory* factory);
void RemoveLast(int number);
void SwapElements(int number, int index1, int index2);
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// TODO(kenton): Hardcore memory management accessors // TODO(kenton): Hardcore memory management accessors
......
...@@ -269,6 +269,61 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { ...@@ -269,6 +269,61 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const {
return total_size; 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, bool GeneratedMessageReflection::HasField(const Message& message,
...@@ -285,8 +340,8 @@ bool GeneratedMessageReflection::HasField(const Message& message, ...@@ -285,8 +340,8 @@ bool GeneratedMessageReflection::HasField(const Message& message,
int GeneratedMessageReflection::FieldSize(const Message& message, int GeneratedMessageReflection::FieldSize(const Message& message,
const FieldDescriptor* field) const { const FieldDescriptor* field) const {
USAGE_CHECK_MESSAGE_TYPE(HasField); USAGE_CHECK_MESSAGE_TYPE(FieldSize);
USAGE_CHECK_REPEATED(HasField); USAGE_CHECK_REPEATED(FieldSize);
if (field->is_extension()) { if (field->is_extension()) {
return GetExtensionSet(message).ExtensionSize(field->number()); return GetExtensionSet(message).ExtensionSize(field->number());
...@@ -350,6 +405,36 @@ void GeneratedMessageReflection::ClearField( ...@@ -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 { namespace {
// Comparison functor for sorting FieldDescriptors by field number. // Comparison functor for sorting FieldDescriptors by field number.
struct FieldNumberSorter { struct FieldNumberSorter {
......
...@@ -140,6 +140,10 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { ...@@ -140,6 +140,10 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
bool HasField(const Message& message, const FieldDescriptor* field) const; bool HasField(const Message& message, const FieldDescriptor* field) const;
int FieldSize(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 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, void ListFields(const Message& message,
vector<const FieldDescriptor*>* output) const; vector<const FieldDescriptor*>* output) const;
......
...@@ -146,6 +146,122 @@ TEST(GeneratedMessageReflectionTest, DefaultsAfterClear) { ...@@ -146,6 +146,122 @@ TEST(GeneratedMessageReflectionTest, DefaultsAfterClear) {
&reflection->GetMessage(message, F("optional_import_message"))); &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) { TEST(GeneratedMessageReflectionTest, Extensions) {
// Set every extension to a unique value then go back and check all those // Set every extension to a unique value then go back and check all those
// values. // values.
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
// // Use the reflection interface to examine the contents. // // Use the reflection interface to examine the contents.
// const Reflection* reflection = foo->GetReflection(); // const Reflection* reflection = foo->GetReflection();
// assert(reflection->GetString(foo, text_field) == "Hello World!"); // 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, 0) == 1);
// assert(reflection->GetInt32(foo, numbers_field, 1) == 5); // assert(reflection->GetInt32(foo, numbers_field, 1) == 5);
// assert(reflection->GetInt32(foo, numbers_field, 2) == 42); // assert(reflection->GetInt32(foo, numbers_field, 2) == 42);
...@@ -494,6 +494,25 @@ class LIBPROTOBUF_EXPORT Reflection { ...@@ -494,6 +494,25 @@ class LIBPROTOBUF_EXPORT Reflection {
virtual void ClearField(Message* message, virtual void ClearField(Message* message,
const FieldDescriptor* field) const = 0; 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 // List all fields of the message which are currently set. This includes
// extensions. Singular fields will only be listed if HasField(field) would // extensions. Singular fields will only be listed if HasField(field) would
// return true and repeated fields will only be listed if FieldSize(field) // return true and repeated fields will only be listed if FieldSize(field)
......
...@@ -86,6 +86,9 @@ class LIBPROTOBUF_EXPORT GenericRepeatedField { ...@@ -86,6 +86,9 @@ class LIBPROTOBUF_EXPORT GenericRepeatedField {
virtual void* GenericMutable(int index) = 0; virtual void* GenericMutable(int index) = 0;
virtual void* GenericAdd() = 0; virtual void* GenericAdd() = 0;
virtual void GenericClear() = 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 GenericSize() const = 0;
virtual int GenericSpaceUsedExcludingSelf() const = 0; virtual int GenericSpaceUsedExcludingSelf() const = 0;
...@@ -135,6 +138,9 @@ class RepeatedField : public internal::GenericRepeatedField { ...@@ -135,6 +138,9 @@ class RepeatedField : public internal::GenericRepeatedField {
// Swap entire contents with "other". // Swap entire contents with "other".
void Swap(RepeatedField* other); void Swap(RepeatedField* other);
// Swap two elements of a repeated field.
void SwapElements(int index1, int index2);
// STL-like iterator support // STL-like iterator support
typedef Element* iterator; typedef Element* iterator;
typedef const Element* const_iterator; typedef const Element* const_iterator;
...@@ -154,6 +160,9 @@ class RepeatedField : public internal::GenericRepeatedField { ...@@ -154,6 +160,9 @@ class RepeatedField : public internal::GenericRepeatedField {
void* GenericMutable(int index); void* GenericMutable(int index);
void* GenericAdd(); void* GenericAdd();
void GenericClear(); void GenericClear();
void GenericRemoveLast();
void GenericSwap(GenericRepeatedField *other);
void GenericSwapElements(int index1, int index2);
int GenericSize() const; int GenericSize() const;
int GenericSpaceUsedExcludingSelf() const; int GenericSpaceUsedExcludingSelf() const;
...@@ -214,6 +223,9 @@ class RepeatedPtrField : public internal::GenericRepeatedField { ...@@ -214,6 +223,9 @@ class RepeatedPtrField : public internal::GenericRepeatedField {
// Swap entire contents with "other". // Swap entire contents with "other".
void Swap(RepeatedPtrField* other); void Swap(RepeatedPtrField* other);
// Swap two elements of a repeated field.
void SwapElements(int index1, int index2);
// STL-like iterator support // STL-like iterator support
typedef internal::RepeatedPtrIterator<Element**> iterator; typedef internal::RepeatedPtrIterator<Element**> iterator;
typedef internal::RepeatedPtrIterator<const Element* const*> const_iterator; typedef internal::RepeatedPtrIterator<const Element* const*> const_iterator;
...@@ -266,6 +278,9 @@ class RepeatedPtrField : public internal::GenericRepeatedField { ...@@ -266,6 +278,9 @@ class RepeatedPtrField : public internal::GenericRepeatedField {
void* GenericMutable(int index); void* GenericMutable(int index);
void* GenericAdd(); void* GenericAdd();
void GenericClear(); void GenericClear();
void GenericRemoveLast();
void GenericSwap(GenericRepeatedField *other);
void GenericSwapElements(int index1, int index2);
int GenericSize() const; int GenericSize() const;
int GenericSpaceUsedExcludingSelf() const; int GenericSpaceUsedExcludingSelf() const;
...@@ -395,6 +410,11 @@ void RepeatedField<Element>::Swap(RepeatedField* other) { ...@@ -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> template <typename Element>
inline typename RepeatedField<Element>::iterator inline typename RepeatedField<Element>::iterator
RepeatedField<Element>::begin() { RepeatedField<Element>::begin() {
...@@ -443,6 +463,21 @@ void RepeatedField<Element>::GenericClear() { ...@@ -443,6 +463,21 @@ void RepeatedField<Element>::GenericClear() {
Clear(); 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> template <typename Element>
int RepeatedField<Element>::GenericSize() const { int RepeatedField<Element>::GenericSize() const {
return size(); return size();
...@@ -622,6 +657,11 @@ void RepeatedPtrField<Element>::Swap(RepeatedPtrField* other) { ...@@ -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> template <typename Element>
inline int RepeatedPtrField<Element>::SpaceUsedExcludingSelf() const { inline int RepeatedPtrField<Element>::SpaceUsedExcludingSelf() const {
int allocated_bytes = int allocated_bytes =
...@@ -707,6 +747,21 @@ void RepeatedPtrField<Element>::GenericClear() { ...@@ -707,6 +747,21 @@ void RepeatedPtrField<Element>::GenericClear() {
Clear(); 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> template <typename Element>
int RepeatedPtrField<Element>::GenericSize() const { int RepeatedPtrField<Element>::GenericSize() const {
return size(); return size();
...@@ -736,7 +791,7 @@ inline Element* RepeatedPtrField<Element>::NewElement() { ...@@ -736,7 +791,7 @@ inline Element* RepeatedPtrField<Element>::NewElement() {
return new Element; 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. // is abstract.
template <> template <>
inline Message* RepeatedPtrField<Message>::NewElement() { inline Message* RepeatedPtrField<Message>::NewElement() {
......
This diff is collapsed.
...@@ -96,6 +96,17 @@ class TestUtil { ...@@ -96,6 +96,17 @@ class TestUtil {
// SetAllFieldsAndExtensions(). // SetAllFieldsAndExtensions().
static void ExpectAllFieldsAndExtensionsInOrder(const string& serialized); 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. // Like above, but use the reflection interface.
class ReflectionTester { class ReflectionTester {
public: public:
...@@ -116,6 +127,9 @@ class TestUtil { ...@@ -116,6 +127,9 @@ class TestUtil {
void ExpectPackedFieldsSetViaReflection(const Message& message); void ExpectPackedFieldsSetViaReflection(const Message& message);
void ExpectPackedClearViaReflection(const Message& message); void ExpectPackedClearViaReflection(const Message& message);
void RemoveLastRepeatedsViaReflection(Message* message);
void SwapRepeatedsViaReflection(Message* message);
private: private:
const FieldDescriptor* F(const string& name); const FieldDescriptor* F(const string& name);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment