1 //------------------------------------------------------------------------------
2 // <copyright file="NameTable.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">[....]</owner>
6 //------------------------------------------------------------------------------
10 namespace System.Xml {
12 /// <include file='doc\NameTable.uex' path='docs/doc[@for="NameTable"]/*' />
15 /// XmlNameTable implemented as a simple hash table.
18 public class NameTable : XmlNameTable {
24 internal int hashCode;
27 internal Entry( string str, int hashCode, Entry next ) {
29 this.hashCode = hashCode;
40 int hashCodeRandomizer;
45 /// <include file='doc\NameTable.uex' path='docs/doc[@for="NameTable.NameTable"]/*' />
47 /// Public constructor.
51 entries = new Entry[mask+1];
52 hashCodeRandomizer = Environment.TickCount;
56 // XmlNameTable public methods
58 /// <include file='doc\NameTable.uex' path='docs/doc[@for="NameTable.Add"]/*' />
60 /// Add the given string to the NameTable or return
61 /// the existing string if it is already in the NameTable.
63 public override string Add( string key ) {
65 throw new ArgumentNullException( "key" );
71 int hashCode = len + hashCodeRandomizer;
72 // use key.Length to eliminate the rangecheck
73 for ( int i = 0; i < key.Length; i++ ) {
74 hashCode += ( hashCode << 7 ) ^ key[i];
77 hashCode -= hashCode >> 17;
78 hashCode -= hashCode >> 11;
79 hashCode -= hashCode >> 5;
81 for ( Entry e = entries[hashCode & mask]; e != null; e = e.next ) {
82 if ( e.hashCode == hashCode && e.str.Equals( key ) ) {
86 return AddEntry( key, hashCode );
89 /// <include file='doc\NameTable.uex' path='docs/doc[@for="NameTable.Add1"]/*' />
91 /// Add the given string to the NameTable or return
92 /// the existing string if it is already in the NameTable.
94 public override string Add( char[] key, int start, int len ) {
99 int hashCode = len + hashCodeRandomizer;
100 hashCode += ( hashCode << 7 ) ^ key[start]; // this will throw IndexOutOfRangeException in case the start index is invalid
102 for ( int i = start + 1; i < end; i++) {
103 hashCode += ( hashCode << 7 ) ^ key[i];
106 hashCode -= hashCode >> 17;
107 hashCode -= hashCode >> 11;
108 hashCode -= hashCode >> 5;
110 for ( Entry e = entries[hashCode & mask]; e != null; e = e.next ) {
111 if ( e.hashCode == hashCode && TextEquals( e.str, key, start, len ) ) {
115 return AddEntry( new string( key, start, len ), hashCode );
118 /// <include file='doc\NameTable.uex' path='docs/doc[@for="NameTable.Get"]/*' />
120 /// Find the matching string in the NameTable.
122 public override string Get( string value ) {
123 if ( value == null ) {
124 throw new ArgumentNullException("value");
126 if ( value.Length == 0 ) {
130 int len = value.Length + hashCodeRandomizer;
132 // use value.Length to eliminate the rangecheck
133 for ( int i = 0; i < value.Length; i++ ) {
134 hashCode += ( hashCode << 7 ) ^ value[i];
137 hashCode -= hashCode >> 17;
138 hashCode -= hashCode >> 11;
139 hashCode -= hashCode >> 5;
141 for ( Entry e = entries[hashCode & mask]; e != null; e = e.next ) {
142 if ( e.hashCode == hashCode && e.str.Equals( value ) ) {
149 /// <include file='doc\NameTable.uex' path='docs/doc[@for="NameTable.Get1"]/*' />
151 /// Find the matching string atom given a range of
154 public override string Get( char[] key, int start, int len ) {
159 int hashCode = len + hashCodeRandomizer;
160 hashCode += ( hashCode << 7 ) ^ key[start]; // this will throw IndexOutOfRangeException in case the start index is invalid
162 for ( int i = start + 1; i < end; i++) {
163 hashCode += ( hashCode << 7 ) ^ key[i];
166 hashCode -= hashCode >> 17;
167 hashCode -= hashCode >> 11;
168 hashCode -= hashCode >> 5;
170 for ( Entry e = entries[hashCode & mask]; e != null; e = e.next ) {
171 if ( e.hashCode == hashCode && TextEquals( e.str, key, start, len ) ) {
182 private string AddEntry( string str, int hashCode ) {
183 int index = hashCode & mask;
184 Entry e = new Entry( str, hashCode, entries[index] );
186 if ( count++ == mask ) {
192 private void Grow() {
193 int newMask = mask * 2 + 1;
194 Entry[] oldEntries = entries;
195 Entry[] newEntries = new Entry[newMask+1];
197 // use oldEntries.Length to eliminate the rangecheck
198 for ( int i = 0; i < oldEntries.Length; i++ ) {
199 Entry e = oldEntries[i];
200 while ( e != null ) {
201 int newIndex = e.hashCode & newMask;
203 e.next = newEntries[newIndex];
204 newEntries[newIndex] = e;
209 entries = newEntries;
213 private static bool TextEquals( string str1, char[] str2, int str2Start, int str2Length ) {
214 if ( str1.Length != str2Length ) {
217 // use array.Length to eliminate the rangecheck
218 for ( int i = 0; i < str1.Length; i++ ) {
219 if ( str1[i] != str2[str2Start+i] ) {