MapComparer.cs

Uses 64bit to 32bit hash Mapping for primitive, Value, and Reference types

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
[Serializable]
public class MapComparer<T> : IEqualityComparer<T>
{
private static Mapping64BitToHash32Bit _hash;
private static Type _type = typeof(T);
private static readonly BinaryFormatter _bf = new BinaryFormatter();
private static readonly MemoryStream _ms = new MemoryStream();
private readonly bool _isPrimitive;
public MapComparer()
{
_isPrimitive = IsPrimitive();
_hash = new Mapping64BitToHash32Bit();
_type = typeof(T);
}
public bool Equals(T x, T y)
{
if (x == null || y == null)
return false;
if (_isPrimitive)
return x.Equals(y);
var xb = GetBytesObject(x, _type);
var yb = GetBytesObject(y, _type);
if (xb.Length != yb.Length)
return false;
return xb.Compare(yb);
}
public int GetHashCode(T obj)
{
var buf = GetBytesObject(obj, _type);
return _hash.ComputeHash(buf).ToInt();
}
private static byte[] GetBytesObjectSerial(object value)
{
if (!_type.IsSerializable)
return GetBytesObjectR(value);
_ms.SetLength(0);
_bf.Serialize(_ms, value);
return _ms.ToArray().SubArray(0, (int) _ms.Length);
}
[SecurityCritical]
private static byte[] GetBytesObjectR(object data)
{
var result = new List<byte>();
var type = data.GetType();
IEnumerable<FieldInfo> tFields = type.GetFields();
foreach (var fieldInfo in tFields)
{
var value = fieldInfo.GetValue(data);
var lt = value.GetType();
var buf = GetBytesObject(value, lt);
result.AddRange(buf);
}
var p = type.GetNestedTypes();
if (p.Length > 0)
foreach (var t in p)
{
var nFields = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).ToArray();
if (nFields.Length > 0)
if (!nFields[0].IsStatic)
return result.ToArray();
foreach (var fieldInfo in nFields)
{
var value = fieldInfo.GetValue(null);
var lt = value.GetType();
var buf = GetBytesObject(value, lt);
result.AddRange(buf);
}
}
return result.ToArray();
}
[SecurityCritical]
private static byte[] GetBytesObject(object obj, Type ltype)
{
switch (ltype.Name.Trim('[', ']'))
{
case "Byte":
return !ltype.IsArray ? new[] {(byte) obj} : (byte[]) obj;
case "Boolean":
return !ltype.IsArray ? ((bool) obj).GetBytes() : ((bool[]) obj).GetBytes();
case "SByte":
return !ltype.IsArray ? ((sbyte) obj).GetBytes() : ((sbyte[]) obj).GetBytes();
case "Char":
return !ltype.IsArray ? ((char) obj).GetBytes() : ((char[]) obj).GetBytes();
case "Int16":
return !ltype.IsArray ? ((short) obj).GetBytes() : ((short[]) obj).GetBytes();
case "UInt16":
return !ltype.IsArray ? ((ushort) obj).GetBytes() : ((ushort[]) obj).GetBytes();
case "Int32":
return !ltype.IsArray ? ((int) obj).GetBytes() : ((int[]) obj).GetBytes();
case "UInt32":
return !ltype.IsArray ? ((uint) obj).GetBytes() : ((uint[]) obj).GetBytes();
case "Int64":
return !ltype.IsArray ? ((long) obj).GetBytes() : ((long[]) obj).GetBytes();
case "UInt64":
return !ltype.IsArray ? ((ulong) obj).GetBytes() : ((ulong[]) obj).GetBytes();
case "Single":
return !ltype.IsArray ? ((float) obj).GetBytes() : ((float[]) obj).GetBytes();
case "Double":
return !ltype.IsArray ? ((double) obj).GetBytes() : ((double[]) obj).GetBytes();
case "String":
return !ltype.IsArray ? ((string) obj).GetBytes() : ((string[]) obj).GetBytes();
case "Decimal":
return !ltype.IsArray ? ((decimal) obj).GetBytes() : ((decimal[]) obj).GetBytes();
case "DateTime":
return !ltype.IsArray ? ((DateTime) obj).GetBytes() : ((DateTime[]) obj).GetBytes();
}
return GetBytesObjectSerial(obj);
}
private bool IsPrimitive()
{
switch (Type.GetTypeCode(_type))
{
case TypeCode.Boolean:
case TypeCode.Char:
case TypeCode.SByte:
case TypeCode.Byte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Single:
case TypeCode.String:
case TypeCode.Decimal:
case TypeCode.DateTime:
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Double:
return true;
default:
return false;
}
}
}
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Serialization.Formatters.Binary; using System.Security; [Serializable] public class MapComparer<T> : IEqualityComparer<T> { private static Mapping64BitToHash32Bit _hash; private static Type _type = typeof(T); private static readonly BinaryFormatter _bf = new BinaryFormatter(); private static readonly MemoryStream _ms = new MemoryStream(); private readonly bool _isPrimitive; public MapComparer() { _isPrimitive = IsPrimitive(); _hash = new Mapping64BitToHash32Bit(); _type = typeof(T); } public bool Equals(T x, T y) { if (x == null || y == null) return false; if (_isPrimitive) return x.Equals(y); var xb = GetBytesObject(x, _type); var yb = GetBytesObject(y, _type); if (xb.Length != yb.Length) return false; return xb.Compare(yb); } public int GetHashCode(T obj) { var buf = GetBytesObject(obj, _type); return _hash.ComputeHash(buf).ToInt(); } private static byte[] GetBytesObjectSerial(object value) { if (!_type.IsSerializable) return GetBytesObjectR(value); _ms.SetLength(0); _bf.Serialize(_ms, value); return _ms.ToArray().SubArray(0, (int) _ms.Length); } [SecurityCritical] private static byte[] GetBytesObjectR(object data) { var result = new List<byte>(); var type = data.GetType(); IEnumerable<FieldInfo> tFields = type.GetFields(); foreach (var fieldInfo in tFields) { var value = fieldInfo.GetValue(data); var lt = value.GetType(); var buf = GetBytesObject(value, lt); result.AddRange(buf); } var p = type.GetNestedTypes(); if (p.Length > 0) foreach (var t in p) { var nFields = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).ToArray(); if (nFields.Length > 0) if (!nFields[0].IsStatic) return result.ToArray(); foreach (var fieldInfo in nFields) { var value = fieldInfo.GetValue(null); var lt = value.GetType(); var buf = GetBytesObject(value, lt); result.AddRange(buf); } } return result.ToArray(); } [SecurityCritical] private static byte[] GetBytesObject(object obj, Type ltype) { switch (ltype.Name.Trim('[', ']')) { case "Byte": return !ltype.IsArray ? new[] {(byte) obj} : (byte[]) obj; case "Boolean": return !ltype.IsArray ? ((bool) obj).GetBytes() : ((bool[]) obj).GetBytes(); case "SByte": return !ltype.IsArray ? ((sbyte) obj).GetBytes() : ((sbyte[]) obj).GetBytes(); case "Char": return !ltype.IsArray ? ((char) obj).GetBytes() : ((char[]) obj).GetBytes(); case "Int16": return !ltype.IsArray ? ((short) obj).GetBytes() : ((short[]) obj).GetBytes(); case "UInt16": return !ltype.IsArray ? ((ushort) obj).GetBytes() : ((ushort[]) obj).GetBytes(); case "Int32": return !ltype.IsArray ? ((int) obj).GetBytes() : ((int[]) obj).GetBytes(); case "UInt32": return !ltype.IsArray ? ((uint) obj).GetBytes() : ((uint[]) obj).GetBytes(); case "Int64": return !ltype.IsArray ? ((long) obj).GetBytes() : ((long[]) obj).GetBytes(); case "UInt64": return !ltype.IsArray ? ((ulong) obj).GetBytes() : ((ulong[]) obj).GetBytes(); case "Single": return !ltype.IsArray ? ((float) obj).GetBytes() : ((float[]) obj).GetBytes(); case "Double": return !ltype.IsArray ? ((double) obj).GetBytes() : ((double[]) obj).GetBytes(); case "String": return !ltype.IsArray ? ((string) obj).GetBytes() : ((string[]) obj).GetBytes(); case "Decimal": return !ltype.IsArray ? ((decimal) obj).GetBytes() : ((decimal[]) obj).GetBytes(); case "DateTime": return !ltype.IsArray ? ((DateTime) obj).GetBytes() : ((DateTime[]) obj).GetBytes(); } return GetBytesObjectSerial(obj); } private bool IsPrimitive() { switch (Type.GetTypeCode(_type)) { case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: case TypeCode.String: case TypeCode.Decimal: case TypeCode.DateTime: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: return true; default: return false; } } }
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
[Serializable]
public class MapComparer<T> : IEqualityComparer<T>
{
    private static          Mapping64BitToHash32Bit _hash;
    private static          Type                    _type = typeof(T);
    private static readonly BinaryFormatter         _bf   = new BinaryFormatter();
    private static readonly MemoryStream            _ms   = new MemoryStream();
    private readonly        bool                    _isPrimitive;
    public MapComparer()
    {
        _isPrimitive = IsPrimitive();
        _hash        = new Mapping64BitToHash32Bit();
        _type        = typeof(T);
    }
    public bool Equals(T x, T y)
    {
        if (x == null || y == null)
            return false;
        if (_isPrimitive)
            return x.Equals(y);
        var xb = GetBytesObject(x, _type);
        var yb = GetBytesObject(y, _type);
        if (xb.Length != yb.Length)
            return false;
        return xb.Compare(yb);
    }
    public int GetHashCode(T obj)
    {
        var buf = GetBytesObject(obj, _type);
        return _hash.ComputeHash(buf).ToInt();
    }
    private static byte[] GetBytesObjectSerial(object value)
    {
        if (!_type.IsSerializable)
            return GetBytesObjectR(value);
        _ms.SetLength(0);
        _bf.Serialize(_ms, value);
        return _ms.ToArray().SubArray(0, (int) _ms.Length);
    }
    [SecurityCritical]
    private static byte[] GetBytesObjectR(object data)
    {
        var                    result  = new List<byte>();
        var                    type    = data.GetType();
        IEnumerable<FieldInfo> tFields = type.GetFields();
        foreach (var fieldInfo in tFields)
        {
            var value = fieldInfo.GetValue(data);
            var lt    = value.GetType();
            var buf   = GetBytesObject(value, lt);
            result.AddRange(buf);
        }
        var p = type.GetNestedTypes();
        if (p.Length > 0)
            foreach (var t in p)
            {
                var nFields = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).ToArray();
                if (nFields.Length > 0)
                    if (!nFields[0].IsStatic)
                        return result.ToArray();
                foreach (var fieldInfo in nFields)
                {
                    var value = fieldInfo.GetValue(null);
                    var lt    = value.GetType();
                    var buf   = GetBytesObject(value, lt);
                    result.AddRange(buf);
                }
            }
        return result.ToArray();
    }
    [SecurityCritical]
    private static byte[] GetBytesObject(object obj, Type ltype)
    {
        switch (ltype.Name.Trim('[', ']'))
        {
            case "Byte":
                return !ltype.IsArray ? new[] {(byte) obj} : (byte[]) obj;
            case "Boolean":
                return !ltype.IsArray ? ((bool) obj).GetBytes() : ((bool[]) obj).GetBytes();
            case "SByte":
                return !ltype.IsArray ? ((sbyte) obj).GetBytes() : ((sbyte[]) obj).GetBytes();
            case "Char":
                return !ltype.IsArray ? ((char) obj).GetBytes() : ((char[]) obj).GetBytes();
            case "Int16":
                return !ltype.IsArray ? ((short) obj).GetBytes() : ((short[]) obj).GetBytes();
            case "UInt16":
                return !ltype.IsArray ? ((ushort) obj).GetBytes() : ((ushort[]) obj).GetBytes();
            case "Int32":
                return !ltype.IsArray ? ((int) obj).GetBytes() : ((int[]) obj).GetBytes();
            case "UInt32":
                return !ltype.IsArray ? ((uint) obj).GetBytes() : ((uint[]) obj).GetBytes();
            case "Int64":
                return !ltype.IsArray ? ((long) obj).GetBytes() : ((long[]) obj).GetBytes();
            case "UInt64":
                return !ltype.IsArray ? ((ulong) obj).GetBytes() : ((ulong[]) obj).GetBytes();
            case "Single":
                return !ltype.IsArray ? ((float) obj).GetBytes() : ((float[]) obj).GetBytes();
            case "Double":
                return !ltype.IsArray ? ((double) obj).GetBytes() : ((double[]) obj).GetBytes();
            case "String":
                return !ltype.IsArray ? ((string) obj).GetBytes() : ((string[]) obj).GetBytes();
            case "Decimal":
                return !ltype.IsArray ? ((decimal) obj).GetBytes() : ((decimal[]) obj).GetBytes();
            case "DateTime":
                return !ltype.IsArray ? ((DateTime) obj).GetBytes() : ((DateTime[]) obj).GetBytes();
        }
        return GetBytesObjectSerial(obj);
    }
    private bool IsPrimitive()
    {
        switch (Type.GetTypeCode(_type))
        {
            case TypeCode.Boolean:
            case TypeCode.Char:
            case TypeCode.SByte:
            case TypeCode.Byte:
            case TypeCode.Int16:
            case TypeCode.UInt16:
            case TypeCode.Int32:
            case TypeCode.UInt32:
            case TypeCode.Single:
            case TypeCode.String:
            case TypeCode.Decimal:
            case TypeCode.DateTime:
            case TypeCode.Int64:
            case TypeCode.UInt64:
            case TypeCode.Double:
                return true;
            default:
                return false;
        }
    }
}