|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** <OWNER>Microsoft</OWNER>
**
** Class: FastResourceComparer
**
**
** Purpose: A collection of quick methods for comparing
** resource keys (strings)
**
**
===========================================================*/
namespace System.Resources {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
internal sealed class FastResourceComparer : IComparer, IEqualityComparer, IComparer<String>, IEqualityComparer<String>
{
internal static readonly FastResourceComparer Default = new FastResourceComparer();
// Implements IHashCodeProvider too, due to Hashtable requirements.
public int GetHashCode(Object key)
{
String s = (String) key;
return FastResourceComparer.HashFunction(s);
}
public int GetHashCode(String key)
{
return FastResourceComparer.HashFunction(key);
}
// This hash function MUST be publically documented with the resource
// file format, AND we may NEVER change this hash function's return
// value (without changing the file format).
internal static int HashFunction(String key)
{
// Never change this hash function. We must standardize it so that
// others can read & write our .resources files. Additionally, we
// have a copy of it in InternalResGen as well.
uint hash = 5381;
for(int i=0; i<key.Length; i++)
hash = ((hash << 5) + hash) ^ key[i];
return (int) hash;
}
// Compares Strings quickly in a case-sensitive way
public int Compare(Object a, Object b)
{
if (a == b) return 0;
String sa = (String)a;
String sb = (String)b;
return String.CompareOrdinal(sa, sb);
}
public int Compare(String a, String b)
{
return String.CompareOrdinal(a, b);
}
public bool Equals(String a, String b)
{
return String.Equals(a, b);
}
public new bool Equals(Object a, Object b)
{
if (a == b) return true;
String sa = (String)a;
String sb = (String)b;
return String.Equals(sa,sb);
}
// Input is one string to compare with, and a byte[] containing chars in
// little endian unicode. Pass in the number of valid chars.
[System.Security.SecurityCritical] // auto-generated
public unsafe static int CompareOrdinal(String a, byte[] bytes, int bCharLength)
{
Contract.Assert(a != null && bytes != null, "FastResourceComparer::CompareOrdinal must have non-null params");
Contract.Assert(bCharLength * 2 <= bytes.Length, "FastResourceComparer::CompareOrdinal - numChars is too big!");
// This is a managed version of strcmp, but I can't take advantage
// of a terminating 0, unlike strcmp in C.
int i = 0;
int r = 0;
// Compare the min length # of characters, then return length diffs.
int numChars = a.Length;
if (numChars > bCharLength)
numChars = bCharLength;
if (bCharLength == 0) // Can't use fixed on a 0-element array.
return (a.Length == 0) ? 0 : -1;
fixed(byte* pb = bytes) {
byte *pChar = pb;
while (i < numChars && r == 0) {
// little endian format
int b = pChar[0] | pChar[1] << 8;
r = a[i++] - b;
pChar += sizeof(char);
}
}
if (r != 0) return r;
return a.Length - bCharLength;
}
[System.Security.SecurityCritical] // auto-generated
public static int CompareOrdinal(byte[] bytes, int aCharLength, String b)
{
return -CompareOrdinal(b, bytes, aCharLength);
}
// This method is to handle potentially misaligned data accesses.
// The byte* must point to little endian Unicode characters.
[System.Security.SecurityCritical] // auto-generated
internal unsafe static int CompareOrdinal(byte* a, int byteLen, String b)
{
Contract.Assert((byteLen & 1) == 0, "CompareOrdinal is expecting a UTF-16 string length, which must be even!");
Contract.Assert(a != null && b != null, "Null args not allowed.");
Contract.Assert(byteLen >= 0, "byteLen must be non-negative.");
int r = 0;
int i = 0;
// Compare the min length # of characters, then return length diffs.
int numChars = byteLen >> 1;
if (numChars > b.Length)
numChars = b.Length;
while(i < numChars && r == 0) {
// Must compare character by character, not byte by byte.
char aCh = (char) (*a++ | (*a++ << 8));
r = aCh - b[i++];
}
if (r != 0) return r;
return byteLen - b.Length * 2;
}
}
}
|