Merge pull request #7141 from RoosterDragon/sync-less-tostring

Generate sync reports faster
This commit is contained in:
Paul Chote
2014-12-22 09:01:08 +13:00

View File

@@ -17,7 +17,7 @@ using OpenRA.Primitives;
namespace OpenRA.Network namespace OpenRA.Network
{ {
using NamesValuesPair = Pair<string[], string[]>; using NamesValuesPair = Pair<string[], object[]>;
class SyncReport class SyncReport
{ {
@@ -35,10 +35,10 @@ namespace OpenRA.Network
TypeInfo typeInfo; TypeInfo typeInfo;
lock (typeInfoCache) lock (typeInfoCache)
typeInfo = typeInfoCache[type]; typeInfo = typeInfoCache[type];
var values = new string[typeInfo.Names.Length]; var values = new object[typeInfo.Names.Length];
var index = 0; var index = 0;
foreach (var func in typeInfo.MemberToStringFunctions) foreach (var func in typeInfo.SerializableCopyOfMemberFunctions)
values[index++] = func(sync); values[index++] = func(sync);
return Pair.New(typeInfo.Names, values); return Pair.New(typeInfo.Names, values);
@@ -166,7 +166,7 @@ namespace OpenRA.Network
static ParameterExpression syncParam = Expression.Parameter(typeof(ISync), "sync"); static ParameterExpression syncParam = Expression.Parameter(typeof(ISync), "sync");
static ConstantExpression nullString = Expression.Constant(null, typeof(string)); static ConstantExpression nullString = Expression.Constant(null, typeof(string));
public readonly Func<ISync, string>[] MemberToStringFunctions; public readonly Func<ISync, object>[] SerializableCopyOfMemberFunctions;
public readonly string[] Names; public readonly string[] Names;
public TypeInfo(Type type) public TypeInfo(Type type)
@@ -182,14 +182,25 @@ namespace OpenRA.Network
"Invalid Property: " + prop.DeclaringType.FullName + "." + prop.Name); "Invalid Property: " + prop.DeclaringType.FullName + "." + prop.Name);
var sync = Expression.Convert(syncParam, type); var sync = Expression.Convert(syncParam, type);
MemberToStringFunctions = fields SerializableCopyOfMemberFunctions = fields
.Select(fi => MemberToString(Expression.Field(sync, fi), fi.FieldType, fi.Name)) .Select(fi => SerializableCopyOfMember(Expression.Field(sync, fi), fi.FieldType, fi.Name))
.Concat(properties.Select(pi => MemberToString(Expression.Property(sync, pi), pi.PropertyType, pi.Name))) .Concat(properties.Select(pi => SerializableCopyOfMember(Expression.Property(sync, pi), pi.PropertyType, pi.Name)))
.ToArray(); .ToArray();
Names = fields.Select(fi => fi.Name).Concat(properties.Select(pi => pi.Name)).ToArray(); Names = fields.Select(fi => fi.Name).Concat(properties.Select(pi => pi.Name)).ToArray();
} }
static Func<ISync, object> SerializableCopyOfMember(MemberExpression getMember, Type memberType, string name)
{
if (memberType.IsValueType)
{
// We can get a copy just by accessing the member since it is a value type.
var boxedCopy = Expression.Convert(getMember, typeof(object));
return Expression.Lambda<Func<ISync, object>>(boxedCopy, name, new[] { syncParam }).Compile();
}
return MemberToString(getMember, memberType, name);
}
static Func<ISync, string> MemberToString(MemberExpression getMember, Type memberType, string name) static Func<ISync, string> MemberToString(MemberExpression getMember, Type memberType, string name)
{ {
// The lambda generated is shown below. // The lambda generated is shown below.
@@ -197,10 +208,13 @@ namespace OpenRA.Network
var toString = memberType.GetMethod("ToString", Type.EmptyTypes); var toString = memberType.GetMethod("ToString", Type.EmptyTypes);
Expression getString; Expression getString;
if (memberType.IsValueType) if (memberType.IsValueType)
{
// (ISync sync) => { return ((TSync)sync).Foo.ToString(); }
getString = Expression.Call(getMember, toString); getString = Expression.Call(getMember, toString);
}
else else
{ {
// (ISync sync) => { var foo = ((TSync)sync).Foo; return foo == null ? null : foo.ToString()); } // (ISync sync) => { var foo = ((TSync)sync).Foo; return foo == null ? null : foo.ToString(); }
var memberVariable = Expression.Variable(memberType, getMember.Member.Name); var memberVariable = Expression.Variable(memberType, getMember.Member.Name);
var assignMemberVariable = Expression.Assign(memberVariable, getMember); var assignMemberVariable = Expression.Assign(memberVariable, getMember);
var member = Expression.Block(new[] { memberVariable }, assignMemberVariable); var member = Expression.Block(new[] { memberVariable }, assignMemberVariable);