Initial commit
[mono.git] / mcs / class / referencesource / mscorlib / system / resources / __fastresourcecomparer.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** <OWNER>[....]</OWNER>
9 ** 
10 ** Class:  FastResourceComparer
11 **
12 **
13 ** Purpose: A collection of quick methods for comparing 
14 **          resource keys (strings)
15 **
16 ** 
17 ===========================================================*/
18 namespace System.Resources {
19     using System;
20     using System.Collections;
21     using System.Collections.Generic;
22     using System.Diagnostics.Contracts;
23
24     internal sealed class FastResourceComparer : IComparer, IEqualityComparer, IComparer<String>, IEqualityComparer<String>
25     {
26         internal static readonly FastResourceComparer Default = new FastResourceComparer();
27
28         // Implements IHashCodeProvider too, due to Hashtable requirements.
29         public int GetHashCode(Object key)
30         {
31             String s = (String) key;
32             return FastResourceComparer.HashFunction(s);
33         }
34
35         public int GetHashCode(String key)
36         {
37             return FastResourceComparer.HashFunction(key);
38         }
39
40         // This hash function MUST be publically documented with the resource
41         // file format, AND we may NEVER change this hash function's return 
42         // value (without changing the file format).
43         internal static int HashFunction(String key)
44         {
45             // Never change this hash function.  We must standardize it so that 
46             // others can read & write our .resources files.  Additionally, we
47             // have a copy of it in InternalResGen as well.
48             uint hash = 5381;
49             for(int i=0; i<key.Length; i++)
50                 hash = ((hash << 5) + hash) ^ key[i];
51             return (int) hash;
52         }
53
54         // Compares Strings quickly in a case-sensitive way
55         public int Compare(Object a, Object b)
56         {
57             if (a == b) return 0;
58             String sa = (String)a;
59             String sb = (String)b;
60             return String.CompareOrdinal(sa, sb);
61         }
62
63         public int Compare(String a, String b)
64         {
65             return String.CompareOrdinal(a, b);
66         }
67
68         public bool Equals(String a, String b)
69         {
70             return String.Equals(a, b);
71         }
72
73         public new bool Equals(Object a, Object b)
74         {
75             if (a == b) return true;
76             String sa = (String)a;
77             String sb = (String)b;
78             return String.Equals(sa,sb);
79         }
80
81         // Input is one string to compare with, and a byte[] containing chars in 
82         // little endian unicode.  Pass in the number of valid chars.
83         [System.Security.SecurityCritical]  // auto-generated
84         public unsafe static int CompareOrdinal(String a, byte[] bytes, int bCharLength)
85         {
86             Contract.Assert(a != null && bytes != null, "FastResourceComparer::CompareOrdinal must have non-null params");
87             Contract.Assert(bCharLength * 2 <= bytes.Length, "FastResourceComparer::CompareOrdinal - numChars is too big!");
88             // This is a managed version of strcmp, but I can't take advantage
89             // of a terminating 0, unlike strcmp in C.
90             int i = 0;
91             int r = 0;
92             // Compare the min length # of characters, then return length diffs.
93             int numChars = a.Length;
94             if (numChars > bCharLength)
95                 numChars = bCharLength;
96             if (bCharLength == 0)   // Can't use fixed on a 0-element array.
97                 return (a.Length == 0) ? 0 : -1;
98             fixed(byte* pb = bytes) {
99
100                 byte *pChar = pb;
101                 while (i < numChars && r == 0) {
102                     // little endian format
103                     int b = pChar[0] | pChar[1] << 8;
104                     r = a[i++] - b;
105                     pChar += sizeof(char);
106                 }
107             }
108             if (r != 0) return r;
109             return a.Length - bCharLength;
110         }
111
112         [System.Security.SecurityCritical]  // auto-generated
113         public static int CompareOrdinal(byte[] bytes, int aCharLength, String b)
114         {
115             return -CompareOrdinal(b, bytes, aCharLength);
116         }
117
118         // This method is to handle potentially misaligned data accesses.
119         // The byte* must point to little endian Unicode characters.
120         [System.Security.SecurityCritical]  // auto-generated
121         internal unsafe static int CompareOrdinal(byte* a, int byteLen, String b)
122         {
123             Contract.Assert((byteLen & 1) == 0, "CompareOrdinal is expecting a UTF-16 string length, which must be even!");
124             Contract.Assert(a != null && b != null, "Null args not allowed.");
125             Contract.Assert(byteLen >= 0, "byteLen must be non-negative.");
126
127             int r = 0;
128             int i = 0;
129             // Compare the min length # of characters, then return length diffs.
130             int numChars = byteLen >> 1;
131             if (numChars > b.Length)
132                 numChars = b.Length;
133             while(i < numChars && r == 0) {
134                 // Must compare character by character, not byte by byte.
135                 char aCh = (char) (*a++ | (*a++ << 8));
136                 r = aCh - b[i++];
137             }
138             if (r != 0) return r;
139             return byteLen - b.Length * 2;
140         }
141     }
142 }
143