{"id":298,"date":"2020-12-17T22:02:20","date_gmt":"2020-12-17T22:02:20","guid":{"rendered":"https:\/\/michaeljohnsteiner.com\/?p=298"},"modified":"2020-12-21T21:39:01","modified_gmt":"2020-12-21T21:39:01","slug":"mapcomparer-cs","status":"publish","type":"post","link":"https:\/\/michaeljohnsteiner.com\/index.php\/2020\/12\/17\/mapcomparer-cs\/","title":{"rendered":"MapComparer.cs"},"content":{"rendered":"\n<p>Uses 64bit to 32bit hash Mapping for primitive, Value, and Reference types<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.Serialization.Formatters.Binary;\nusing System.Security;\n[Serializable]\npublic class MapComparer&lt;T> : IEqualityComparer&lt;T>\n{\n    private static          Mapping64BitToHash32Bit _hash;\n    private static          Type                    _type = typeof(T);\n    private static readonly BinaryFormatter         _bf   = new BinaryFormatter();\n    private static readonly MemoryStream            _ms   = new MemoryStream();\n    private readonly        bool                    _isPrimitive;\n    public MapComparer()\n    {\n        _isPrimitive = IsPrimitive();\n        _hash        = new Mapping64BitToHash32Bit();\n        _type        = typeof(T);\n    }\n    public bool Equals(T x, T y)\n    {\n        if (x == null || y == null)\n            return false;\n        if (_isPrimitive)\n            return x.Equals(y);\n        var xb = GetBytesObject(x, _type);\n        var yb = GetBytesObject(y, _type);\n        if (xb.Length != yb.Length)\n            return false;\n        return xb.Compare(yb);\n    }\n    public int GetHashCode(T obj)\n    {\n        var buf = GetBytesObject(obj, _type);\n        return _hash.ComputeHash(buf).ToInt();\n    }\n    private static byte[] GetBytesObjectSerial(object value)\n    {\n        if (!_type.IsSerializable)\n            return GetBytesObjectR(value);\n        _ms.SetLength(0);\n        _bf.Serialize(_ms, value);\n        return _ms.ToArray().SubArray(0, (int) _ms.Length);\n    }\n    [SecurityCritical]\n    private static byte[] GetBytesObjectR(object data)\n    {\n        var                    result  = new List&lt;byte>();\n        var                    type    = data.GetType();\n        IEnumerable&lt;FieldInfo> tFields = type.GetFields();\n        foreach (var fieldInfo in tFields)\n        {\n            var value = fieldInfo.GetValue(data);\n            var lt    = value.GetType();\n            var buf   = GetBytesObject(value, lt);\n            result.AddRange(buf);\n        }\n        var p = type.GetNestedTypes();\n        if (p.Length > 0)\n            foreach (var t in p)\n            {\n                var nFields = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).ToArray();\n                if (nFields.Length > 0)\n                    if (!nFields[0].IsStatic)\n                        return result.ToArray();\n                foreach (var fieldInfo in nFields)\n                {\n                    var value = fieldInfo.GetValue(null);\n                    var lt    = value.GetType();\n                    var buf   = GetBytesObject(value, lt);\n                    result.AddRange(buf);\n                }\n            }\n        return result.ToArray();\n    }\n    [SecurityCritical]\n    private static byte[] GetBytesObject(object obj, Type ltype)\n    {\n        switch (ltype.Name.Trim('[', ']'))\n        {\n            case \"Byte\":\n                return !ltype.IsArray ? new[] {(byte) obj} : (byte[]) obj;\n            case \"Boolean\":\n                return !ltype.IsArray ? ((bool) obj).GetBytes() : ((bool[]) obj).GetBytes();\n            case \"SByte\":\n                return !ltype.IsArray ? ((sbyte) obj).GetBytes() : ((sbyte[]) obj).GetBytes();\n            case \"Char\":\n                return !ltype.IsArray ? ((char) obj).GetBytes() : ((char[]) obj).GetBytes();\n            case \"Int16\":\n                return !ltype.IsArray ? ((short) obj).GetBytes() : ((short[]) obj).GetBytes();\n            case \"UInt16\":\n                return !ltype.IsArray ? ((ushort) obj).GetBytes() : ((ushort[]) obj).GetBytes();\n            case \"Int32\":\n                return !ltype.IsArray ? ((int) obj).GetBytes() : ((int[]) obj).GetBytes();\n            case \"UInt32\":\n                return !ltype.IsArray ? ((uint) obj).GetBytes() : ((uint[]) obj).GetBytes();\n            case \"Int64\":\n                return !ltype.IsArray ? ((long) obj).GetBytes() : ((long[]) obj).GetBytes();\n            case \"UInt64\":\n                return !ltype.IsArray ? ((ulong) obj).GetBytes() : ((ulong[]) obj).GetBytes();\n            case \"Single\":\n                return !ltype.IsArray ? ((float) obj).GetBytes() : ((float[]) obj).GetBytes();\n            case \"Double\":\n                return !ltype.IsArray ? ((double) obj).GetBytes() : ((double[]) obj).GetBytes();\n            case \"String\":\n                return !ltype.IsArray ? ((string) obj).GetBytes() : ((string[]) obj).GetBytes();\n            case \"Decimal\":\n                return !ltype.IsArray ? ((decimal) obj).GetBytes() : ((decimal[]) obj).GetBytes();\n            case \"DateTime\":\n                return !ltype.IsArray ? ((DateTime) obj).GetBytes() : ((DateTime[]) obj).GetBytes();\n        }\n        return GetBytesObjectSerial(obj);\n    }\n    private bool IsPrimitive()\n    {\n        switch (Type.GetTypeCode(_type))\n        {\n            case TypeCode.Boolean:\n            case TypeCode.Char:\n            case TypeCode.SByte:\n            case TypeCode.Byte:\n            case TypeCode.Int16:\n            case TypeCode.UInt16:\n            case TypeCode.Int32:\n            case TypeCode.UInt32:\n            case TypeCode.Single:\n            case TypeCode.String:\n            case TypeCode.Decimal:\n            case TypeCode.DateTime:\n            case TypeCode.Int64:\n            case TypeCode.UInt64:\n            case TypeCode.Double:\n                return true;\n            default:\n                return false;\n        }\n    }\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Uses 64bit to 32bit hash Mapping for primitive, Value, and Reference types<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[146,62,145],"_links":{"self":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/298"}],"collection":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/comments?post=298"}],"version-history":[{"count":2,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/298\/revisions"}],"predecessor-version":[{"id":303,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/298\/revisions\/303"}],"wp:attachment":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/media?parent=298"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/categories?post=298"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/tags?post=298"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}