2003-06-20 Ben Maurer <bmaurer@users.sourceforge.net>
authorBen Maurer <benm@mono-cvs.ximian.com>
Sun, 22 Jun 2003 18:32:39 +0000 (18:32 -0000)
committerBen Maurer <benm@mono-cvs.ximian.com>
Sun, 22 Jun 2003 18:32:39 +0000 (18:32 -0000)
* NameTable.cs: Now uses a custom hashtable to implement. As a
result, when Get (char[], int, int) is called, a string is only
allocated if it is actually a new entry.
(StrEqArray) Compares a string and a char[]
(AddEntry) Adds a new entry to the hashtable
(Entry) Represents a hashtable entry.

svn path=/trunk/mcs/; revision=15551

mcs/class/System.XML/System.Xml/ChangeLog
mcs/class/System.XML/System.Xml/NameTable.cs

index 869699664068e0b906e9f540712671cc206978fa..99d05e1690c6a258db0b8046d5abfc51782044df 100644 (file)
@@ -8,8 +8,15 @@
        * XmlInputStream.cs : quick fix for public ctor() BaseURI bug.
 
 2003-06-20  Ben Maurer <bmaurer@users.sourceforge.net>
+       
        * XmlTextReader.cs: Reduces memory allocation when the reader is
        not queried for some values.
+       * NameTable.cs: Now uses a custom hashtable to implement. As a
+       result, when Get (char[], int, int) is called, a string is only
+       allocated if it is actually a new entry.
+       (StrEqArray) Compares a string and a char[]
+       (AddEntry) Adds a new entry to the hashtable
+       (Entry) Represents a hashtable entry.
 
 2003-06-20  Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
 
index 8b6de29371ee2c71fdd0040d717dd1cca4c16e20..d4bc31e73c066e89f2214a056f94fb338453f659 100755 (executable)
 //
 // System.Xml.NameTable.cs
 //
-// Author: Duncan Mak (duncan@ximian.com)
+// Authors:
+//     Duncan Mak (duncan@ximian.com)
+//     Ben Maurer (bmaurer@users.sourceforge.net)
 //
 // (C) Ximian, Inc.
+// (C) 2003 Ben Maurer
 //
 
 using System;
 using System.Collections;
 
-namespace System.Xml
-{
-       public class NameTable : XmlNameTable
-       {
-               // Fields
-               Hashtable table;
+namespace System.Xml {
+       //
+       // This class implements the name table as a simple
+       // hashtable, using buckets and a linked list.
+       //
+       public class NameTable : XmlNameTable {
                
-               // Constructor
-               public NameTable ()
-                       : base ()
+               const int INITIAL_BUCKETS = 2 << 6; // 64
+               
+               int count = INITIAL_BUCKETS;
+               Entry [] buckets = new Entry [INITIAL_BUCKETS];
+               int size;
+
+               public NameTable () {}
+               
+               class Entry {
+                       public string str;
+                       public int hash, len;
+                       public Entry next;
+       
+                       public Entry (string str, int hash, Entry next)
+                       {
+                               this.str = str;
+                               this.len = str.Length;
+                               this.hash = hash;
+                               this.next = next;
+                       }
+               }
+               
+               public override string Add (char [] key, int start, int len)
                {
-                       table = new Hashtable ();
+                       if (((0 > start) && (start >= key.Length))
+                          || ((0 > len) && (len >= key.Length - len)))
+                               throw new IndexOutOfRangeException ("The Index is out of range.");
+                       
+                       if (len == 0) return String.Empty;
+                       
+                       int h = 0;
+                       // This is from the String.Gethash () icall
+                       for (int i = start; i < len; i++)
+                               h = (h << 5) - h + key [i];
+                       // h must be be >= 0
+                       h &= 0x7FFFFFFF;
+                       
+
+                       for (Entry e = buckets [h % count]; e != null; e = e.next) {
+                               if (e.hash == h && e.len == len && StrEqArray (e.str, key, start))
+                                       return e.str;
+                       }
+                       return AddEntry (new string (key, start, len), h);
                }
-         
-               // Method
+               
                public override string Add (string key)
                {
-                       if (table.Contains (key))
-                               return (string) table [key];
-                       else {
-                               // We don't have to check IsInterned since the implementation
-                               // of String.Intern is mono_string_is_interned_lookup.
-                               String.Intern (key);
-                               table.Add (key, key);
-                               return key;
+                       if (key == String.Empty) return String.Empty;
+                               
+                       int h = 0;
+                       // This is from the String.Gethash () icall
+                       for (int i = 0; i < key.Length; i++)
+                               h = (h << 5) - h + key [i];
+                       
+                       // h must be be >= 0
+                       h &= 0x7FFFFFFF;
+
+                       for (Entry e = buckets [h % count]; e != null; e = e.next) {
+                               if (e.hash == h && e.len == key.Length && e.str == key)
+                                       return e.str;
                        }
+                       
+                       return AddEntry (key, h);
                }
 
-               public override string Add (char[] key, int start, int len)
+               public override string Get (char [] key, int start, int len)
                {
                        if (((0 > start) && (start >= key.Length))
-                           || ((0 > len) && (len >= key.Length - len)))
+                          || ((0 > len) && (len >= key.Length - len)))
                                throw new IndexOutOfRangeException ("The Index is out of range.");
-                                       
-                       if (len == 0)
-                               return String.Empty;
-
-                       string item = new string (key, start, len);
-
-                       return Add (item);
+                       
+                       if (len == 0) return String.Empty;
+                       
+                       int h = 0;
+                       // This is from the String.Gethash () icall
+                       for (int i = start; i < len; i++)
+                               h = (h << 5) - h + key [i];
+                       // h must be be >= 0
+                       h &= 0x7FFFFFFF;
+                       
+                       for (Entry e = buckets [h % count]; e != null; e = e.next) {
+                               if (e.hash == h && e.len == len && StrEqArray (e.str, key, start))
+                                       return e.str;
+                       }
+                       
+                       return null;
                }
-
-               public override string Get (string key)
+               
+               public override string Get (string value) {
+                       if (value == String.Empty) return value;
+                       
+                       int h = 0;
+                       // This is from the String.Gethash () icall
+                       for (int i = 0; i < value.Length; i++)
+                               h = (h << 5) - h + value [i];
+                       // h must be be >= 0
+                       h &= 0x7FFFFFFF;
+                       
+                       for (Entry e = buckets [h % count]; e != null; e = e.next) {
+                               if (e.hash == h && e.len == value.Length && e.str == value)
+                                       return e.str;
+                       }
+                       
+                       return null;
+               }
+               
+               string AddEntry (string str, int hash)
                {
-                       if (! (table.Contains (key)))
-                               return null;
-                       else
-                               return (string) table [key];
+                       int bucket = hash % count;
+                       buckets [bucket] = new Entry (str, hash, buckets [bucket]);
+                       
+                       // Grow whenever we double in size
+                       if (size++ == count) {
+                               count <<= 1;
+                               int csub1 = count - 1;
+                               
+                               Entry [] newBuckets = new Entry [count];
+                               foreach (Entry root in buckets) {
+                                       Entry e = root;
+                                       while (e != null) {
+                                               int newLoc = e.hash & csub1;
+                                               Entry n = e.next;
+                                               e.next = newBuckets [newLoc];
+                                               newBuckets [newLoc] = e;
+                                               e = n;
+                                       }
+                               }
 
+                               buckets = newBuckets;
+                       }
+                       
+                       return str;
                }
-         
-               public override string Get (char[] array, int offset, int length)
+       
+               static bool StrEqArray (string str, char [] str2, int start)
                {
-                       if (((0 > offset) && (offset >= array.Length))
-                           || ((0 > length) && (length >= array.Length - offset)))
-                               throw new IndexOutOfRangeException ("The Index is out of range.");
-
-                       if (length == 0)
-                               return String.Empty;
-
-                       string key = new string (array, offset, length);
-
-                       return Get (key);
+                       for (int i = 0; i < str.Length; i++) {
+                               if (str [i] != str2 [start + i])
+                                       return false;
+                       }
+                       return true;
                }
        }
 }