Files
crtr/Assets/Cryville/Common/Collections/Specialized/IntKeyedDictionary.cs
2023-03-26 23:25:20 +08:00

1038 lines
28 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
namespace Cryville.Common.Collections.Specialized {
/// <summary>
/// Represents a collection of <see cref="int" /> keys and values. Identical to <see cref="Dictionary{int, T}" /> but much faster.
/// </summary>
/// <typeparam name="T">The type of the values in the dictionary.</typeparam>
[DebuggerTypeProxy(typeof(IntKeyedDictionaryDebugView<>))]
[DebuggerDisplay("Count = {Count}")]
public class IntKeyedDictionary<T> : IDictionary<int, T>, IDictionary, IReadOnlyDictionary<int, T> {
private struct Entry {
public int next; // Index of next entry, -1 if last
public int key; // Key of entry
public T value; // Value of entry
}
private int[] buckets;
private Entry[] entries;
private int count;
private int version;
private int freeList;
private int freeCount;
private KeyCollection keys;
private ValueCollection values;
private Object _syncRoot;
public IntKeyedDictionary() : this(0) { }
public IntKeyedDictionary(int capacity) {
if (capacity < 0) throw new ArgumentOutOfRangeException("capacity");
if (capacity > 0) Initialize(capacity);
}
public IntKeyedDictionary(IDictionary<int, T> dictionary) :
this(dictionary != null ? dictionary.Count : 0) {
if (dictionary == null) {
throw new ArgumentNullException("dictionary");
}
foreach (KeyValuePair<int, T> pair in dictionary) {
Add(pair.Key, pair.Value);
}
}
public int Count {
get { return count - freeCount; }
}
public KeyCollection Keys {
get {
Contract.Ensures(Contract.Result<KeyCollection>() != null);
if (keys == null) keys = new KeyCollection(this);
return keys;
}
}
ICollection<int> IDictionary<int, T>.Keys {
get {
if (keys == null) keys = new KeyCollection(this);
return keys;
}
}
IEnumerable<int> IReadOnlyDictionary<int, T>.Keys {
get {
if (keys == null) keys = new KeyCollection(this);
return keys;
}
}
public ValueCollection Values {
get {
Contract.Ensures(Contract.Result<ValueCollection>() != null);
if (values == null) values = new ValueCollection(this);
return values;
}
}
ICollection<T> IDictionary<int, T>.Values {
get {
if (values == null) values = new ValueCollection(this);
return values;
}
}
IEnumerable<T> IReadOnlyDictionary<int, T>.Values {
get {
if (values == null) values = new ValueCollection(this);
return values;
}
}
public T this[int key] {
get {
int i = FindEntry(key);
if (i >= 0) return entries[i].value;
throw new KeyNotFoundException();
}
set {
Insert(key, value, false);
}
}
public void Add(int key, T value) {
Insert(key, value, true);
}
void ICollection<KeyValuePair<int, T>>.Add(KeyValuePair<int, T> keyValuePair) {
Add(keyValuePair.Key, keyValuePair.Value);
}
bool ICollection<KeyValuePair<int, T>>.Contains(KeyValuePair<int, T> keyValuePair) {
int i = FindEntry(keyValuePair.Key);
if (i >= 0) {
return true;
}
return false;
}
bool ICollection<KeyValuePair<int, T>>.Remove(KeyValuePair<int, T> keyValuePair) {
int i = FindEntry(keyValuePair.Key);
if (i >= 0) {
Remove(keyValuePair.Key);
return true;
}
return false;
}
public void Clear() {
if (count > 0) {
for (int i = 0; i < buckets.Length; i++) buckets[i] = -1;
Array.Clear(entries, 0, count);
freeList = -1;
count = 0;
freeCount = 0;
version++;
}
}
public bool ContainsKey(int key) {
return FindEntry(key) >= 0;
}
public bool ContainsValue(T value) {
if (value == null) {
for (int i = 0; i < count; i++) {
if (entries[i].key >= 0 && entries[i].value == null) return true;
}
}
else {
EqualityComparer<T> c = EqualityComparer<T>.Default;
for (int i = 0; i < count; i++) {
if (entries[i].key >= 0 && c.Equals(entries[i].value, value)) return true;
}
}
return false;
}
private void CopyTo(KeyValuePair<int, T>[] array, int index) {
if (array == null) {
throw new ArgumentNullException("array");
}
if (index < 0 || index > array.Length) {
throw new ArgumentOutOfRangeException("index", "Non-negative number required.");
}
if (array.Length - index < Count) {
throw new ArgumentException("Destination array is not long enough to copy all the items in the collection. Check array index and length.");
}
int count = this.count;
Entry[] entries = this.entries;
for (int i = 0; i < count; i++) {
if (entries[i].key >= 0) {
array[index++] = new KeyValuePair<int, T>(entries[i].key, entries[i].value);
}
}
}
public Enumerator GetEnumerator() {
return new Enumerator(this, Enumerator.KeyValuePair);
}
IEnumerator<KeyValuePair<int, T>> IEnumerable<KeyValuePair<int, T>>.GetEnumerator() {
return new Enumerator(this, Enumerator.KeyValuePair);
}
private int FindEntry(int key) {
if (buckets != null) {
for (int i = buckets[key % buckets.Length]; i >= 0; i = entries[i].next) {
if (entries[i].key == key) return i;
}
}
return -1;
}
private void Initialize(int capacity) {
int size = HashHelpers.GetPrime(capacity);
buckets = new int[size];
for (int i = 0; i < buckets.Length; i++) buckets[i] = -1;
entries = new Entry[size];
freeList = -1;
}
private void Insert(int key, T value, bool add) {
if (buckets == null) Initialize(0);
int targetBucket = key % buckets.Length;
#if FEATURE_RANDOMIZED_STRING_HASHING
int collisionCount = 0;
#endif
for (int i = buckets[targetBucket]; i >= 0; i = entries[i].next) {
if (entries[i].key == key) {
if (add) {
throw new ArgumentException("An item with the same key has already been added.");
}
entries[i].value = value;
version++;
return;
}
#if FEATURE_RANDOMIZED_STRING_HASHING
collisionCount++;
#endif
}
int index;
if (freeCount > 0) {
index = freeList;
freeList = entries[index].next;
freeCount--;
}
else {
if (count == entries.Length) {
Resize();
targetBucket = key % buckets.Length;
}
index = count;
count++;
}
entries[index].next = buckets[targetBucket];
entries[index].key = key;
entries[index].value = value;
buckets[targetBucket] = index;
version++;
}
private void Resize() {
Resize(HashHelpers.ExpandPrime(count), false);
}
private void Resize(int newSize, bool forceNewHashCodes) {
Contract.Assert(newSize >= entries.Length);
int[] newBuckets = new int[newSize];
for (int i = 0; i < newBuckets.Length; i++) newBuckets[i] = -1;
Entry[] newEntries = new Entry[newSize];
Array.Copy(entries, 0, newEntries, 0, count);
if (forceNewHashCodes) {
for (int i = 0; i < count; i++) {
if (newEntries[i].key != -1) {
newEntries[i].key = newEntries[i].key;
}
}
}
for (int i = 0; i < count; i++) {
if (newEntries[i].key >= 0) {
int bucket = newEntries[i].key % newSize;
newEntries[i].next = newBuckets[bucket];
newBuckets[bucket] = i;
}
}
buckets = newBuckets;
entries = newEntries;
}
public bool Remove(int key) {
if (buckets != null) {
int bucket = key % buckets.Length;
int last = -1;
for (int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next) {
if (entries[i].key == key) {
if (last < 0) {
buckets[bucket] = entries[i].next;
}
else {
entries[last].next = entries[i].next;
}
entries[i].key = -1;
entries[i].next = freeList;
entries[i].value = default(T);
freeList = i;
freeCount++;
version++;
return true;
}
}
}
return false;
}
public bool TryGetValue(int key, out T value) {
int i = FindEntry(key);
if (i >= 0) {
value = entries[i].value;
return true;
}
value = default(T);
return false;
}
// This is a convenience method for the internal callers that were converted from using Hashtable.
// Many were combining key doesn't exist and key exists but null value (for non-value types) checks.
// This allows them to continue getting that behavior with minimal code delta. This is basically
// TryGetValue without the out param
internal T GetValueOrDefault(int key) {
int i = FindEntry(key);
if (i >= 0) {
return entries[i].value;
}
return default(T);
}
bool ICollection<KeyValuePair<int, T>>.IsReadOnly {
get { return false; }
}
void ICollection<KeyValuePair<int, T>>.CopyTo(KeyValuePair<int, T>[] array, int index) {
CopyTo(array, index);
}
void ICollection.CopyTo(Array array, int index) {
if (array == null) {
throw new ArgumentNullException("array");
}
if (array.Rank != 1) {
throw new ArgumentException("Only single dimensional arrays are supported for the requested action.");
}
if (array.GetLowerBound(0) != 0) {
throw new ArgumentException("The lower bound of target array must be zero.");
}
if (index < 0 || index > array.Length) {
throw new ArgumentOutOfRangeException("index", "Non-negative number required.");
}
if (array.Length - index < Count) {
throw new ArgumentException("Destination array is not long enough to copy all the items in the collection. Check array index and length.");
}
KeyValuePair<int,T>[] pairs = array as KeyValuePair<int,T>[];
if (pairs != null) {
CopyTo(pairs, index);
}
else if (array is DictionaryEntry[]) {
DictionaryEntry[] dictEntryArray = array as DictionaryEntry[];
Entry[] entries = this.entries;
for (int i = 0; i < count; i++) {
if (entries[i].key >= 0) {
dictEntryArray[index++] = new DictionaryEntry(entries[i].key, entries[i].value);
}
}
}
else {
object[] objects = array as object[];
if (objects == null) {
throw new ArgumentException("Target array type is not compatible with the type of items in the collection.");
}
try {
int count = this.count;
Entry[] entries = this.entries;
for (int i = 0; i < count; i++) {
if (entries[i].key >= 0) {
objects[index++] = new KeyValuePair<int, T>(entries[i].key, entries[i].value);
}
}
}
catch (ArrayTypeMismatchException) {
throw new ArgumentException("Target array type is not compatible with the type of items in the collection.");
}
}
}
IEnumerator IEnumerable.GetEnumerator() {
return new Enumerator(this, Enumerator.KeyValuePair);
}
bool ICollection.IsSynchronized {
get { return false; }
}
object ICollection.SyncRoot {
get {
if (_syncRoot == null) {
System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null);
}
return _syncRoot;
}
}
bool IDictionary.IsFixedSize {
get { return false; }
}
bool IDictionary.IsReadOnly {
get { return false; }
}
ICollection IDictionary.Keys {
get { return (ICollection)Keys; }
}
ICollection IDictionary.Values {
get { return (ICollection)Values; }
}
object IDictionary.this[object key] {
get {
if (IsCompatibleKey(key)) {
int i = FindEntry((int)key);
if (i >= 0) {
return entries[i].value;
}
}
return null;
}
set {
if (key == null) {
throw new ArgumentNullException("key");
}
if (value == null && default(T) != null) {
throw new ArgumentNullException("value");
}
try {
int tempKey = (int)key;
try {
this[tempKey] = (T)value;
}
catch (InvalidCastException) {
throw new ArgumentException(string.Format("The value \"{0}\" is not of type \"{1}\" and cannot be used in this generic collection.", value, typeof(T)), "value");
}
}
catch (InvalidCastException) {
throw new ArgumentException(string.Format("The value \"{0}\" is not of type \"{1}\" and cannot be used in this generic collection.", key, typeof(int)), "key");
}
}
}
private static bool IsCompatibleKey(object key) {
if (key == null) {
throw new ArgumentNullException("key");
}
return (key is int);
}
void IDictionary.Add(object key, object value) {
if (key == null) {
throw new ArgumentNullException("key");
}
if (value == null && default(T) != null) {
throw new ArgumentNullException("value");
}
try {
int tempKey = (int)key;
try {
Add(tempKey, (T)value);
}
catch (InvalidCastException) {
throw new ArgumentException(string.Format("The value \"{0}\" is not of type \"{1}\" and cannot be used in this generic collection.", value, typeof(T)), "value");
}
}
catch (InvalidCastException) {
throw new ArgumentException(string.Format("The value \"{0}\" is not of type \"{1}\" and cannot be used in this generic collection.", key, typeof(int)), "key");
}
}
bool IDictionary.Contains(object key) {
if (IsCompatibleKey(key)) {
return ContainsKey((int)key);
}
return false;
}
IDictionaryEnumerator IDictionary.GetEnumerator() {
return new Enumerator(this, Enumerator.DictEntry);
}
void IDictionary.Remove(object key) {
if (IsCompatibleKey(key)) {
Remove((int)key);
}
}
[Serializable]
public struct Enumerator : IEnumerator<KeyValuePair<int, T>>,
IDictionaryEnumerator {
private readonly IntKeyedDictionary<T> dictionary;
private readonly int version;
private int index;
private KeyValuePair<int,T> current;
private readonly int getEnumeratorRetType; // What should Enumerator.Current return?
internal const int DictEntry = 1;
internal const int KeyValuePair = 2;
internal Enumerator(IntKeyedDictionary<T> dictionary, int getEnumeratorRetType) {
this.dictionary = dictionary;
version = dictionary.version;
index = 0;
this.getEnumeratorRetType = getEnumeratorRetType;
current = new KeyValuePair<int, T>();
}
public bool MoveNext() {
if (version != dictionary.version) {
throw new InvalidOperationException("Collection was modified; enumeration operation may not execute.");
}
// Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
// dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
while ((uint)index < (uint)dictionary.count) {
if (dictionary.entries[index].key >= 0) {
current = new KeyValuePair<int, T>(dictionary.entries[index].key, dictionary.entries[index].value);
index++;
return true;
}
index++;
}
index = dictionary.count + 1;
current = new KeyValuePair<int, T>();
return false;
}
public KeyValuePair<int, T> Current {
get { return current; }
}
public void Dispose() {
}
object IEnumerator.Current {
get {
if (index == 0 || (index == dictionary.count + 1)) {
throw new InvalidOperationException("Enumeration has either not started or has already finished.");
}
if (getEnumeratorRetType == DictEntry) {
return new System.Collections.DictionaryEntry(current.Key, current.Value);
}
else {
return new KeyValuePair<int, T>(current.Key, current.Value);
}
}
}
void IEnumerator.Reset() {
if (version != dictionary.version) {
throw new InvalidOperationException("Collection was modified; enumeration operation may not execute.");
}
index = 0;
current = new KeyValuePair<int, T>();
}
DictionaryEntry IDictionaryEnumerator.Entry {
get {
if (index == 0 || (index == dictionary.count + 1)) {
throw new InvalidOperationException("Enumeration has either not started or has already finished.");
}
return new DictionaryEntry(current.Key, current.Value);
}
}
object IDictionaryEnumerator.Key {
get {
if (index == 0 || (index == dictionary.count + 1)) {
throw new InvalidOperationException("Enumeration has either not started or has already finished.");
}
return current.Key;
}
}
object IDictionaryEnumerator.Value {
get {
if (index == 0 || (index == dictionary.count + 1)) {
throw new InvalidOperationException("Enumeration has either not started or has already finished.");
}
return current.Value;
}
}
}
[DebuggerTypeProxy(typeof(IntKeyedDictionaryKeyCollectionDebugView<>))]
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public sealed class KeyCollection : ICollection<int>, ICollection, IReadOnlyCollection<int> {
private readonly IntKeyedDictionary<T> dictionary;
public KeyCollection(IntKeyedDictionary<T> dictionary) {
if (dictionary == null) {
throw new ArgumentNullException("dictionary");
}
this.dictionary = dictionary;
}
public Enumerator GetEnumerator() {
return new Enumerator(dictionary);
}
public void CopyTo(int[] array, int index) {
if (array == null) {
throw new ArgumentNullException("array");
}
if (index < 0 || index > array.Length) {
throw new ArgumentOutOfRangeException("index", "Non-negative number required.");
}
if (array.Length - index < dictionary.Count) {
throw new ArgumentException("Destination array is not long enough to copy all the items in the collection. Check array index and length.");
}
int count = dictionary.count;
Entry[] entries = dictionary.entries;
for (int i = 0; i < count; i++) {
if (entries[i].key >= 0) array[index++] = entries[i].key;
}
}
public int Count {
get { return dictionary.Count; }
}
bool ICollection<int>.IsReadOnly {
get { return true; }
}
void ICollection<int>.Add(int item) {
throw new NotSupportedException("Mutating a key collection derived from a dictionary is not allowed.");
}
void ICollection<int>.Clear() {
throw new NotSupportedException("Mutating a key collection derived from a dictionary is not allowed.");
}
bool ICollection<int>.Contains(int item) {
return dictionary.ContainsKey(item);
}
bool ICollection<int>.Remove(int item) {
throw new NotSupportedException("Mutating a key collection derived from a dictionary is not allowed.");
}
IEnumerator<int> IEnumerable<int>.GetEnumerator() {
return new Enumerator(dictionary);
}
IEnumerator IEnumerable.GetEnumerator() {
return new Enumerator(dictionary);
}
void ICollection.CopyTo(Array array, int index) {
if (array == null) {
throw new ArgumentNullException("array");
}
if (array.Rank != 1) {
throw new ArgumentException("Only single dimensional arrays are supported for the requested action.");
}
if (array.GetLowerBound(0) != 0) {
throw new ArgumentException("The lower bound of target array must be zero.");
}
if (index < 0 || index > array.Length) {
throw new ArgumentOutOfRangeException("index", "Non-negative number required.");
}
if (array.Length - index < dictionary.Count) {
throw new ArgumentException("Destination array is not long enough to copy all the items in the collection. Check array index and length.");
}
int[] keys = array as int[];
if (keys != null) {
CopyTo(keys, index);
}
else {
object[] objects = array as object[];
if (objects == null) {
throw new ArgumentException("Target array type is not compatible with the type of items in the collection.");
}
int count = dictionary.count;
Entry[] entries = dictionary.entries;
try {
for (int i = 0; i < count; i++) {
if (entries[i].key >= 0) objects[index++] = entries[i].key;
}
}
catch (ArrayTypeMismatchException) {
throw new ArgumentException("Target array type is not compatible with the type of items in the collection.");
}
}
}
bool ICollection.IsSynchronized {
get { return false; }
}
Object ICollection.SyncRoot {
get { return ((ICollection)dictionary).SyncRoot; }
}
[Serializable]
public struct Enumerator : IEnumerator<int>, System.Collections.IEnumerator {
private readonly IntKeyedDictionary<T> dictionary;
private int index;
private readonly int version;
private int currentKey;
internal Enumerator(IntKeyedDictionary<T> dictionary) {
this.dictionary = dictionary;
version = dictionary.version;
index = 0;
currentKey = default(int);
}
public void Dispose() {
}
public bool MoveNext() {
if (version != dictionary.version) {
throw new InvalidOperationException("Collection was modified; enumeration operation may not execute.");
}
while ((uint)index < (uint)dictionary.count) {
if (dictionary.entries[index].key >= 0) {
currentKey = dictionary.entries[index].key;
index++;
return true;
}
index++;
}
index = dictionary.count + 1;
currentKey = default(int);
return false;
}
public int Current {
get {
return currentKey;
}
}
Object System.Collections.IEnumerator.Current {
get {
if (index == 0 || (index == dictionary.count + 1)) {
throw new InvalidOperationException("Enumeration has either not started or has already finished.");
}
return currentKey;
}
}
void System.Collections.IEnumerator.Reset() {
if (version != dictionary.version) {
throw new InvalidOperationException("Collection was modified; enumeration operation may not execute.");
}
index = 0;
currentKey = default(int);
}
}
}
[DebuggerTypeProxy(typeof(IntKeyedDictionaryValueCollectionDebugView<>))]
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public sealed class ValueCollection : ICollection<T>, ICollection, IReadOnlyCollection<T> {
private readonly IntKeyedDictionary<T> dictionary;
public ValueCollection(IntKeyedDictionary<T> dictionary) {
if (dictionary == null) {
throw new ArgumentNullException("dictionary");
}
this.dictionary = dictionary;
}
public Enumerator GetEnumerator() {
return new Enumerator(dictionary);
}
public void CopyTo(T[] array, int index) {
if (array == null) {
throw new ArgumentNullException("array");
}
if (index < 0 || index > array.Length) {
throw new ArgumentOutOfRangeException("index", "Non-negative number required.");
}
if (array.Length - index < dictionary.Count) {
throw new ArgumentException("Destination array is not long enough to copy all the items in the collection. Check array index and length.");
}
int count = dictionary.count;
Entry[] entries = dictionary.entries;
for (int i = 0; i < count; i++) {
if (entries[i].key >= 0) array[index++] = entries[i].value;
}
}
public int Count {
get { return dictionary.Count; }
}
bool ICollection<T>.IsReadOnly {
get { return true; }
}
void ICollection<T>.Add(T item) {
throw new NotSupportedException("Mutating a value collection derived from a dictionary is not allowed.");
}
bool ICollection<T>.Remove(T item) {
throw new NotSupportedException("Mutating a value collection derived from a dictionary is not allowed.");
}
void ICollection<T>.Clear() {
throw new NotSupportedException("Mutating a value collection derived from a dictionary is not allowed.");
}
bool ICollection<T>.Contains(T item) {
return dictionary.ContainsValue(item);
}
IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return new Enumerator(dictionary);
}
IEnumerator IEnumerable.GetEnumerator() {
return new Enumerator(dictionary);
}
void ICollection.CopyTo(Array array, int index) {
if (array == null) {
throw new ArgumentNullException("array");
}
if (array.Rank != 1) {
throw new ArgumentException("Only single dimensional arrays are supported for the requested action.");
}
if (array.GetLowerBound(0) != 0) {
throw new ArgumentException("The lower bound of target array must be zero.");
}
if (index < 0 || index > array.Length) {
throw new ArgumentOutOfRangeException("index", "Non-negative number required.");
}
if (array.Length - index < dictionary.Count) {
throw new ArgumentException("Destination array is not long enough to copy all the items in the collection. Check array index and length.");
}
T[] values = array as T[];
if (values != null) {
CopyTo(values, index);
}
else {
object[] objects = array as object[];
if (objects == null) {
throw new ArgumentException("Target array type is not compatible with the type of items in the collection.");
}
int count = dictionary.count;
Entry[] entries = dictionary.entries;
try {
for (int i = 0; i < count; i++) {
if (entries[i].key >= 0) objects[index++] = entries[i].value;
}
}
catch (ArrayTypeMismatchException) {
throw new ArgumentException("Target array type is not compatible with the type of items in the collection.");
}
}
}
bool ICollection.IsSynchronized {
get { return false; }
}
Object ICollection.SyncRoot {
get { return ((ICollection)dictionary).SyncRoot; }
}
[Serializable]
public struct Enumerator : IEnumerator<T>, IEnumerator {
private readonly IntKeyedDictionary<T> dictionary;
private int index;
private readonly int version;
private T currentValue;
internal Enumerator(IntKeyedDictionary<T> dictionary) {
this.dictionary = dictionary;
version = dictionary.version;
index = 0;
currentValue = default(T);
}
public void Dispose() {
}
public bool MoveNext() {
if (version != dictionary.version) {
throw new InvalidOperationException("Collection was modified; enumeration operation may not execute.");
}
while ((uint)index < (uint)dictionary.count) {
if (dictionary.entries[index].key >= 0) {
currentValue = dictionary.entries[index].value;
index++;
return true;
}
index++;
}
index = dictionary.count + 1;
currentValue = default(T);
return false;
}
public T Current {
get {
return currentValue;
}
}
Object System.Collections.IEnumerator.Current {
get {
if (index == 0 || (index == dictionary.count + 1)) {
throw new InvalidOperationException("Enumeration has either not started or has already finished.");
}
return currentValue;
}
}
void System.Collections.IEnumerator.Reset() {
if (version != dictionary.version) {
throw new InvalidOperationException("Collection was modified; enumeration operation may not execute.");
}
index = 0;
currentValue = default(T);
}
}
}
}
internal sealed class IntKeyedDictionaryDebugView<T> {
private readonly IntKeyedDictionary<T> dict;
public IntKeyedDictionaryDebugView(IntKeyedDictionary<T> dictionary) {
if (dictionary == null)
throw new ArgumentNullException("dictionary");
this.dict = dictionary;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair<int, T>[] Items {
get {
KeyValuePair<int, T>[] items = new KeyValuePair<int, T>[dict.Count];
((IDictionary)dict).CopyTo(items, 0);
return items;
}
}
}
internal sealed class IntKeyedDictionaryKeyCollectionDebugView<T> {
private readonly IntKeyedDictionary<T> collection;
public IntKeyedDictionaryKeyCollectionDebugView(IntKeyedDictionary<T> collection) {
if (collection == null)
throw new ArgumentNullException("collection");
this.collection = collection;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items {
get {
T[] items = new T[collection.Count];
((IDictionary)collection).CopyTo(items, 0);
return items;
}
}
}
internal sealed class IntKeyedDictionaryValueCollectionDebugView<T> {
private readonly IntKeyedDictionary<T> collection;
public IntKeyedDictionaryValueCollectionDebugView(IntKeyedDictionary<T> collection) {
if (collection == null)
throw new ArgumentNullException("collection");
this.collection = collection;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items {
get {
T[] items = new T[collection.Count];
((IDictionary)collection).CopyTo(items, 0);
return items;
}
}
}
}