1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
//---------------------------------------------------------------------
// <copyright file="ByValueEqualityComparer.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Linq;
namespace System.Data.Common.Utils
{
/// <summary>
/// An implementation of IEqualityComparer<object> that compares byte[] instances by value, and
/// delegates all other equality comparisons to a specified IEqualityComparer. In the default case,
/// this provides by-value comparison for instances of the CLR equivalents of all EDM primitive types.
/// </summary>
internal sealed class ByValueEqualityComparer : IEqualityComparer<object>
{
/// <summary>
/// Provides by-value comparison for instances of the CLR equivalents of all EDM primitive types.
/// </summary>
internal static readonly ByValueEqualityComparer Default = new ByValueEqualityComparer();
private ByValueEqualityComparer()
{
}
public new bool Equals(object x, object y)
{
if (object.Equals(x, y))
{
return true;
}
// If x and y are both non-null byte arrays, then perform a by-value comparison
// based on length and element values, otherwise defer to the default comparison.
//
byte[] xBytes = x as byte[];
byte[] yBytes = y as byte[];
if (xBytes != null && yBytes != null)
{
return CompareBinaryValues(xBytes, yBytes);
}
return false;
}
public int GetHashCode(object obj)
{
if (obj != null)
{
byte[] bytes = obj as byte[];
if (bytes != null)
{
return ComputeBinaryHashCode(bytes);
}
}
else
{
return 0;
}
return obj.GetHashCode();
}
internal static int ComputeBinaryHashCode(byte[] bytes)
{
Debug.Assert(bytes != null, "Byte array cannot be null");
int hashCode = 0;
for (int i = 0, n = Math.Min(bytes.Length, 7); i < n; i++)
{
hashCode = ((hashCode << 5) ^ bytes[i]);
}
return hashCode;
}
internal static bool CompareBinaryValues(byte[] first, byte[] second)
{
Debug.Assert(first != null && second != null, "Arguments cannot be null");
if (first.Length != second.Length)
{
return false;
}
for (int i = 0; i < first.Length; i++)
{
if (first[i] != second[i])
{
return false;
}
}
return true;
}
}
/// <summary>
/// Extends IComparer support to the (non-IComparable) byte[] type, based on by-value comparison.
/// </summary>
internal class ByValueComparer : IComparer
{
internal static readonly IComparer Default = new ByValueComparer(Comparer<object>.Default);
private readonly IComparer nonByValueComparer;
private ByValueComparer(IComparer comparer)
{
Debug.Assert(comparer != null, "Non-ByValue comparer cannot be null");
this.nonByValueComparer = comparer;
}
int IComparer.Compare(object x, object y)
{
if (object.ReferenceEquals(x, y))
{
return 0;
}
//We can convert DBNulls to nulls for the purposes of comparison.
Debug.Assert(!((object.ReferenceEquals(x, DBNull.Value)) && (object.ReferenceEquals(y,DBNull.Value))), "object.ReferenceEquals should catch the case when both values are dbnull");
if (object.ReferenceEquals(x, DBNull.Value))
{
x = null;
}
if (object.ReferenceEquals(y, DBNull.Value))
{
y = null;
}
if (x != null && y != null)
{
byte[] xAsBytes = x as byte[];
byte[] yAsBytes = y as byte[];
if (xAsBytes != null && yAsBytes != null)
{
int result = xAsBytes.Length - yAsBytes.Length;
if (result == 0)
{
int idx = 0;
while (result == 0 && idx < xAsBytes.Length)
{
byte xVal = xAsBytes[idx];
byte yVal = yAsBytes[idx];
if (xVal != yVal)
{
result = xVal - yVal;
}
idx++;
}
}
return result;
}
}
return this.nonByValueComparer.Compare(x, y);
}
}
}
|