The Labs \ Source Viewer \ SSCLI \ System.Collections.Specialized \ HybridDictionary

  1. //------------------------------------------------------------------------------
  2. // <copyright file="HybridDictionary.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Collections.Specialized
  16. {
  17.    
  18.     using System.Collections;
  19.     using System.Globalization;
  20.    
  21.     /// <devdoc>
  22.     /// <para>
  23.     /// This data structure implements IDictionary first using a linked list
  24.     /// (ListDictionary) and then switching over to use Hashtable when large. This is recommended
  25.     /// for cases where the number of elements in a dictionary is unknown and might be small.
  26.     ///
  27.     /// It also has a single boolean parameter to allow case-sensitivity that is not affected by
  28.     /// ambient culture and has been optimized for looking up case-insensitive symbols
  29.     /// </para>
  30.     /// </devdoc>
  31.     [Serializable()]
  32.     public class HybridDictionary : IDictionary
  33.     {
  34.        
  35.         // These numbers have been carefully tested to be optimal. Please don't change them
  36.         // without doing thorough performance testing.
  37.         private const int CutoverPoint = 9;
  38.         private const int InitialHashtableSize = 13;
  39.         private const int FixedSizeCutoverPoint = 6;
  40.        
  41.         // Instance variables. This keeps the HybridDictionary very light-weight when empty
  42.         private ListDictionary list;
  43.         private Hashtable hashtable;
  44.         private bool caseInsensitive;
  45.        
  46.         /// <devdoc>
  47.         /// <para>[To be supplied.]</para>
  48.         /// </devdoc>
  49.         public HybridDictionary()
  50.         {
  51.         }
  52.        
  53.         /// <devdoc>
  54.         /// <para>[To be supplied.]</para>
  55.         /// </devdoc>
  56.         public HybridDictionary(int initialSize) : this(initialSize, false)
  57.         {
  58.         }
  59.        
  60.         /// <devdoc>
  61.         /// <para>[To be supplied.]</para>
  62.         /// </devdoc>
  63.         public HybridDictionary(bool caseInsensitive)
  64.         {
  65.             this.caseInsensitive = caseInsensitive;
  66.         }
  67.        
  68.         /// <devdoc>
  69.         /// <para>[To be supplied.]</para>
  70.         /// </devdoc>
  71.         public HybridDictionary(int initialSize, bool caseInsensitive)
  72.         {
  73.             this.caseInsensitive = caseInsensitive;
  74.             if (initialSize >= FixedSizeCutoverPoint) {
  75.                 if (caseInsensitive) {
  76.                     hashtable = new Hashtable(initialSize, StringComparer.OrdinalIgnoreCase);
  77.                 }
  78.                 else {
  79.                     hashtable = new Hashtable(initialSize);
  80.                 }
  81.             }
  82.         }
  83.        
  84.         /// <devdoc>
  85.         /// <para>[To be supplied.]</para>
  86.         /// </devdoc>
  87.         public object this[object key]
  88.         {
  89.             get {
  90.                 //
  91.                
  92.                 ListDictionary cachedList = list;
  93.                 if (hashtable != null) {
  94.                     return hashtable[key];
  95.                 }
  96.                 else if (cachedList != null) {
  97.                     return cachedList[key];
  98.                 }
  99.                 else {
  100.                     //
  101.                     if (key == null) {
  102.                         throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
  103.                     }
  104.                     return null;
  105.                 }
  106.             }
  107.             set {
  108.                 if (hashtable != null) {
  109.                     hashtable[key] = value;
  110.                 }
  111.                 else if (list != null) {
  112.                     if (list.Count >= CutoverPoint - 1) {
  113.                         ChangeOver();
  114.                         hashtable[key] = value;
  115.                     }
  116.                     else {
  117.                         list[key] = value;
  118.                     }
  119.                 }
  120.                 else {
  121.                     list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
  122.                     list[key] = value;
  123.                 }
  124.             }
  125.         }
  126.        
  127.         private ListDictionary List {
  128.             get {
  129.                 if (list == null) {
  130.                     list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
  131.                 }
  132.                 return list;
  133.             }
  134.         }
  135.        
  136.         private void ChangeOver()
  137.         {
  138.             IDictionaryEnumerator en = list.GetEnumerator();
  139.             Hashtable newTable;
  140.             if (caseInsensitive) {
  141.                 newTable = new Hashtable(InitialHashtableSize, StringComparer.OrdinalIgnoreCase);
  142.             }
  143.             else {
  144.                 newTable = new Hashtable(InitialHashtableSize);
  145.             }
  146.             while (en.MoveNext()) {
  147.                 newTable.Add(en.Key, en.Value);
  148.             }
  149.             hashtable = newTable;
  150.             list = null;
  151.         }
  152.        
  153.         /// <devdoc>
  154.         /// <para>[To be supplied.]</para>
  155.         /// </devdoc>
  156.         public int Count {
  157.             get {
  158.                 ListDictionary cachedList = list;
  159.                 if (hashtable != null) {
  160.                     return hashtable.Count;
  161.                 }
  162.                 else if (cachedList != null) {
  163.                     return cachedList.Count;
  164.                 }
  165.                 else {
  166.                     return 0;
  167.                 }
  168.             }
  169.         }
  170.        
  171.         /// <devdoc>
  172.         /// <para>[To be supplied.]</para>
  173.         /// </devdoc>
  174.         public ICollection Keys {
  175.             get {
  176.                 if (hashtable != null) {
  177.                     return hashtable.Keys;
  178.                 }
  179.                 else {
  180.                     return List.Keys;
  181.                 }
  182.             }
  183.         }
  184.        
  185.         /// <devdoc>
  186.         /// <para>[To be supplied.]</para>
  187.         /// </devdoc>
  188.         public bool IsReadOnly {
  189.             get { return false; }
  190.         }
  191.        
  192.         /// <devdoc>
  193.         /// <para>[To be supplied.]</para>
  194.         /// </devdoc>
  195.         public bool IsFixedSize {
  196.             get { return false; }
  197.         }
  198.        
  199.         /// <devdoc>
  200.         /// <para>[To be supplied.]</para>
  201.         /// </devdoc>
  202.         public bool IsSynchronized {
  203.             get { return false; }
  204.         }
  205.        
  206.         /// <devdoc>
  207.         /// <para>[To be supplied.]</para>
  208.         /// </devdoc>
  209.         public object SyncRoot {
  210.             get { return this; }
  211.         }
  212.        
  213.         /// <devdoc>
  214.         /// <para>[To be supplied.]</para>
  215.         /// </devdoc>
  216.         public ICollection Values {
  217.             get {
  218.                 if (hashtable != null) {
  219.                     return hashtable.Values;
  220.                 }
  221.                 else {
  222.                     return List.Values;
  223.                 }
  224.             }
  225.         }
  226.        
  227.         /// <devdoc>
  228.         /// <para>[To be supplied.]</para>
  229.         /// </devdoc>
  230.         public void Add(object key, object value)
  231.         {
  232.             if (hashtable != null) {
  233.                 hashtable.Add(key, value);
  234.             }
  235.             else {
  236.                 if (list == null) {
  237.                     list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
  238.                     list.Add(key, value);
  239.                 }
  240.                 else {
  241.                     if (list.Count + 1 >= CutoverPoint) {
  242.                         ChangeOver();
  243.                         hashtable.Add(key, value);
  244.                     }
  245.                     else {
  246.                         list.Add(key, value);
  247.                     }
  248.                 }
  249.             }
  250.         }
  251.        
  252.         /// <devdoc>
  253.         /// <para>[To be supplied.]</para>
  254.         /// </devdoc>
  255.         public void Clear()
  256.         {
  257.             if (hashtable != null) {
  258.                 Hashtable cachedHashtable = hashtable;
  259.                 hashtable = null;
  260.                 cachedHashtable.Clear();
  261.             }
  262.            
  263.             if (list != null) {
  264.                 ListDictionary cachedList = list;
  265.                 list = null;
  266.                 cachedList.Clear();
  267.             }
  268.         }
  269.        
  270.         /// <devdoc>
  271.         /// <para>[To be supplied.]</para>
  272.         /// </devdoc>
  273.         public bool Contains(object key)
  274.         {
  275.             ListDictionary cachedList = list;
  276.             if (hashtable != null) {
  277.                 return hashtable.Contains(key);
  278.             }
  279.             else if (cachedList != null) {
  280.                 return cachedList.Contains(key);
  281.             }
  282.             else {
  283.                 if (key == null) {
  284.                     throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
  285.                 }
  286.                 return false;
  287.             }
  288.         }
  289.        
  290.         /// <devdoc>
  291.         /// <para>[To be supplied.]</para>
  292.         /// </devdoc>
  293.         public void CopyTo(Array array, int index)
  294.         {
  295.             if (hashtable != null) {
  296.                 hashtable.CopyTo(array, index);
  297.             }
  298.             else {
  299.                 List.CopyTo(array, index);
  300.             }
  301.         }
  302.        
  303.         /// <devdoc>
  304.         /// <para>[To be supplied.]</para>
  305.         /// </devdoc>
  306.         public IDictionaryEnumerator GetEnumerator()
  307.         {
  308.             if (hashtable != null) {
  309.                 return hashtable.GetEnumerator();
  310.             }
  311.             if (list == null) {
  312.                 list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
  313.             }
  314.             return list.GetEnumerator();
  315.         }
  316.        
  317.         /// <devdoc>
  318.         /// <para>[To be supplied.]</para>
  319.         /// </devdoc>
  320.         IEnumerator IEnumerable.GetEnumerator()
  321.         {
  322.             if (hashtable != null) {
  323.                 return hashtable.GetEnumerator();
  324.             }
  325.             if (list == null) {
  326.                 list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
  327.             }
  328.             return list.GetEnumerator();
  329.         }
  330.        
  331.         /// <devdoc>
  332.         /// <para>[To be supplied.]</para>
  333.         /// </devdoc>
  334.         public void Remove(object key)
  335.         {
  336.             if (hashtable != null) {
  337.                 hashtable.Remove(key);
  338.             }
  339.             else if (list != null) {
  340.                 list.Remove(key);
  341.             }
  342.             else {
  343.                 if (key == null) {
  344.                     throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
  345.                 }
  346.             }
  347.         }
  348.     }
  349. }

Developer Fusion