e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
339 lines
10 KiB
C#
339 lines
10 KiB
C#
//------------------------------------------------------------------------------
|
|
// <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));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|