Commit 659a43b5 authored by Jan Tattermusch's avatar Jan Tattermusch

Merge pull request #532 from jskeet/proto3-clone

Implement Clone.
parents 45b70328 785e13e3
......@@ -62,7 +62,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
#region Messages
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class Person : pb::IMessage<Person>, global::System.IEquatable<Person> {
public sealed partial class Person : pb::IMessage<Person> {
private static readonly pb::MessageParser<Person> _parser = new pb::MessageParser<Person>(() => new Person());
public static pb::MessageParser<Person> Parser { get { return _parser; } }
......@@ -77,9 +77,18 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public Person() { }
public Person(Person other) {
MergeFrom(other);
name_ = other.name_;
id_ = other.id_;
email_ = other.email_;
phone_ = other.phone_.Clone();
}
public Person Clone() {
return new Person(this);
}
public const int NameFieldNumber = 1;
private string name_ = "";
public string Name {
......@@ -231,7 +240,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class PhoneNumber : pb::IMessage<PhoneNumber>, global::System.IEquatable<PhoneNumber> {
public sealed partial class PhoneNumber : pb::IMessage<PhoneNumber> {
private static readonly pb::MessageParser<PhoneNumber> _parser = new pb::MessageParser<PhoneNumber>(() => new PhoneNumber());
public static pb::MessageParser<PhoneNumber> Parser { get { return _parser; } }
......@@ -246,9 +255,16 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public PhoneNumber() { }
public PhoneNumber(PhoneNumber other) {
MergeFrom(other);
number_ = other.number_;
type_ = other.type_;
}
public PhoneNumber Clone() {
return new PhoneNumber(this);
}
public const int NumberFieldNumber = 1;
private string number_ = "";
public string Number {
......@@ -352,7 +368,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class AddressBook : pb::IMessage<AddressBook>, global::System.IEquatable<AddressBook> {
public sealed partial class AddressBook : pb::IMessage<AddressBook> {
private static readonly pb::MessageParser<AddressBook> _parser = new pb::MessageParser<AddressBook>(() => new AddressBook());
public static pb::MessageParser<AddressBook> Parser { get { return _parser; } }
......@@ -367,9 +383,15 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public AddressBook() { }
public AddressBook(AddressBook other) {
MergeFrom(other);
person_ = other.person_.Clone();
}
public AddressBook Clone() {
return new AddressBook(this);
}
public const int PersonFieldNumber = 1;
private readonly pbc::RepeatedField<global::Google.ProtocolBuffers.Examples.AddressBook.Person> person_ = new pbc::RepeatedField<global::Google.ProtocolBuffers.Examples.AddressBook.Person>();
public pbc::RepeatedField<global::Google.ProtocolBuffers.Examples.AddressBook.Person> Person {
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Google.Protobuf.TestProtos;
using Google.Protobuf.TestProtos;
using NUnit.Framework;
namespace Google.Protobuf
......@@ -88,7 +83,7 @@ namespace Google.Protobuf
var message = new TestAllTypes
{
SingleBool = true,
SingleBytes = ByteString.CopyFrom(new byte[] { 1, 2, 3, 4 }),
SingleBytes = ByteString.CopyFrom(1, 2, 3, 4),
SingleDouble = 23.5,
SingleFixed32 = 23,
SingleFixed64 = 1234567890123,
......@@ -122,7 +117,7 @@ namespace Google.Protobuf
var message = new TestAllTypes
{
RepeatedBool = { true, false },
RepeatedBytes = { ByteString.CopyFrom(new byte[] { 1, 2, 3, 4 }), ByteString.CopyFrom(new byte[] { 5, 6 }) },
RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) },
RepeatedDouble = { -12.25, 23.5 },
RepeatedFixed32 = { uint.MaxValue, 23 },
RepeatedFixed64 = { ulong.MaxValue, 1234567890123 },
......@@ -149,5 +144,118 @@ namespace Google.Protobuf
TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes);
Assert.AreEqual(message, parsed);
}
[Test]
public void CloneSingleNonMessageValues()
{
var original = new TestAllTypes
{
SingleBool = true,
SingleBytes = ByteString.CopyFrom(1, 2, 3, 4),
SingleDouble = 23.5,
SingleFixed32 = 23,
SingleFixed64 = 1234567890123,
SingleFloat = 12.25f,
SingleInt32 = 100,
SingleInt64 = 3210987654321,
SingleNestedEnum = TestAllTypes.Types.NestedEnum.FOO,
SingleSfixed32 = -123,
SingleSfixed64 = -12345678901234,
SingleSint32 = -456,
SingleSint64 = -12345678901235,
SingleString = "test",
SingleUint32 = uint.MaxValue,
SingleUint64 = ulong.MaxValue
};
var clone = original.Clone();
Assert.AreNotSame(original, clone);
Assert.AreEqual(original, clone);
// Just as a single example
clone.SingleInt32 = 150;
Assert.AreNotEqual(original, clone);
}
[Test]
public void CloneRepeatedNonMessageValues()
{
var original = new TestAllTypes
{
RepeatedBool = { true, false },
RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) },
RepeatedDouble = { -12.25, 23.5 },
RepeatedFixed32 = { uint.MaxValue, 23 },
RepeatedFixed64 = { ulong.MaxValue, 1234567890123 },
RepeatedFloat = { 100f, 12.25f },
RepeatedInt32 = { 100, 200 },
RepeatedInt64 = { 3210987654321, long.MaxValue },
RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.FOO, TestAllTypes.Types.NestedEnum.NEG },
RepeatedSfixed32 = { -123, 123 },
RepeatedSfixed64 = { -12345678901234, 12345678901234 },
RepeatedSint32 = { -456, 100 },
RepeatedSint64 = { -12345678901235, 123 },
RepeatedString = { "foo", "bar" },
RepeatedUint32 = { uint.MaxValue, uint.MinValue },
RepeatedUint64 = { ulong.MaxValue, uint.MinValue }
};
var clone = original.Clone();
Assert.AreNotSame(original, clone);
Assert.AreEqual(original, clone);
// Just as a single example
clone.RepeatedDouble.Add(25.5);
Assert.AreNotEqual(original, clone);
}
[Test]
public void CloneSingleMessageField()
{
var original = new TestAllTypes
{
SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 }
};
var clone = original.Clone();
Assert.AreNotSame(original, clone);
Assert.AreNotSame(original.SingleNestedMessage, clone.SingleNestedMessage);
Assert.AreEqual(original, clone);
clone.SingleNestedMessage.Bb = 30;
Assert.AreNotEqual(original, clone);
}
[Test]
public void CloneRepeatedMessageField()
{
var original = new TestAllTypes
{
RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 20 } }
};
var clone = original.Clone();
Assert.AreNotSame(original, clone);
Assert.AreNotSame(original.RepeatedNestedMessage, clone.RepeatedNestedMessage);
Assert.AreNotSame(original.RepeatedNestedMessage[0], clone.RepeatedNestedMessage[0]);
Assert.AreEqual(original, clone);
clone.RepeatedNestedMessage[0].Bb = 30;
Assert.AreNotEqual(original, clone);
}
[Test]
public void CloneOneofField()
{
var original = new TestAllTypes
{
OneofNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 }
};
var clone = original.Clone();
Assert.AreNotSame(original, clone);
Assert.AreEqual(original, clone);
// We should have cloned the message
original.OneofNestedMessage.Bb = 30;
Assert.AreNotEqual(original, clone);
}
}
}
......@@ -60,7 +60,7 @@ namespace Google.Protobuf.TestProtos {
#region Messages
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class ImportMessage : pb::IMessage<ImportMessage>, global::System.IEquatable<ImportMessage> {
public sealed partial class ImportMessage : pb::IMessage<ImportMessage> {
private static readonly pb::MessageParser<ImportMessage> _parser = new pb::MessageParser<ImportMessage>(() => new ImportMessage());
public static pb::MessageParser<ImportMessage> Parser { get { return _parser; } }
......@@ -75,9 +75,15 @@ namespace Google.Protobuf.TestProtos {
}
public ImportMessage() { }
public ImportMessage(ImportMessage other) {
MergeFrom(other);
d_ = other.d_;
}
public ImportMessage Clone() {
return new ImportMessage(this);
}
public const int DFieldNumber = 1;
private int d_;
public int D {
......
......@@ -45,7 +45,7 @@ namespace Google.Protobuf.TestProtos {
}
#region Messages
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class PublicImportMessage : pb::IMessage<PublicImportMessage>, global::System.IEquatable<PublicImportMessage> {
public sealed partial class PublicImportMessage : pb::IMessage<PublicImportMessage> {
private static readonly pb::MessageParser<PublicImportMessage> _parser = new pb::MessageParser<PublicImportMessage>(() => new PublicImportMessage());
public static pb::MessageParser<PublicImportMessage> Parser { get { return _parser; } }
......@@ -60,9 +60,15 @@ namespace Google.Protobuf.TestProtos {
}
public PublicImportMessage() { }
public PublicImportMessage(PublicImportMessage other) {
MergeFrom(other);
e_ = other.e_;
}
public PublicImportMessage Clone() {
return new PublicImportMessage(this);
}
public const int EFieldNumber = 1;
private int e_;
public int E {
......
......@@ -90,7 +90,7 @@ namespace UnitTest.Issues.TestProtos {
#region Messages
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class NegativeEnumMessage : pb::IMessage<NegativeEnumMessage>, global::System.IEquatable<NegativeEnumMessage> {
public sealed partial class NegativeEnumMessage : pb::IMessage<NegativeEnumMessage> {
private static readonly pb::MessageParser<NegativeEnumMessage> _parser = new pb::MessageParser<NegativeEnumMessage>(() => new NegativeEnumMessage());
public static pb::MessageParser<NegativeEnumMessage> Parser { get { return _parser; } }
......@@ -105,9 +105,17 @@ namespace UnitTest.Issues.TestProtos {
}
public NegativeEnumMessage() { }
public NegativeEnumMessage(NegativeEnumMessage other) {
MergeFrom(other);
value_ = other.value_;
values_ = other.values_.Clone();
packedValues_ = other.packedValues_.Clone();
}
public NegativeEnumMessage Clone() {
return new NegativeEnumMessage(this);
}
public const int ValueFieldNumber = 1;
private global::UnitTest.Issues.TestProtos.NegativeEnum value_ = global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO;
public global::UnitTest.Issues.TestProtos.NegativeEnum Value {
......@@ -233,7 +241,7 @@ namespace UnitTest.Issues.TestProtos {
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class DeprecatedChild : pb::IMessage<DeprecatedChild>, global::System.IEquatable<DeprecatedChild> {
public sealed partial class DeprecatedChild : pb::IMessage<DeprecatedChild> {
private static readonly pb::MessageParser<DeprecatedChild> _parser = new pb::MessageParser<DeprecatedChild>(() => new DeprecatedChild());
public static pb::MessageParser<DeprecatedChild> Parser { get { return _parser; } }
......@@ -248,9 +256,14 @@ namespace UnitTest.Issues.TestProtos {
}
public DeprecatedChild() { }
public DeprecatedChild(DeprecatedChild other) {
MergeFrom(other);
}
public DeprecatedChild Clone() {
return new DeprecatedChild(this);
}
public override bool Equals(object other) {
return Equals(other as DeprecatedChild);
}
......@@ -301,7 +314,7 @@ namespace UnitTest.Issues.TestProtos {
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class DeprecatedFieldsMessage : pb::IMessage<DeprecatedFieldsMessage>, global::System.IEquatable<DeprecatedFieldsMessage> {
public sealed partial class DeprecatedFieldsMessage : pb::IMessage<DeprecatedFieldsMessage> {
private static readonly pb::MessageParser<DeprecatedFieldsMessage> _parser = new pb::MessageParser<DeprecatedFieldsMessage>(() => new DeprecatedFieldsMessage());
public static pb::MessageParser<DeprecatedFieldsMessage> Parser { get { return _parser; } }
......@@ -316,9 +329,20 @@ namespace UnitTest.Issues.TestProtos {
}
public DeprecatedFieldsMessage() { }
public DeprecatedFieldsMessage(DeprecatedFieldsMessage other) {
MergeFrom(other);
primitiveValue_ = other.primitiveValue_;
primitiveArray_ = other.primitiveArray_.Clone();
MessageValue = other.messageValue_ != null ? other.MessageValue.Clone() : null;
messageArray_ = other.messageArray_.Clone();
enumValue_ = other.enumValue_;
enumArray_ = other.enumArray_.Clone();
}
public DeprecatedFieldsMessage Clone() {
return new DeprecatedFieldsMessage(this);
}
public const int PrimitiveValueFieldNumber = 1;
private int primitiveValue_;
[global::System.ObsoleteAttribute()]
......@@ -525,7 +549,7 @@ namespace UnitTest.Issues.TestProtos {
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class ItemField : pb::IMessage<ItemField>, global::System.IEquatable<ItemField> {
public sealed partial class ItemField : pb::IMessage<ItemField> {
private static readonly pb::MessageParser<ItemField> _parser = new pb::MessageParser<ItemField>(() => new ItemField());
public static pb::MessageParser<ItemField> Parser { get { return _parser; } }
......@@ -540,9 +564,15 @@ namespace UnitTest.Issues.TestProtos {
}
public ItemField() { }
public ItemField(ItemField other) {
MergeFrom(other);
item_ = other.item_;
}
public ItemField Clone() {
return new ItemField(this);
}
public const int ItemFieldNumber = 1;
private int item_;
public int Item {
......
......@@ -139,7 +139,7 @@ namespace Google.Protobuf
/// are copied, so further modifications to the array will not
/// be reflected in the returned ByteString.
/// </summary>
public static ByteString CopyFrom(byte[] bytes)
public static ByteString CopyFrom(params byte[] bytes)
{
return new ByteString((byte[]) bytes.Clone());
}
......
......@@ -12,6 +12,36 @@ namespace Google.Protobuf.Collections
private T[] array = EmptyArray;
private int count = 0;
/// <summary>
/// Creates a deep clone of this repeated field.
/// </summary>
/// <remarks>
/// If the field type is
/// a message type, each element is also cloned; otherwise, it is
/// assumed that the field type is primitive (including string and
/// bytes, both of which are immutable) and so a simple copy is
/// equivalent to a deep clone.
/// </remarks>
/// <returns>A deep clone of this repeated field.</returns>
public RepeatedField<T> Clone()
{
RepeatedField<T> clone = new RepeatedField<T>();
if (array != EmptyArray)
{
clone.array = (T[])array.Clone();
IDeepCloneable<T>[] cloneableArray = clone.array as IDeepCloneable<T>[];
if (cloneableArray != null)
{
for (int i = 0; i < count; i++)
{
clone.array[i] = cloneableArray[i].Clone();
}
}
}
clone.count = count;
return clone;
}
private void EnsureSize(int size)
{
size = Math.Max(size, MinArraySize);
......
......@@ -34,6 +34,7 @@
#endregion
using System;
using Google.Protobuf.FieldAccess;
namespace Google.Protobuf
......@@ -84,7 +85,7 @@ namespace Google.Protobuf
/// the implementation class.
/// </summary>
/// <typeparam name="T">The message type.</typeparam>
public interface IMessage<T> : IMessage where T : IMessage<T>
public interface IMessage<T> : IMessage, IEquatable<T>, IDeepCloneable<T> where T : IMessage<T>
{
/// <summary>
/// Merges the given message into this one.
......@@ -93,4 +94,22 @@ namespace Google.Protobuf
/// <param name="message">The message to merge with this one. Must not be null.</param>
void MergeFrom(T message);
}
}
\ No newline at end of file
/// <summary>
/// Generic interface for a deeply cloneable type.
/// <summary>
/// <remarks>
/// All generated messages implement this interface, but so do some non-message types.
/// Additionally, due to the type constraint on <c>T</c> in <see cref="IMessage{T}"/>,
/// it is simpler to keep this as a separate interface.
/// </remarks>
/// <typeparam name="T">The type itself, returned by the <see cref="Clone"/> method.</typeparam>
public interface IDeepCloneable<T>
{
/// <summary>
/// Creates a deep clone of this object.
/// </summary>
/// <returns>A deep clone of this object.</returns>
T Clone();
}
}
......@@ -47,6 +47,7 @@ class FieldGeneratorBase : public SourceGeneratorBase {
FieldGeneratorBase(const FieldDescriptor* descriptor, int fieldOrdinal);
~FieldGeneratorBase();
virtual void GenerateCloningCode(io::Printer* printer) = 0;
virtual void GenerateMembers(io::Printer* printer) = 0;
virtual void GenerateMergingCode(io::Printer* printer) = 0;
virtual void GenerateParsingCode(io::Printer* printer) = 0;
......
......@@ -179,7 +179,7 @@ void MessageGenerator::Generate(io::Printer* printer) {
WriteGeneratedCodeAttributes(printer);
printer->Print(
vars,
"$access_level$ sealed partial class $class_name$ : pb::IMessage<$class_name$>, global::System.IEquatable<$class_name$> {\n");
"$access_level$ sealed partial class $class_name$ : pb::IMessage<$class_name$> {\n");
printer->Indent();
// All static fields and properties
......@@ -213,16 +213,12 @@ void MessageGenerator::Generate(io::Printer* printer) {
"}\n"
"\n");
// Constructors
// Parameterless constructor
printer->Print(
vars,
"public $class_name$() { }\n"); // Public parameterless ctor.
"public $class_name$() { }\n\n");
printer->Print(
vars,
"public $class_name$($class_name$ other) {\n"
" MergeFrom(other);\n"
"}\n"); // Merge ctor.
GenerateCloningCode(printer);
// Fields/properties
for (int i = 0; i < descriptor_->field_count(); i++) {
......@@ -303,6 +299,53 @@ void MessageGenerator::Generate(io::Printer* printer) {
}
void MessageGenerator::GenerateCloningCode(io::Printer* printer) {
map<string, string> vars;
vars["class_name"] = class_name();
printer->Print(
vars,
"public $class_name$($class_name$ other) {\n");
printer->Indent();
// Clone non-oneof fields first
for (int i = 0; i < descriptor_->field_count(); i++) {
if (!descriptor_->field(i)->containing_oneof()) {
scoped_ptr<FieldGeneratorBase> generator(
CreateFieldGeneratorInternal(descriptor_->field(i)));
generator->GenerateCloningCode(printer);
}
}
// Clone just the right field for each oneof
for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false);
vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true);
printer->Print(vars, "switch (other.$property_name$Case) {\n");
printer->Indent();
for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
scoped_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field));
vars["field_property_name"] = GetPropertyName(field);
printer->Print(
vars,
"case $property_name$OneofCase.$field_property_name$:\n");
printer->Indent();
generator->GenerateCloningCode(printer);
printer->Print("break;\n");
printer->Outdent();
}
printer->Outdent();
printer->Print("}\n\n");
}
printer->Outdent();
printer->Print("}\n\n");
printer->Print(
vars,
"public $class_name$ Clone() {\n"
" return new $class_name$(this);\n"
"}\n\n");
}
void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) {
map<string, string> vars;
vars["class_name"] = class_name();
......
......@@ -50,6 +50,7 @@ class MessageGenerator : public SourceGeneratorBase {
MessageGenerator(const Descriptor* descriptor);
~MessageGenerator();
void GenerateCloningCode(io::Printer* printer);
void GenerateFrameworkMethods(io::Printer* printer);
void GenerateStaticVariables(io::Printer* printer);
void GenerateStaticVariableInitializers(io::Printer* printer);
......
......@@ -125,6 +125,11 @@ void MessageFieldGenerator::WriteToString(io::Printer* printer) {
"PrintField(\"$field_name$\", has$property_name$, $name$_, writer);\n");
}
void MessageFieldGenerator::GenerateCloningCode(io::Printer* printer) {
printer->Print(variables_,
"$property_name$ = other.$has_property_check$ ? other.$property_name$.Clone() : null;\n");
}
MessageOneofFieldGenerator::MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal)
: MessageFieldGenerator(descriptor, fieldOrdinal) {
......@@ -166,6 +171,11 @@ void MessageOneofFieldGenerator::WriteToString(io::Printer* printer) {
"PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
}
void MessageOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) {
printer->Print(variables_,
"$property_name$ = other.$property_name$.Clone();\n");
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
......
......@@ -46,6 +46,7 @@ class MessageFieldGenerator : public FieldGeneratorBase {
MessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
~MessageFieldGenerator();
virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer);
virtual void GenerateMergingCode(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
......@@ -65,6 +66,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
MessageOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
~MessageOneofFieldGenerator();
virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer);
virtual void WriteToString(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
......
......@@ -146,6 +146,11 @@ void PrimitiveFieldGenerator::WriteToString(io::Printer* printer) {
"PrintField(\"$descriptor_name$\", $has_property_check$, $property_name$, writer);\n");
}
void PrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) {
printer->Print(variables_,
"$name$_ = other.$name$_;\n");
}
PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
const FieldDescriptor* descriptor, int fieldOrdinal)
: PrimitiveFieldGenerator(descriptor, fieldOrdinal) {
......@@ -189,6 +194,11 @@ void PrimitiveOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
"$property_name$ = input.Read$capitalized_type_name$();\n");
}
void PrimitiveOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) {
printer->Print(variables_,
"$property_name$ = other.$property_name$;\n");
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
......
......@@ -46,6 +46,7 @@ class PrimitiveFieldGenerator : public FieldGeneratorBase {
PrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
~PrimitiveFieldGenerator();
virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer);
virtual void GenerateMergingCode(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
......@@ -68,6 +69,7 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
~PrimitiveOneofFieldGenerator();
virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer);
virtual void WriteToString(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
......
......@@ -142,6 +142,11 @@ void RepeatedEnumFieldGenerator::WriteToString(io::Printer* printer) {
"PrintField(\"$descriptor_name$\", $name$_, writer);\n");
}
void RepeatedEnumFieldGenerator::GenerateCloningCode(io::Printer* printer) {
printer->Print(variables_,
"$name$_ = other.$name$_.Clone();\n");
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
......
......@@ -48,6 +48,7 @@ class RepeatedEnumFieldGenerator : public FieldGeneratorBase {
RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
~RepeatedEnumFieldGenerator();
virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer);
virtual void GenerateMergingCode(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
......
......@@ -118,6 +118,11 @@ void RepeatedMessageFieldGenerator::WriteToString(io::Printer* printer) {
"PrintField(\"$field_name$\", $name$_, writer);\n");
}
void RepeatedMessageFieldGenerator::GenerateCloningCode(io::Printer* printer) {
printer->Print(variables_,
"$name$_ = other.$name$_.Clone();\n");
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
......
......@@ -46,6 +46,7 @@ class RepeatedMessageFieldGenerator : public FieldGeneratorBase {
RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
~RepeatedMessageFieldGenerator();
virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer);
virtual void GenerateMergingCode(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
......
......@@ -148,6 +148,11 @@ void RepeatedPrimitiveFieldGenerator::WriteToString(io::Printer* printer) {
"PrintField(\"$descriptor_name$\", $name$_, writer);\n");
}
void RepeatedPrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) {
printer->Print(variables_,
"$name$_ = other.$name$_.Clone();\n");
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
......
......@@ -46,6 +46,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGeneratorBase {
RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
~RepeatedPrimitiveFieldGenerator();
virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer);
virtual void GenerateMergingCode(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
......
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