File: compmod\system\collections\specialized\hybriddictionary.cs
Project: ndp\fx\src\System.csproj (System)
//------------------------------------------------------------------------------
// <copyright file="HybridDictionary.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Collections.Specialized {
 
    using System.Collections;
    using System.Globalization;
 
    /// <devdoc>
    ///  <para> 
    ///    This data structure implements IDictionary first using a linked list
    ///    (ListDictionary) and then switching over to use Hashtable when large. This is recommended
    ///    for cases where the number of elements in a dictionary is unknown and might be small.
    ///
    ///    It also has a single boolean parameter to allow case-sensitivity that is not affected by
    ///    ambient culture and has been optimized for looking up case-insensitive symbols
    ///  </para>
    /// </devdoc>
    [Serializable]
    public class HybridDictionary: IDictionary {
 
        // These numbers have been carefully tested to be optimal. Please don't change them
        // without doing thorough performance testing.
        private const int CutoverPoint = 9;
        private const int InitialHashtableSize = 13;
        private const int FixedSizeCutoverPoint = 6;       
 
        // Instance variables. This keeps the HybridDictionary very light-weight when empty
        private ListDictionary list;
        private Hashtable hashtable;
        private bool caseInsensitive;
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public HybridDictionary() {
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public HybridDictionary(int initialSize) : this(initialSize, false) {
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public HybridDictionary(bool caseInsensitive) {
            this.caseInsensitive = caseInsensitive;
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public HybridDictionary(int initialSize, bool caseInsensitive) {
            this.caseInsensitive = caseInsensitive;
            if (initialSize >= FixedSizeCutoverPoint) {
                if (caseInsensitive) {
                    hashtable = new Hashtable(initialSize, StringComparer.OrdinalIgnoreCase);
                } else {
                    hashtable = new Hashtable(initialSize);
                }
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public object this[object key] {
            get {
                // <
 
 
 
 
 
 
                
                ListDictionary cachedList = list;
                if (hashtable != null) {
                    return hashtable[key];
                } else if (cachedList != null) {
                    return cachedList[key];
                } else {
                    // <
 
 
 
 
 
 
 
                    if (key == null) {
                        throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
                    }
                    return null;
                }
            }
            set {
                if (hashtable != null) {
                    hashtable[key] = value;
                } 
                else if (list != null) {
                    if (list.Count >= CutoverPoint - 1) {
                        ChangeOver();
                        hashtable[key] = value;
                    } else {
                        list[key] = value;
                    }
                }
                else {
                    list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
                    list[key] = value;
                }
            }
        }
 
        private ListDictionary List {
            get {
                if (list == null) {
                    list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
                }
                return list;
            }
        }
 
        private void ChangeOver() {
            IDictionaryEnumerator en = list.GetEnumerator();
            Hashtable newTable;            
            if (caseInsensitive) {
                newTable = new Hashtable(InitialHashtableSize, StringComparer.OrdinalIgnoreCase);
            } else {
                newTable = new Hashtable(InitialHashtableSize);
            }
            while (en.MoveNext()) {
                newTable.Add(en.Key, en.Value);
            }
            // <
 
 
 
 
            hashtable = newTable;
            list = null;
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public int Count {
            get {
                ListDictionary cachedList = list;                
                if (hashtable != null) {
                    return hashtable.Count;
                } else if (cachedList != null) {
                    return cachedList.Count;
                } else {
                    return 0;
                }
            }
        }   
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public ICollection Keys {
            get {
                if (hashtable != null) {
                    return hashtable.Keys;
                } else {
                    return List.Keys;
                } 
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public bool IsReadOnly {
            get {
                return false;
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public bool IsFixedSize {
            get {
                return false;
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public bool IsSynchronized {
            get {
                return false;
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public object SyncRoot {
            get {
                return this;
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public ICollection Values {
            get {
                if (hashtable != null) {
                    return hashtable.Values;
                } else {
                    return List.Values;
                } 
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public void Add(object key, object value) {
            if (hashtable != null) {
                hashtable.Add(key, value);
            } else {
                if (list == null) {
                    list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
                    list.Add(key, value); 
                }
                else {
                    if (list.Count + 1 >= CutoverPoint) {
                        ChangeOver();
                        hashtable.Add(key, value);
                    } else {
                        list.Add(key, value); 
                    }
                }
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public void Clear() {
            if(hashtable != null) {
                Hashtable cachedHashtable = hashtable;
                hashtable = null;                
                cachedHashtable.Clear();
            }
 
            if( list != null) {
                ListDictionary cachedList = list;                                
                list = null;                
                cachedList.Clear();
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public bool Contains(object key) {
            ListDictionary cachedList = list;
            if (hashtable != null) {
                return hashtable.Contains(key);
            } else if (cachedList != null) {
                return cachedList.Contains(key);
            } else {
                if (key == null) {
                    throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
                }
                return false;
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public void CopyTo(Array array, int index)  {
            if (hashtable != null) {
                hashtable.CopyTo(array, index);
            } else {
                List.CopyTo(array, index);
            } 
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public IDictionaryEnumerator GetEnumerator() {
            if (hashtable != null) {
                return hashtable.GetEnumerator();
            } 
            if (list == null) {
                list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
            }
            return list.GetEnumerator();
        }
 
        /// <devdoc>
        /// <para>[To be supplied.]</para>
        /// </devdoc>
        IEnumerator IEnumerable.GetEnumerator() {
            if (hashtable != null) {
                return hashtable.GetEnumerator();
            } 
            if (list == null) {
                list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
            }
            return list.GetEnumerator();
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public void Remove(object key) {
            if (hashtable != null) {
                hashtable.Remove(key);
            } 
            else if (list != null){
                list.Remove(key);
            } 
            else {
                if (key == null) {
                    throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
                }                
            }
        }
    }
}