add missing file
This commit is contained in:
parent
4fa8df8e30
commit
84ad460d20
|
@ -0,0 +1,119 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BizHawk.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// causes DeepEquality to ignore this field when determining equality
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class DeepEqualsIgnoreAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
public class DeepEquality
|
||||
{
|
||||
/// <summary>
|
||||
/// return true if an array type is not 0-based
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
private static bool IsNonZeroBaedArray(Type t)
|
||||
{
|
||||
if (!t.IsArray)
|
||||
throw new InvalidOperationException();
|
||||
// is there a better way to do this? i couldn't find any documentation...
|
||||
return t.ToString().Contains('*');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// return all instance fields of a type
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<FieldInfo> GetAllFields(Type t)
|
||||
{
|
||||
while (t != null)
|
||||
{
|
||||
// GetFields() will not return inherited private fields, so walk the inheritance hierachy
|
||||
foreach (var f in t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly))
|
||||
{
|
||||
if (f.GetCustomAttributes(typeof(DeepEqualsIgnoreAttribute), true).Length == 0)
|
||||
yield return f;
|
||||
}
|
||||
t = t.BaseType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// test if two arrays are equal in contents; arrays should have same type
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="o1"></param>
|
||||
/// <param name="o2"></param>
|
||||
/// <returns></returns>
|
||||
private static bool ArrayEquals<T>(T[] o1, T[] o2)
|
||||
{
|
||||
if (o1.Length != o2.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < o1.Length; i++)
|
||||
{
|
||||
if (!DeepEquals(o1[i], o2[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static MethodInfo ArrayEqualsGeneric = typeof(DeepEquality).GetMethod("ArrayEquals", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
|
||||
/// <summary>
|
||||
/// test if two objects are equal field by field (with deep inspection of each field)
|
||||
/// </summary>
|
||||
/// <param name="o1"></param>
|
||||
/// <param name="o2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool DeepEquals(object o1, object o2)
|
||||
{
|
||||
if (o1 == o2)
|
||||
{
|
||||
// reference equal, so nothing else to be done
|
||||
return true;
|
||||
}
|
||||
Type t1 = o1.GetType();
|
||||
Type t2 = o2.GetType();
|
||||
if (t1 != t2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (t1.IsArray)
|
||||
{
|
||||
// it's not too hard to support thesse if needed
|
||||
if (t1.GetArrayRank() > 1 || IsNonZeroBaedArray(t1))
|
||||
throw new InvalidOperationException("Complex arrays not supported");
|
||||
|
||||
// this is actually pretty fast; it allows using fast ldelem and stelem opcodes on
|
||||
// arbitrary array types without emitting custom IL
|
||||
var method = ArrayEqualsGeneric.MakeGenericMethod(new Type[] { t1.GetElementType() });
|
||||
return (bool)method.Invoke(null, new object[] { o1, o2 });
|
||||
}
|
||||
else if (t1.IsPrimitive)
|
||||
{
|
||||
return o1.Equals(o2);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var field in GetAllFields(t1))
|
||||
{
|
||||
if (!DeepEquals(field.GetValue(o1), field.GetValue(o2)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue