diff options
Diffstat (limited to 'src/mscorlib/src/System/Collections')
47 files changed, 3496 insertions, 3767 deletions
diff --git a/src/mscorlib/src/System/Collections/ArrayList.cs b/src/mscorlib/src/System/Collections/ArrayList.cs index 53746e224e..cee7be726a 100644 --- a/src/mscorlib/src/System/Collections/ArrayList.cs +++ b/src/mscorlib/src/System/Collections/ArrayList.cs @@ -14,16 +14,18 @@ ** ** ===========================================================*/ -namespace System.Collections { - using System; - using System.Runtime; - using System.Security; - using System.Diagnostics; - using System.Runtime.CompilerServices; - using System.Runtime.Serialization; - using System.Diagnostics.CodeAnalysis; - using System.Diagnostics.Contracts; +using System; +using System.Runtime; +using System.Security; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; + +namespace System.Collections +{ // Implements a variable-size List that uses an array of objects to store the // elements. A ArrayList has a capacity, which is the allocated length // of the internal array. As elements are added to a ArrayList, the capacity @@ -31,7 +33,7 @@ namespace System.Collections { // internal array. // [FriendAccessAllowed] - [DebuggerTypeProxy(typeof(System.Collections.ArrayList.ArrayListDebugView))] + [DebuggerTypeProxy(typeof(System.Collections.ArrayList.ArrayListDebugView))] [DebuggerDisplay("Count = {Count}")] [Serializable] internal class ArrayList : IList, ICloneable @@ -42,38 +44,41 @@ namespace System.Collections { private int _version; [NonSerialized] private Object _syncRoot; - + private const int _defaultCapacity = 4; - private static readonly Object[] emptyArray = EmptyArray<Object>.Value; + private static readonly Object[] emptyArray = Array.Empty<Object>(); // Constructs a ArrayList. The list is initially empty and has a capacity // of zero. Upon adding the first element to the list the capacity is // increased to _defaultCapacity, and then increased in multiples of two as required. - public ArrayList() { - _items = emptyArray; + public ArrayList() + { + _items = emptyArray; } - + // Constructs a ArrayList with a given initial capacity. The list is // initially empty, but will have room for the given number of elements // before any reallocations are required. // - public ArrayList(int capacity) { - if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity), Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegNum", nameof(capacity))); - Contract.EndContractBlock(); - - if (capacity == 0) - _items = emptyArray; - else - _items = new Object[capacity]; + public ArrayList(int capacity) + { + if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity), SR.Format(SR.ArgumentOutOfRange_MustBeNonNegNum, nameof(capacity))); + Contract.EndContractBlock(); + + if (capacity == 0) + _items = emptyArray; + else + _items = new Object[capacity]; } - + // Constructs a ArrayList, copying the contents of the given collection. The // size and capacity of the new list will both be equal to the size of the // given collection. // - public ArrayList(ICollection c) { - if (c==null) - throw new ArgumentNullException(nameof(c), Environment.GetResourceString("ArgumentNull_Collection")); + public ArrayList(ICollection c) + { + if (c == null) + throw new ArgumentNullException(nameof(c), SR.ArgumentNull_Collection); Contract.EndContractBlock(); int count = c.Count; @@ -81,124 +86,147 @@ namespace System.Collections { { _items = emptyArray; } - else { + else + { _items = new Object[count]; AddRange(c); } } - + // Gets and sets the capacity of this list. The capacity is the size of // the internal array used to hold items. When set, the internal // array of the list is reallocated to the given capacity. // - public virtual int Capacity { - get { + public virtual int Capacity + { + get + { Contract.Ensures(Contract.Result<int>() >= Count); return _items.Length; } - set { - if (value < _size) { - throw new ArgumentOutOfRangeException(nameof(value), Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity")); + set + { + if (value < _size) + { + throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_SmallCapacity); } Contract.Ensures(Capacity >= 0); Contract.EndContractBlock(); // We don't want to update the version number when we change the capacity. // Some existing applications have dependency on this. - if (value != _items.Length) { - if (value > 0) { + if (value != _items.Length) + { + if (value > 0) + { Object[] newItems = new Object[value]; - if (_size > 0) { + if (_size > 0) + { Array.Copy(_items, 0, newItems, 0, _size); } _items = newItems; } - else { + else + { _items = new Object[_defaultCapacity]; } - } + } } } // Read-only property describing how many elements are in the List. - public virtual int Count { - get { + public virtual int Count + { + get + { Contract.Ensures(Contract.Result<int>() >= 0); return _size; } } - public virtual bool IsFixedSize { + public virtual bool IsFixedSize + { get { return false; } } - + // Is this ArrayList read-only? - public virtual bool IsReadOnly { + public virtual bool IsReadOnly + { get { return false; } } // Is this ArrayList synchronized (thread-safe)? - public virtual bool IsSynchronized { + public virtual bool IsSynchronized + { get { return false; } } - + // Synchronization root for this object. - public virtual Object SyncRoot { - get { - if( _syncRoot == null) { - System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); + public virtual Object SyncRoot + { + get + { + if (_syncRoot == null) + { + System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); } - return _syncRoot; + return _syncRoot; } } - + // Sets or Gets the element at the given index. // - public virtual Object this[int index] { - get { - if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index")); + public virtual Object this[int index] + { + get + { + if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); Contract.EndContractBlock(); return _items[index]; } - set { - if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index")); + set + { + if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); Contract.EndContractBlock(); _items[index] = value; _version++; } } - + // Adds the given object to the end of this list. The size of the list is // increased by one. If required, the capacity of the list is doubled // before adding the new element. // - public virtual int Add(Object value) { + public virtual int Add(Object value) + { Contract.Ensures(Contract.Result<int>() >= 0); if (_size == _items.Length) EnsureCapacity(_size + 1); _items[_size] = value; _version++; return _size++; } - + // Adds the elements of the given collection to the end of this list. If // required, the capacity of the list is increased to twice the previous // capacity or the new size, whichever is larger. // - public virtual void AddRange(ICollection c) { + public virtual void AddRange(ICollection c) + { InsertRange(_size, c); } - + // Clears the contents of ArrayList. - public virtual void Clear() { + public virtual void Clear() + { if (_size > 0) { - Array.Clear(_items, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references. - _size = 0; + Array.Clear(_items, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references. + _size = 0; } _version++; } - + // Clones this ArrayList, doing a shallow copy. (A copy is made of all // Object references in the ArrayList, but the Objects pointed to // are not cloned). @@ -211,22 +239,25 @@ namespace System.Collections { Array.Copy(_items, 0, la._items, 0, _size); return la; } - - + + // Contains returns true if the specified element is in the ArrayList. // It does a linear, O(n) search. Equality is determined by calling // item.Equals(). // - public virtual bool Contains(Object item) { - if (item==null) { - for(int i=0; i<_size; i++) - if (_items[i]==null) + public virtual bool Contains(Object item) + { + if (item == null) + { + for (int i = 0; i < _size; i++) + if (_items[i] == null) return true; return false; } - else { - for(int i=0; i<_size; i++) - if ( (_items[i] != null) && (_items[i].Equals(item)) ) + else + { + for (int i = 0; i < _size; i++) + if ((_items[i] != null) && (_items[i].Equals(item))) return true; return false; } @@ -235,9 +266,10 @@ namespace System.Collections { // Copies this ArrayList into array, which must be of a // compatible array type. // - public virtual void CopyTo(Array array, int arrayIndex) { + public virtual void CopyTo(Array array, int arrayIndex) + { if ((array != null) && (array.Rank != 1)) - throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported")); + throw new ArgumentException(SR.Arg_RankMultiDimNotSupported); Contract.EndContractBlock(); // Delegate rest of error checking to Array.Copy. Array.Copy(_items, 0, array, arrayIndex, _size); @@ -247,9 +279,11 @@ namespace System.Collections { // value. If the currect capacity of the list is less than min, the // capacity is increased to twice the current capacity or to min, // whichever is larger. - private void EnsureCapacity(int min) { - if (_items.Length < min) { - int newCapacity = _items.Length == 0? _defaultCapacity: _items.Length * 2; + private void EnsureCapacity(int min) + { + if (_items.Length < min) + { + int newCapacity = _items.Length == 0 ? _defaultCapacity : _items.Length * 2; // Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow. // Note that this check works even when _items.Length overflowed thanks to the (uint) cast if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength; @@ -257,17 +291,18 @@ namespace System.Collections { Capacity = newCapacity; } } - + // Returns an enumerator for this list with the given // permission for removal of elements. If modifications made to the list // while an enumeration is in progress, the MoveNext and // GetObject methods of the enumerator will throw an exception. // - public virtual IEnumerator GetEnumerator() { + public virtual IEnumerator GetEnumerator() + { Contract.Ensures(Contract.Result<IEnumerator>() != null); return new ArrayListEnumeratorSimple(this); } - + // Returns the index of the first occurrence of a given value in a range of // this list. The list is searched forwards from beginning to end. // The elements of the list are compared to the given value using the @@ -276,47 +311,53 @@ namespace System.Collections { // This method uses the Array.IndexOf method to perform the // search. // - public virtual int IndexOf(Object value) { + public virtual int IndexOf(Object value) + { Contract.Ensures(Contract.Result<int>() < Count); return Array.IndexOf((Array)_items, value, 0, _size); } - + // Inserts an element into this list at a given index. The size of the list // is increased by one. If required, the capacity of the list is doubled // before inserting the new element. // - public virtual void Insert(int index, Object value) { + public virtual void Insert(int index, Object value) + { // Note that insertions at the end are legal. - if (index < 0 || index > _size) throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_ArrayListInsert")); + if (index < 0 || index > _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_ArrayListInsert); //Contract.Ensures(Count == Contract.OldValue(Count) + 1); Contract.EndContractBlock(); if (_size == _items.Length) EnsureCapacity(_size + 1); - if (index < _size) { + if (index < _size) + { Array.Copy(_items, index, _items, index + 1, _size - index); } _items[index] = value; _size++; _version++; } - + // Inserts the elements of the given collection at a given index. If // required, the capacity of the list is increased to twice the previous // capacity or the new size, whichever is larger. Ranges may be added // to the end of the list by setting index to the ArrayList's size. // - public virtual void InsertRange(int index, ICollection c) { - if (c==null) - throw new ArgumentNullException(nameof(c), Environment.GetResourceString("ArgumentNull_Collection")); - if (index < 0 || index > _size) throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index")); + public virtual void InsertRange(int index, ICollection c) + { + if (c == null) + throw new ArgumentNullException(nameof(c), SR.ArgumentNull_Collection); + if (index < 0 || index > _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); //Contract.Ensures(Count == Contract.OldValue(Count) + c.Count); Contract.EndContractBlock(); int count = c.Count; - if (count > 0) { - EnsureCapacity(_size + count); + if (count > 0) + { + EnsureCapacity(_size + count); // shift existing items - if (index < _size) { + if (index < _size) + { Array.Copy(_items, index, _items, index + count, _size - index); } @@ -327,54 +368,59 @@ namespace System.Collections { _version++; } } - + // Returns a read-only IList wrapper for the given IList. // [FriendAccessAllowed] - public static IList ReadOnly(IList list) { - if (list==null) + public static IList ReadOnly(IList list) + { + if (list == null) throw new ArgumentNullException(nameof(list)); Contract.Ensures(Contract.Result<IList>() != null); Contract.EndContractBlock(); return new ReadOnlyList(list); } - + // Removes the element at the given index. The size of the list is // decreased by one. // - public virtual void Remove(Object obj) { + public virtual void Remove(Object obj) + { Contract.Ensures(Count >= 0); int index = IndexOf(obj); - BCLDebug.Correctness(index >= 0 || !(obj is Int32), "You passed an Int32 to Remove that wasn't in the ArrayList." + Environment.NewLine + "Did you mean RemoveAt? int: "+obj+" Count: "+Count); - if (index >=0) + BCLDebug.Correctness(index >= 0 || !(obj is Int32), "You passed an Int32 to Remove that wasn't in the ArrayList." + Environment.NewLine + "Did you mean RemoveAt? int: " + obj + " Count: " + Count); + if (index >= 0) RemoveAt(index); } - + // Removes the element at the given index. The size of the list is // decreased by one. // - public virtual void RemoveAt(int index) { - if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index")); + public virtual void RemoveAt(int index) + { + if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); Contract.Ensures(Count >= 0); //Contract.Ensures(Count == Contract.OldValue(Count) - 1); Contract.EndContractBlock(); _size--; - if (index < _size) { + if (index < _size) + { Array.Copy(_items, index + 1, _items, index, _size - index); } _items[_size] = null; _version++; } - + // ToArray returns a new array of a particular type containing the contents // of the ArrayList. This requires copying the ArrayList and potentially // downcasting all elements. This copy may fail and is an O(n) operation. // Internally, this implementation calls Array.Copy. // - public virtual Array ToArray(Type type) { - if (type==null) + public virtual Array ToArray(Type type) + { + if (type == null) throw new ArgumentNullException(nameof(type)); Contract.Ensures(Contract.Result<Array>() != null); Contract.EndContractBlock(); @@ -382,84 +428,103 @@ namespace System.Collections { Array.Copy(_items, 0, array, 0, _size); return array; } - + [Serializable] private class ReadOnlyList : IList { private IList _list; - - internal ReadOnlyList(IList l) { + + internal ReadOnlyList(IList l) + { _list = l; } - - public virtual int Count { + + public virtual int Count + { get { return _list.Count; } } - - public virtual bool IsReadOnly { + + public virtual bool IsReadOnly + { get { return true; } } - public virtual bool IsFixedSize { + public virtual bool IsFixedSize + { get { return true; } } - public virtual bool IsSynchronized { + public virtual bool IsSynchronized + { get { return _list.IsSynchronized; } } - - public virtual Object this[int index] { - get { + + public virtual Object this[int index] + { + get + { return _list[index]; } - set { - throw new NotSupportedException(Environment.GetResourceString("NotSupported_ReadOnlyCollection")); + set + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); } } - - public virtual Object SyncRoot { + + public virtual Object SyncRoot + { get { return _list.SyncRoot; } } - - public virtual int Add(Object obj) { - throw new NotSupportedException(Environment.GetResourceString("NotSupported_ReadOnlyCollection")); + + public virtual int Add(Object obj) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); } - - public virtual void Clear() { - throw new NotSupportedException(Environment.GetResourceString("NotSupported_ReadOnlyCollection")); + + public virtual void Clear() + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); } - - public virtual bool Contains(Object obj) { + + public virtual bool Contains(Object obj) + { return _list.Contains(obj); } - - public virtual void CopyTo(Array array, int index) { + + public virtual void CopyTo(Array array, int index) + { _list.CopyTo(array, index); } - - public virtual IEnumerator GetEnumerator() { + + public virtual IEnumerator GetEnumerator() + { return _list.GetEnumerator(); } - - public virtual int IndexOf(Object value) { + + public virtual int IndexOf(Object value) + { return _list.IndexOf(value); } - - public virtual void Insert(int index, Object obj) { - throw new NotSupportedException(Environment.GetResourceString("NotSupported_ReadOnlyCollection")); + + public virtual void Insert(int index, Object obj) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); } - public virtual void Remove(Object value) { - throw new NotSupportedException(Environment.GetResourceString("NotSupported_ReadOnlyCollection")); + public virtual void Remove(Object value) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); } - - public virtual void RemoveAt(int index) { - throw new NotSupportedException(Environment.GetResourceString("NotSupported_ReadOnlyCollection")); + + public virtual void RemoveAt(int index) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); } } [Serializable] - private sealed class ArrayListEnumeratorSimple : IEnumerator, ICloneable { + private sealed class ArrayListEnumeratorSimple : IEnumerator, ICloneable + { private ArrayList list; private int index; private int version; @@ -467,77 +532,95 @@ namespace System.Collections { [NonSerialized] private bool isArrayList; // this object is used to indicate enumeration has not started or has terminated - static Object dummyObject = new Object(); - - internal ArrayListEnumeratorSimple(ArrayList list) { + private static Object dummyObject = new Object(); + + internal ArrayListEnumeratorSimple(ArrayList list) + { this.list = list; - this.index = -1; + index = -1; version = list._version; isArrayList = (list.GetType() == typeof(ArrayList)); - currentElement = dummyObject; + currentElement = dummyObject; } - - public Object Clone() { + + public Object Clone() + { return MemberwiseClone(); } - - public bool MoveNext() { - if (version != list._version) { - throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumFailedVersion)); + + public bool MoveNext() + { + if (version != list._version) + { + throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumFailedVersion)); } - if( isArrayList) { // avoid calling virtual methods if we are operating on ArrayList to improve performance - if (index < list._size - 1) { + if (isArrayList) + { // avoid calling virtual methods if we are operating on ArrayList to improve performance + if (index < list._size - 1) + { currentElement = list._items[++index]; return true; } - else { + else + { currentElement = dummyObject; - index =list._size; + index = list._size; return false; - } + } } - else { - if (index < list.Count - 1) { + else + { + if (index < list.Count - 1) + { currentElement = list[++index]; return true; } - else { + else + { index = list.Count; currentElement = dummyObject; return false; } } } - - public Object Current { - get { + + public Object Current + { + get + { object temp = currentElement; - if(dummyObject == temp) { // check if enumeration has not started or has terminated - if (index == -1) { - throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted)); + if (dummyObject == temp) + { // check if enumeration has not started or has terminated + if (index == -1) + { + throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumNotStarted)); } - else { - throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded)); + else + { + throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumEnded)); } } return temp; } } - - public void Reset() { - if (version != list._version) { - throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumFailedVersion)); - } - + + public void Reset() + { + if (version != list._version) + { + throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumFailedVersion)); + } + currentElement = dummyObject; index = -1; } } - internal class ArrayListDebugView { - private ArrayList arrayList; + internal class ArrayListDebugView + { + private ArrayList arrayList; } - } + } } diff --git a/src/mscorlib/src/System/Collections/CollectionBase.cs b/src/mscorlib/src/System/Collections/CollectionBase.cs deleted file mode 100644 index a3dd88a7b3..0000000000 --- a/src/mscorlib/src/System/Collections/CollectionBase.cs +++ /dev/null @@ -1,199 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -// - -namespace System.Collections { - using System; - using System.Diagnostics.Contracts; - - // Useful base class for typed read/write collections where items derive from object - [Serializable] - public abstract class CollectionBase : IList { - private ArrayList list; - - protected CollectionBase() { - list = new ArrayList(); - } - - internal ArrayList InnerList { - get { - if (list == null) - list = new ArrayList(); - return list; - } - } - - protected IList List { - get { return (IList)this; } - } - - - public int Count { - get { - return list == null ? 0 : list.Count; - } - } - - public void Clear() { - OnClear(); - InnerList.Clear(); - OnClearComplete(); - } - - public void RemoveAt(int index) { - if (index < 0 || index >= Count) - throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index")); - Contract.EndContractBlock(); - Object temp = InnerList[index]; - OnValidate(temp); - OnRemove(index, temp); - InnerList.RemoveAt(index); - try { - OnRemoveComplete(index, temp); - } - catch { - InnerList.Insert(index, temp); - throw; - } - - } - - bool IList.IsReadOnly { - get { return InnerList.IsReadOnly; } - } - - bool IList.IsFixedSize { - get { return InnerList.IsFixedSize; } - } - - bool ICollection.IsSynchronized { - get { return InnerList.IsSynchronized; } - } - - Object ICollection.SyncRoot { - get { return InnerList.SyncRoot; } - } - - void ICollection.CopyTo(Array array, int index) { - InnerList.CopyTo(array, index); - } - - Object IList.this[int index] { - get { - if (index < 0 || index >= Count) - throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index")); - Contract.EndContractBlock(); - return InnerList[index]; - } - set { - if (index < 0 || index >= Count) - throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index")); - Contract.EndContractBlock(); - OnValidate(value); - Object temp = InnerList[index]; - OnSet(index, temp, value); - InnerList[index] = value; - try { - OnSetComplete(index, temp, value); - } - catch { - InnerList[index] = temp; - throw; - } - } - } - - bool IList.Contains(Object value) { - return InnerList.Contains(value); - } - - int IList.Add(Object value) { - OnValidate(value); - OnInsert(InnerList.Count, value); - int index = InnerList.Add(value); - try { - OnInsertComplete(index, value); - } - catch { - InnerList.RemoveAt(index); - throw; - } - return index; - } - - - void IList.Remove(Object value) { - OnValidate(value); - int index = InnerList.IndexOf(value); - if (index < 0) throw new ArgumentException(Environment.GetResourceString("Arg_RemoveArgNotFound")); - OnRemove(index, value); - InnerList.RemoveAt(index); - try{ - OnRemoveComplete(index, value); - } - catch { - InnerList.Insert(index, value); - throw; - } - } - - int IList.IndexOf(Object value) { - return InnerList.IndexOf(value); - } - - void IList.Insert(int index, Object value) { - if (index < 0 || index > Count) - throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index")); - Contract.EndContractBlock(); - OnValidate(value); - OnInsert(index, value); - InnerList.Insert(index, value); - try { - OnInsertComplete(index, value); - } - catch { - InnerList.RemoveAt(index); - throw; - } - } - - public IEnumerator GetEnumerator() { - return InnerList.GetEnumerator(); - } - - protected virtual void OnSet(int index, Object oldValue, Object newValue) { - } - - protected virtual void OnInsert(int index, Object value) { - } - - protected virtual void OnClear() { - } - - protected virtual void OnRemove(int index, Object value) { - } - - protected virtual void OnValidate(Object value) { - if (value == null) throw new ArgumentNullException(nameof(value)); - Contract.EndContractBlock(); - } - - protected virtual void OnSetComplete(int index, Object oldValue, Object newValue) { - } - - protected virtual void OnInsertComplete(int index, Object value) { - } - - protected virtual void OnClearComplete() { - } - - protected virtual void OnRemoveComplete(int index, Object value) { - } - - } - -} diff --git a/src/mscorlib/src/System/Collections/Comparer.cs b/src/mscorlib/src/System/Collections/Comparer.cs index 928b0f9f9a..7f4f9f0a07 100644 --- a/src/mscorlib/src/System/Collections/Comparer.cs +++ b/src/mscorlib/src/System/Collections/Comparer.cs @@ -12,46 +12,53 @@ ** ** ===========================================================*/ -namespace System.Collections { - - using System; - using System.Globalization; - using System.Runtime.Serialization; - using System.Diagnostics.Contracts; +using System; +using System.Globalization; +using System.Runtime.Serialization; +using System.Diagnostics.Contracts; + +namespace System.Collections +{ [Serializable] - internal sealed class Comparer : IComparer , ISerializable + internal sealed class Comparer : IComparer, ISerializable { - private CompareInfo m_compareInfo; + private CompareInfo m_compareInfo; public static readonly Comparer Default = new Comparer(CultureInfo.CurrentCulture); public static readonly Comparer DefaultInvariant = new Comparer(CultureInfo.InvariantCulture); - + private const String CompareInfoName = "CompareInfo"; - private Comparer() { + private Comparer() + { m_compareInfo = null; } - public Comparer(CultureInfo culture) { - if (culture==null) { + public Comparer(CultureInfo culture) + { + if (culture == null) + { throw new ArgumentNullException(nameof(culture)); } Contract.EndContractBlock(); m_compareInfo = culture.CompareInfo; } - - private Comparer(SerializationInfo info, StreamingContext context) { + + private Comparer(SerializationInfo info, StreamingContext context) + { m_compareInfo = null; - SerializationInfoEnumerator enumerator = info.GetEnumerator(); - while( enumerator.MoveNext()) { - switch( enumerator.Name) { + SerializationInfoEnumerator enumerator = info.GetEnumerator(); + while (enumerator.MoveNext()) + { + switch (enumerator.Name) + { case CompareInfoName: - m_compareInfo = (CompareInfo) info.GetValue(CompareInfoName, typeof(CompareInfo)); + m_compareInfo = (CompareInfo)info.GetValue(CompareInfoName, typeof(CompareInfo)); break; } } } - + // Compares two Objects by calling CompareTo. If a == // b,0 is returned. If a implements // IComparable, a.CompareTo(b) is returned. If a @@ -59,11 +66,13 @@ namespace System.Collections { // -(b.CompareTo(a)) is returned, otherwise an // exception is thrown. // - public int Compare(Object a, Object b) { + public int Compare(Object a, Object b) + { if (a == b) return 0; if (a == null) return -1; if (b == null) return 1; - if (m_compareInfo != null) { + if (m_compareInfo != null) + { String sa = a as String; String sb = b as String; if (sa != null && sb != null) @@ -78,18 +87,21 @@ namespace System.Collections { if (ib != null) return -ib.CompareTo(a); - throw new ArgumentException(Environment.GetResourceString("Argument_ImplementIComparable")); + throw new ArgumentException(SR.Argument_ImplementIComparable); } - public void GetObjectData(SerializationInfo info, StreamingContext context) { - if (info==null) { + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { throw new ArgumentNullException(nameof(info)); } Contract.EndContractBlock(); - if( m_compareInfo != null) { + if (m_compareInfo != null) + { info.AddValue(CompareInfoName, m_compareInfo); } - } + } } } diff --git a/src/mscorlib/src/System/Collections/CompatibleComparer.cs b/src/mscorlib/src/System/Collections/CompatibleComparer.cs index e5d3961245..1c90707184 100644 --- a/src/mscorlib/src/System/Collections/CompatibleComparer.cs +++ b/src/mscorlib/src/System/Collections/CompatibleComparer.cs @@ -6,39 +6,45 @@ using System.Diagnostics.Contracts; -namespace System.Collections { - +namespace System.Collections +{ [Serializable] - internal class CompatibleComparer: IEqualityComparer { - IComparer _comparer; + internal class CompatibleComparer : IEqualityComparer + { + private IComparer _comparer; #pragma warning disable 618 - IHashCodeProvider _hcp; + private IHashCodeProvider _hcp; - internal CompatibleComparer(IComparer comparer, IHashCodeProvider hashCodeProvider) { + internal CompatibleComparer(IComparer comparer, IHashCodeProvider hashCodeProvider) + { _comparer = comparer; _hcp = hashCodeProvider; } #pragma warning restore 618 - public int Compare(Object a, Object b) { + public int Compare(Object a, Object b) + { if (a == b) return 0; if (a == null) return -1; if (b == null) return 1; if (_comparer != null) - return _comparer.Compare(a,b); + return _comparer.Compare(a, b); IComparable ia = a as IComparable; if (ia != null) return ia.CompareTo(b); - throw new ArgumentException(Environment.GetResourceString("Argument_ImplementIComparable")); + throw new ArgumentException(SR.Argument_ImplementIComparable); } - public new bool Equals(Object a, Object b) { - return Compare(a, b) == 0; + public new bool Equals(Object a, Object b) + { + return Compare(a, b) == 0; } - public int GetHashCode(Object obj) { - if( obj == null) { + public int GetHashCode(Object obj) + { + if (obj == null) + { throw new ArgumentNullException(nameof(obj)); } Contract.EndContractBlock(); @@ -49,16 +55,20 @@ namespace System.Collections { } // These are helpers for the Hashtable to query the IKeyComparer infrastructure. - internal IComparer Comparer { - get { + internal IComparer Comparer + { + get + { return _comparer; } } // These are helpers for the Hashtable to query the IKeyComparer infrastructure. #pragma warning disable 618 - internal IHashCodeProvider HashCodeProvider { - get { + internal IHashCodeProvider HashCodeProvider + { + get + { return _hcp; } } diff --git a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentDictionary.cs b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentDictionary.cs index 8b9014a103..436808c439 100644 --- a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentDictionary.cs +++ b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentDictionary.cs @@ -65,7 +65,7 @@ namespace System.Collections.Concurrent private volatile Tables m_tables; // Internal tables of the dictionary // NOTE: this is only used for compat reasons to serialize the comparer. // This should not be accessed from anywhere else outside of the serialization methods. - internal IEqualityComparer<TKey> m_comparer; + internal IEqualityComparer<TKey> m_comparer; private readonly bool m_growLockArray; // Whether to dynamically increase the size of the striped lock // How many times we resized becaused of collisions. @@ -102,6 +102,10 @@ namespace System.Collections.Concurrent private static bool IsValueWriteAtomic() { Type valueType = typeof(TValue); + if (valueType.IsEnum) + { + valueType = Enum.GetUnderlyingType(valueType); + } // // Section 12.6.6 of ECMA CLI explains which types can be read and written atomically without @@ -705,7 +709,6 @@ namespace System.Collections.Concurrent { count += m_tables.m_countPerLock[i]; } - } finally { @@ -1404,7 +1407,6 @@ namespace System.Collections.Concurrent /// </summary> private static int DefaultConcurrencyLevel { - get { return DEFAULT_CONCURRENCY_MULTIPLIER * PlatformHelper.ProcessorCount; } } @@ -1559,7 +1561,7 @@ namespace System.Collections.Concurrent /// </summary> private class DictionaryEnumerator : IDictionaryEnumerator { - IEnumerator<KeyValuePair<TKey, TValue>> m_enumerator; // Enumerator over the dictionary. + private IEnumerator<KeyValuePair<TKey, TValue>> m_enumerator; // Enumerator over the dictionary. internal DictionaryEnumerator(ConcurrentDictionary<TKey, TValue> dictionary) { diff --git a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentQueue.cs b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentQueue.cs index 90ada007dd..c6211dadd3 100644 --- a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentQueue.cs +++ b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentQueue.cs @@ -205,7 +205,7 @@ namespace System.Collections.Concurrent /// cref="ICollection"/>. This property is not supported. /// </summary> /// <exception cref="NotSupportedException">The SyncRoot property is not supported.</exception> - object ICollection.SyncRoot { get { throw new NotSupportedException(Environment.GetResourceString("ConcurrentCollection_SyncRoot_NotSupported")); } } + object ICollection.SyncRoot { get { throw new NotSupportedException(SR.ConcurrentCollection_SyncRoot_NotSupported); } } /// <summary>Returns an enumerator that iterates through a collection.</summary> /// <returns>An <see cref="IEnumerator"/> that can be used to iterate through the collection.</returns> @@ -443,7 +443,7 @@ namespace System.Collections.Concurrent long count = GetCount(head, headHead, tail, tailTail); if (index > array.Length - count) { - throw new ArgumentException(Environment.GetResourceString("Arg_ArrayPlusOffTooSmall")); + throw new ArgumentException(SR.Arg_ArrayPlusOffTooSmall); } // Copy the items to the target array @@ -1115,7 +1115,7 @@ namespace System.Collections.Concurrent [StructLayout(LayoutKind.Explicit, Size = 192)] // padding before/between/after fields based on typical cache line size of 64 internal struct PaddedHeadAndTail { - [FieldOffset(64)] public int Head; + [FieldOffset(64)] public int Head; [FieldOffset(128)] public int Tail; } } diff --git a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs index 10a5201f6c..82bc4f9f5c 100644 --- a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs +++ b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs @@ -135,7 +135,7 @@ namespace System.Collections.Concurrent { get { - throw new NotSupportedException(Environment.GetResourceString("ConcurrentCollection_SyncRoot_NotSupported")); + throw new NotSupportedException(SR.ConcurrentCollection_SyncRoot_NotSupported); } } @@ -306,7 +306,6 @@ namespace System.Collections.Concurrent result = default(T); return false; - } /// <summary> @@ -328,7 +327,7 @@ namespace System.Collections.Concurrent Node head; Node next; int backoff = 1; - Random r = new Random(Environment.TickCount & Int32.MaxValue); // avoid the case where TickCount could return Int32.MinValue + Random r = null; while (true) { head = m_head; @@ -359,7 +358,18 @@ namespace System.Collections.Concurrent spin.SpinOnce(); } - backoff = spin.NextSpinWillYield ? r.Next(1, BACKOFF_MAX_YIELDS) : backoff * 2; + if (spin.NextSpinWillYield) + { + if (r == null) + { + r = new Random(); + } + backoff = r.Next(1, BACKOFF_MAX_YIELDS); + } + else + { + backoff *= 2; + } } } diff --git a/src/mscorlib/src/System/Collections/Concurrent/IProducerConsumerCollection.cs b/src/mscorlib/src/System/Collections/Concurrent/IProducerConsumerCollection.cs index 0347ece0ec..7c585d8b98 100644 --- a/src/mscorlib/src/System/Collections/Concurrent/IProducerConsumerCollection.cs +++ b/src/mscorlib/src/System/Collections/Concurrent/IProducerConsumerCollection.cs @@ -16,7 +16,6 @@ using System.Diagnostics; namespace System.Collections.Concurrent { - /// <summary> /// Defines methods to manipulate thread-safe collections intended for producer/consumer usage. /// </summary> @@ -64,6 +63,5 @@ namespace System.Collections.Concurrent internal sealed class SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView<T> { private IProducerConsumerCollection<T> m_collection; // The collection being viewed. - } } diff --git a/src/mscorlib/src/System/Collections/DictionaryEntry.cs b/src/mscorlib/src/System/Collections/DictionaryEntry.cs deleted file mode 100644 index 0c5d8b2387..0000000000 --- a/src/mscorlib/src/System/Collections/DictionaryEntry.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: DictionaryEntry -** -** -** -** -** Purpose: Return Value for IDictionaryEnumerator::GetEntry -** -** -===========================================================*/ -namespace System.Collections { - - using System; - using System.ComponentModel; - // A DictionaryEntry holds a key and a value from a dictionary. - // It is returned by IDictionaryEnumerator::GetEntry(). - [Serializable] - public struct DictionaryEntry - { - private Object _key; - private Object _value; - - // Constructs a new DictionaryEnumerator by setting the Key - // and Value fields appropriately. - public DictionaryEntry(Object key, Object value) { - _key = key; - _value = value; - } - - public Object Key { - get { - return _key; - } - - set { - _key = value; - } - } - - public Object Value { - get { - return _value; - } - - set { - _value = value; - } - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out object key, out object value) - { - key = Key; - value = Value; - } - } -} diff --git a/src/mscorlib/src/System/Collections/EmptyReadOnlyDictionaryInternal.cs b/src/mscorlib/src/System/Collections/EmptyReadOnlyDictionaryInternal.cs index a610fce016..63e0d47c75 100644 --- a/src/mscorlib/src/System/Collections/EmptyReadOnlyDictionaryInternal.cs +++ b/src/mscorlib/src/System/Collections/EmptyReadOnlyDictionaryInternal.cs @@ -15,178 +15,218 @@ using System.Diagnostics.Contracts; -namespace System.Collections { +namespace System.Collections +{ /// This is a simple implementation of IDictionary that is empty and readonly. [Serializable] - internal sealed class EmptyReadOnlyDictionaryInternal: IDictionary { - + internal sealed class EmptyReadOnlyDictionaryInternal : IDictionary + { // Note that this class must be agile with respect to AppDomains. See its usage in // System.Exception to understand why this is the case. - public EmptyReadOnlyDictionaryInternal() { + public EmptyReadOnlyDictionaryInternal() + { } // IEnumerable members - IEnumerator IEnumerable.GetEnumerator() { + IEnumerator IEnumerable.GetEnumerator() + { return new NodeEnumerator(); } // ICollection members - public void CopyTo(Array array, int index) { - if (array==null) + public void CopyTo(Array array, int index) + { + if (array == null) throw new ArgumentNullException(nameof(array)); if (array.Rank != 1) - throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported")); + throw new ArgumentException(SR.Arg_RankMultiDimNotSupported); if (index < 0) - throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); - if ( array.Length - index < this.Count ) - throw new ArgumentException( Environment.GetResourceString("ArgumentOutOfRange_Index"), nameof(index)); + if (array.Length - index < this.Count) + throw new ArgumentException(SR.ArgumentOutOfRange_Index, nameof(index)); Contract.EndContractBlock(); // the actual copy is a NOP } - public int Count { - get { + public int Count + { + get + { return 0; } - } + } - public Object SyncRoot { - get { + public Object SyncRoot + { + get + { return this; } } - public bool IsSynchronized { - get { + public bool IsSynchronized + { + get + { return false; } } // IDictionary members - public Object this[Object key] { - get { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + public Object this[Object key] + { + get + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } Contract.EndContractBlock(); return null; } - set { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + set + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } - if (!key.GetType().IsSerializable) - throw new ArgumentException(Environment.GetResourceString("Argument_NotSerializable"), nameof(key)); + if (!key.GetType().IsSerializable) + throw new ArgumentException(SR.Argument_NotSerializable, nameof(key)); - if( (value != null) && (!value.GetType().IsSerializable ) ) - throw new ArgumentException(Environment.GetResourceString("Argument_NotSerializable"), nameof(value)); + if ((value != null) && (!value.GetType().IsSerializable)) + throw new ArgumentException(SR.Argument_NotSerializable, nameof(value)); Contract.EndContractBlock(); - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly")); + throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); } } - public ICollection Keys { - get { - return EmptyArray<Object>.Value; + public ICollection Keys + { + get + { + return Array.Empty<Object>(); } } - public ICollection Values { - get { - return EmptyArray<Object>.Value; + public ICollection Values + { + get + { + return Array.Empty<Object>(); } } - public bool Contains(Object key) { + public bool Contains(Object key) + { return false; } - public void Add(Object key, Object value) { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + public void Add(Object key, Object value) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } - if (!key.GetType().IsSerializable) - throw new ArgumentException(Environment.GetResourceString("Argument_NotSerializable"), nameof(key) ); + if (!key.GetType().IsSerializable) + throw new ArgumentException(SR.Argument_NotSerializable, nameof(key)); - if( (value != null) && (!value.GetType().IsSerializable) ) - throw new ArgumentException(Environment.GetResourceString("Argument_NotSerializable"), nameof(value)); + if ((value != null) && (!value.GetType().IsSerializable)) + throw new ArgumentException(SR.Argument_NotSerializable, nameof(value)); Contract.EndContractBlock(); - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly")); + throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); } - public void Clear() { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly")); + public void Clear() + { + throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); } - public bool IsReadOnly { - get { + public bool IsReadOnly + { + get + { return true; } } - public bool IsFixedSize { - get { + public bool IsFixedSize + { + get + { return true; } } - public IDictionaryEnumerator GetEnumerator() { + public IDictionaryEnumerator GetEnumerator() + { return new NodeEnumerator(); } - public void Remove(Object key) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly")); + public void Remove(Object key) + { + throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); } - private sealed class NodeEnumerator : IDictionaryEnumerator { - - public NodeEnumerator() { + private sealed class NodeEnumerator : IDictionaryEnumerator + { + public NodeEnumerator() + { } // IEnumerator members - public bool MoveNext() { + public bool MoveNext() + { return false; } - public Object Current { - get { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumOpCantHappen")); + public Object Current + { + get + { + throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen); } } - public void Reset() { + public void Reset() + { } // IDictionaryEnumerator members - public Object Key { - get { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumOpCantHappen")); + public Object Key + { + get + { + throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen); } } - public Object Value { - get { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumOpCantHappen")); + public Object Value + { + get + { + throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen); } } - public DictionaryEntry Entry { - get { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumOpCantHappen")); + public DictionaryEntry Entry + { + get + { + throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen); } } } diff --git a/src/mscorlib/src/System/Collections/Generic/ArraySortHelper.cs b/src/mscorlib/src/System/Collections/Generic/ArraySortHelper.cs index 298ac3e177..e313cda0fb 100644 --- a/src/mscorlib/src/System/Collections/Generic/ArraySortHelper.cs +++ b/src/mscorlib/src/System/Collections/Generic/ArraySortHelper.cs @@ -12,15 +12,16 @@ ** ** ===========================================================*/ + +using System; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Runtime.Versioning; + namespace System.Collections.Generic { - using System; - using System.Globalization; - using System.Runtime.CompilerServices; - using System.Diagnostics; - using System.Diagnostics.Contracts; - using System.Runtime.Versioning; - #region ArraySortHelper for single arrays internal interface IArraySortHelper<TKey> @@ -36,8 +37,6 @@ namespace System.Collections.Generic // Large value types may benefit from a smaller number. internal const int IntrosortSizeThreshold = 16; - internal const int QuickSortDepthThreshold = 32; - internal static int FloorLog2(int n) { int result = 0; @@ -49,18 +48,18 @@ namespace System.Collections.Generic return result; } - internal static void ThrowOrIgnoreBadComparer(Object comparer) { - throw new ArgumentException(Environment.GetResourceString("Arg_BogusIComparer", comparer)); + internal static void ThrowOrIgnoreBadComparer(Object comparer) + { + throw new ArgumentException(SR.Format(SR.Arg_BogusIComparer, comparer)); } - } - [TypeDependencyAttribute("System.Collections.Generic.GenericArraySortHelper`1")] - internal class ArraySortHelper<T> + [TypeDependencyAttribute("System.Collections.Generic.GenericArraySortHelper`1")] + internal class ArraySortHelper<T> : IArraySortHelper<T> { - static volatile IArraySortHelper<T> defaultArraySortHelper; - + private static volatile IArraySortHelper<T> defaultArraySortHelper; + public static IArraySortHelper<T> Default { get @@ -71,8 +70,8 @@ namespace System.Collections.Generic return sorter; } - } - + } + private static IArraySortHelper<T> CreateArraySortHelper() { if (typeof(IComparable<T>).IsAssignableFrom(typeof(T))) @@ -81,7 +80,7 @@ namespace System.Collections.Generic } else { - defaultArraySortHelper = new ArraySortHelper<T>(); + defaultArraySortHelper = new ArraySortHelper<T>(); } return defaultArraySortHelper; } @@ -91,7 +90,7 @@ namespace System.Collections.Generic public void Sort(T[] keys, int index, int length, IComparer<T> comparer) { Debug.Assert(keys != null, "Check the arguments in the caller!"); - Debug.Assert( index >= 0 && length >= 0 && (keys.Length - index >= length), "Check the arguments in the caller!"); + Debug.Assert(index >= 0 && length >= 0 && (keys.Length - index >= length), "Check the arguments in the caller!"); // Add a try block here to detect IComparers (or their // underlying IComparables, etc) that are bogus. @@ -110,7 +109,7 @@ namespace System.Collections.Generic } catch (Exception e) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), e); + throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); } } @@ -127,7 +126,7 @@ namespace System.Collections.Generic } catch (Exception e) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), e); + throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); } } @@ -150,7 +149,7 @@ namespace System.Collections.Generic } catch (Exception e) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), e); + throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); } } @@ -241,9 +240,9 @@ namespace System.Collections.Generic } if (partitionSize == 3) { - SwapIfGreater(keys, comparer, lo, hi-1); + SwapIfGreater(keys, comparer, lo, hi - 1); SwapIfGreater(keys, comparer, lo, hi); - SwapIfGreater(keys, comparer, hi-1, hi); + SwapIfGreater(keys, comparer, hi - 1, hi); return; } @@ -375,7 +374,7 @@ namespace System.Collections.Generic where T : IComparable<T> { // Do not add a constructor to this class because ArraySortHelper<T>.CreateSortHelper will not execute it - + #region IArraySortHelper<T> Members public void Sort(T[] keys, int index, int length, IComparer<T> comparer) @@ -400,7 +399,7 @@ namespace System.Collections.Generic } catch (Exception e) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), e); + throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); } } @@ -422,7 +421,7 @@ namespace System.Collections.Generic } catch (Exception e) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), e); + throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); } } @@ -485,7 +484,7 @@ namespace System.Collections.Generic private static void Swap(T[] a, int i, int j) { - if(i!=j) + if (i != j) { T t = a[i]; a[i] = a[j]; @@ -529,9 +528,9 @@ namespace System.Collections.Generic } if (partitionSize == 3) { - SwapIfGreaterWithItems(keys, lo, hi-1); + SwapIfGreaterWithItems(keys, lo, hi - 1); SwapIfGreaterWithItems(keys, lo, hi); - SwapIfGreaterWithItems(keys, hi-1, hi); + SwapIfGreaterWithItems(keys, hi - 1, hi); return; } @@ -662,7 +661,7 @@ namespace System.Collections.Generic } } -#endregion + #endregion #region ArraySortHelper for paired key and value arrays @@ -675,7 +674,7 @@ namespace System.Collections.Generic internal class ArraySortHelper<TKey, TValue> : IArraySortHelper<TKey, TValue> { - static volatile IArraySortHelper<TKey, TValue> defaultArraySortHelper; + private static volatile IArraySortHelper<TKey, TValue> defaultArraySortHelper; public static IArraySortHelper<TKey, TValue> Default { @@ -724,7 +723,7 @@ namespace System.Collections.Generic } catch (Exception e) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), e); + throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); } } @@ -755,12 +754,12 @@ namespace System.Collections.Generic private static void Swap(TKey[] keys, TValue[] values, int i, int j) { - if(i!=j) + if (i != j) { TKey k = keys[i]; keys[i] = keys[j]; keys[j] = k; - if(values != null) + if (values != null) { TValue v = values[i]; values[i] = values[j]; @@ -810,9 +809,9 @@ namespace System.Collections.Generic } if (partitionSize == 3) { - SwapIfGreaterWithItems(keys, values, comparer, lo, hi-1); + SwapIfGreaterWithItems(keys, values, comparer, lo, hi - 1); SwapIfGreaterWithItems(keys, values, comparer, lo, hi); - SwapIfGreaterWithItems(keys, values, comparer, hi-1, hi); + SwapIfGreaterWithItems(keys, values, comparer, hi - 1, hi); return; } @@ -913,12 +912,12 @@ namespace System.Collections.Generic if (!(comparer.Compare(d, keys[lo + child - 1]) < 0)) break; keys[lo + i - 1] = keys[lo + child - 1]; - if(values != null) + if (values != null) values[lo + i - 1] = values[lo + child - 1]; i = child; } keys[lo + i - 1] = d; - if(values != null) + if (values != null) values[lo + i - 1] = dValue; } @@ -942,12 +941,12 @@ namespace System.Collections.Generic while (j >= lo && comparer.Compare(t, keys[j]) < 0) { keys[j + 1] = keys[j]; - if(values != null) + if (values != null) values[j + 1] = values[j]; j--; } keys[j + 1] = t; - if(values != null) + if (values != null) values[j + 1] = tValue; } } @@ -960,8 +959,8 @@ namespace System.Collections.Generic public void Sort(TKey[] keys, TValue[] values, int index, int length, IComparer<TKey> comparer) { Debug.Assert(keys != null, "Check the arguments in the caller!"); - Debug.Assert( index >= 0 && length >= 0 && (keys.Length - index >= length), "Check the arguments in the caller!"); - + Debug.Assert(index >= 0 && length >= 0 && (keys.Length - index >= length), "Check the arguments in the caller!"); + // Add a try block here to detect IComparers (or their // underlying IComparables, etc) that are bogus. try @@ -974,14 +973,14 @@ namespace System.Collections.Generic { ArraySortHelper<TKey, TValue>.IntrospectiveSort(keys, values, index, length, comparer); } - } + } catch (IndexOutOfRangeException) { IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); } catch (Exception e) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), e); + throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); } } @@ -1006,12 +1005,12 @@ namespace System.Collections.Generic private static void Swap(TKey[] keys, TValue[] values, int i, int j) { - if(i != j) + if (i != j) { TKey k = keys[i]; keys[i] = keys[j]; keys[j] = k; - if(values != null) + if (values != null) { TValue v = values[i]; values[i] = values[j]; @@ -1059,9 +1058,9 @@ namespace System.Collections.Generic } if (partitionSize == 3) { - SwapIfGreaterWithItems(keys, values, lo, hi-1); + SwapIfGreaterWithItems(keys, values, lo, hi - 1); SwapIfGreaterWithItems(keys, values, lo, hi); - SwapIfGreaterWithItems(keys, values, hi-1, hi); + SwapIfGreaterWithItems(keys, values, hi - 1, hi); return; } @@ -1106,10 +1105,10 @@ namespace System.Collections.Generic while (left < right) { - if(pivot == null) + if (pivot == null) { while (left < (hi - 1) && keys[++left] == null) ; - while (right > lo && keys[--right] != null); + while (right > lo && keys[--right] != null) ; } else { @@ -1167,12 +1166,12 @@ namespace System.Collections.Generic if (keys[lo + child - 1] == null || keys[lo + child - 1].CompareTo(d) < 0) break; keys[lo + i - 1] = keys[lo + child - 1]; - if(values != null) + if (values != null) values[lo + i - 1] = values[lo + child - 1]; i = child; } keys[lo + i - 1] = d; - if(values != null) + if (values != null) values[lo + i - 1] = dValue; } @@ -1191,16 +1190,16 @@ namespace System.Collections.Generic { j = i; t = keys[i + 1]; - tValue = (values != null)? values[i + 1] : default(TValue); + tValue = (values != null) ? values[i + 1] : default(TValue); while (j >= lo && (t == null || t.CompareTo(keys[j]) < 0)) { keys[j + 1] = keys[j]; - if(values != null) + if (values != null) values[j + 1] = values[j]; j--; } keys[j + 1] = t; - if(values != null) + if (values != null) values[j + 1] = tValue; } } diff --git a/src/mscorlib/src/System/Collections/Generic/Comparer.cs b/src/mscorlib/src/System/Collections/Generic/Comparer.cs index 056843a606..a9b4b3f0dd 100644 --- a/src/mscorlib/src/System/Collections/Generic/Comparer.cs +++ b/src/mscorlib/src/System/Collections/Generic/Comparer.cs @@ -15,19 +15,14 @@ using System.Security; using System.Runtime.Serialization; namespace System.Collections.Generic -{ +{ [Serializable] - [TypeDependencyAttribute("System.Collections.Generic.ObjectComparer`1")] + [TypeDependencyAttribute("System.Collections.Generic.ObjectComparer`1")] public abstract class Comparer<T> : IComparer, IComparer<T> { - static readonly Comparer<T> defaultComparer = CreateComparer(); - - public static Comparer<T> Default { - get { - Contract.Ensures(Contract.Result<Comparer<T>>() != null); - return defaultComparer; - } - } + // To minimize generic instantiation overhead of creating the comparer per type, we keep the generic portion of the code as small + // as possible and define most of the creation logic in a non-generic class. + public static Comparer<T> Default { get; } = (Comparer<T>)ComparerHelpers.CreateDefaultComparer(typeof(T)); public static Comparer<T> Create(Comparison<T> comparison) { @@ -39,69 +34,10 @@ namespace System.Collections.Generic return new ComparisonComparer<T>(comparison); } - // - // Note that logic in this method is replicated in vm\compile.cpp to ensure that NGen - // saves the right instantiations - // - private static Comparer<T> CreateComparer() - { - object result = null; - RuntimeType t = (RuntimeType)typeof(T); - - // If T implements IComparable<T> return a GenericComparer<T> - if (typeof(IComparable<T>).IsAssignableFrom(t)) - { - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericComparer<int>), t); - } - else if (default(T) == null) - { - // If T is a Nullable<U> where U implements IComparable<U> return a NullableComparer<U> - if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) { - RuntimeType u = (RuntimeType)t.GetGenericArguments()[0]; - if (typeof(IComparable<>).MakeGenericType(u).IsAssignableFrom(u)) { - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableComparer<int>), u); - } - } - } - else if (t.IsEnum) - { - // Explicitly call Enum.GetUnderlyingType here. Although GetTypeCode - // ends up doing this anyway, we end up avoiding an unnecessary P/Invoke - // and virtual method call. - TypeCode underlyingTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(t)); - - // Depending on the enum type, we need to special case the comparers so that we avoid boxing - // Specialize differently for signed/unsigned types so we avoid problems with large numbers - switch (underlyingTypeCode) - { - case TypeCode.SByte: - case TypeCode.Int16: - case TypeCode.Int32: - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(Int32EnumComparer<int>), t); - break; - case TypeCode.Byte: - case TypeCode.UInt16: - case TypeCode.UInt32: - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(UInt32EnumComparer<uint>), t); - break; - // 64-bit enums: use UnsafeEnumCastLong - case TypeCode.Int64: - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(Int64EnumComparer<long>), t); - break; - case TypeCode.UInt64: - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(UInt64EnumComparer<ulong>), t); - break; - } - } - - return result != null ? - (Comparer<T>)result : - new ObjectComparer<T>(); // Fallback to ObjectComparer, which uses boxing - } - public abstract int Compare(T x, T y); - int IComparer.Compare(object x, object y) { + int IComparer.Compare(object x, object y) + { if (x == null) return y == null ? 0 : -1; if (y == null) return 1; if (x is T && y is T) return Compare((T)x, (T)y); @@ -109,18 +45,20 @@ namespace System.Collections.Generic return 0; } } - + // Note: although there is a lot of shared code in the following // comparers, we do not incorporate it into a base class for perf // reasons. Adding another base class (even one with no fields) // means another generic instantiation, which can be costly esp. // for value types. - + [Serializable] internal sealed class GenericComparer<T> : Comparer<T> where T : IComparable<T> - { - public override int Compare(T x, T y) { - if (x != null) { + { + public override int Compare(T x, T y) + { + if (x != null) + { if (y != null) return x.CompareTo(y); return 1; } @@ -139,8 +77,10 @@ namespace System.Collections.Generic [Serializable] internal sealed class NullableComparer<T> : Comparer<T?> where T : struct, IComparable<T> { - public override int Compare(T? x, T? y) { - if (x.HasValue) { + public override int Compare(T? x, T? y) + { + if (x.HasValue) + { if (y.HasValue) return x.value.CompareTo(y.value); return 1; } @@ -159,7 +99,8 @@ namespace System.Collections.Generic [Serializable] internal sealed class ObjectComparer<T> : Comparer<T> { - public override int Compare(T x, T y) { + public override int Compare(T x, T y) + { return System.Collections.Comparer.Default.Compare(x, y); } @@ -176,11 +117,13 @@ namespace System.Collections.Generic { private readonly Comparison<T> _comparison; - public ComparisonComparer(Comparison<T> comparison) { + public ComparisonComparer(Comparison<T> comparison) + { _comparison = comparison; } - public override int Compare(T x, T y) { + public override int Compare(T x, T y) + { return _comparison(x, y); } } @@ -196,12 +139,12 @@ namespace System.Collections.Generic { public Int32EnumComparer() { - Debug.Assert(typeof(T).IsEnum, "This type is only intended to be used to compare enums!"); + Debug.Assert(typeof(T).IsEnum); } - + // Used by the serialization engine. private Int32EnumComparer(SerializationInfo info, StreamingContext context) { } - + public override int Compare(T x, T y) { int ix = JitHelpers.UnsafeEnumCast(x); @@ -231,12 +174,12 @@ namespace System.Collections.Generic { public UInt32EnumComparer() { - Debug.Assert(typeof(T).IsEnum, "This type is only intended to be used to compare enums!"); + Debug.Assert(typeof(T).IsEnum); } - + // Used by the serialization engine. private UInt32EnumComparer(SerializationInfo info, StreamingContext context) { } - + public override int Compare(T x, T y) { uint ix = (uint)JitHelpers.UnsafeEnumCast(x); @@ -262,9 +205,9 @@ namespace System.Collections.Generic { public Int64EnumComparer() { - Debug.Assert(typeof(T).IsEnum, "This type is only intended to be used to compare enums!"); + Debug.Assert(typeof(T).IsEnum); } - + public override int Compare(T x, T y) { long lx = JitHelpers.UnsafeEnumCastLong(x); @@ -290,12 +233,12 @@ namespace System.Collections.Generic { public UInt64EnumComparer() { - Debug.Assert(typeof(T).IsEnum, "This type is only intended to be used to compare enums!"); + Debug.Assert(typeof(T).IsEnum); } - + // Used by the serialization engine. private UInt64EnumComparer(SerializationInfo info, StreamingContext context) { } - + public override int Compare(T x, T y) { ulong lx = (ulong)JitHelpers.UnsafeEnumCastLong(x); diff --git a/src/mscorlib/src/System/Collections/Generic/ComparerHelpers.cs b/src/mscorlib/src/System/Collections/Generic/ComparerHelpers.cs new file mode 100644 index 0000000000..3e428413d4 --- /dev/null +++ b/src/mscorlib/src/System/Collections/Generic/ComparerHelpers.cs @@ -0,0 +1,210 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using static System.RuntimeTypeHandle; + +namespace System.Collections.Generic +{ + /// <summary> + /// Helper class for creating the default <see cref="Comparer{T}"/> and <see cref="EqualityComparer{T}"/>. + /// </summary> + /// <remarks> + /// This class is intentionally type-unsafe and non-generic to minimize the generic instantiation overhead of creating + /// the default comparer/equality comparer for a new type parameter. Efficiency of the methods in here does not matter too + /// much since they will only be run once per type parameter, but generic code involved in creating the comparers needs to be + /// kept to a minimum. + /// </remarks> + internal static class ComparerHelpers + { + /// <summary> + /// Creates the default <see cref="Comparer{T}"/>. + /// </summary> + /// <param name="type">The type to create the default comparer for.</param> + /// <remarks> + /// The logic in this method is replicated in vm/compile.cpp to ensure that NGen saves the right instantiations. + /// </remarks> + internal static object CreateDefaultComparer(Type type) + { + Debug.Assert(type != null && type is RuntimeType); + + object result = null; + var runtimeType = (RuntimeType)type; + + // If T implements IComparable<T> return a GenericComparer<T> + if (typeof(IComparable<>).MakeGenericType(type).IsAssignableFrom(type)) + { + result = CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericComparer<int>), runtimeType); + } + // Nullable does not implement IComparable<T?> directly because that would add an extra interface call per comparison. + // Instead, it relies on Comparer<T?>.Default to specialize for nullables and do the lifted comparisons if T implements IComparable. + else if (type.IsGenericType) + { + if (type.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + result = TryCreateNullableComparer(runtimeType); + } + } + // The comparer for enums is specialized to avoid boxing. + else if (type.IsEnum) + { + result = TryCreateEnumComparer(runtimeType); + } + + return result ?? CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ObjectComparer<object>), runtimeType); + } + + /// <summary> + /// Creates the default <see cref="Comparer{T}"/> for a nullable type. + /// </summary> + /// <param name="nullableType">The nullable type to create the default comparer for.</param> + private static object TryCreateNullableComparer(RuntimeType nullableType) + { + Debug.Assert(nullableType != null); + Debug.Assert(nullableType.IsGenericType && nullableType.GetGenericTypeDefinition() == typeof(Nullable<>)); + + var embeddedType = (RuntimeType)nullableType.GetGenericArguments()[0]; + + if (typeof(IComparable<>).MakeGenericType(embeddedType).IsAssignableFrom(embeddedType)) + { + return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableComparer<int>), embeddedType); + } + + return null; + } + + /// <summary> + /// Creates the default <see cref="Comparer{T}"/> for an enum type. + /// </summary> + /// <param name="enumType">The enum type to create the default comparer for.</param> + private static object TryCreateEnumComparer(RuntimeType enumType) + { + Debug.Assert(enumType != null); + Debug.Assert(enumType.IsEnum); + + // Explicitly call Enum.GetUnderlyingType here. Although GetTypeCode + // ends up doing this anyway, we end up avoiding an unnecessary P/Invoke + // and virtual method call. + TypeCode underlyingTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(enumType)); + + // Depending on the enum type, we need to special case the comparers so that we avoid boxing. + // Specialize differently for signed/unsigned types so we avoid problems with large numbers. + switch (underlyingTypeCode) + { + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.Int32: + return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(Int32EnumComparer<int>), enumType); + case TypeCode.Byte: + case TypeCode.UInt16: + case TypeCode.UInt32: + return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(UInt32EnumComparer<uint>), enumType); + // 64-bit enums: Use `UnsafeEnumCastLong` + case TypeCode.Int64: + return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(Int64EnumComparer<long>), enumType); + case TypeCode.UInt64: + return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(UInt64EnumComparer<ulong>), enumType); + } + + return null; + } + + /// <summary> + /// Creates the default <see cref="EqualityComparer{T}"/>. + /// </summary> + /// <param name="type">The type to create the default equality comparer for.</param> + /// <remarks> + /// The logic in this method is replicated in vm/compile.cpp to ensure that NGen saves the right instantiations. + /// </remarks> + internal static object CreateDefaultEqualityComparer(Type type) + { + Debug.Assert(type != null && type is RuntimeType); + + object result = null; + var runtimeType = (RuntimeType)type; + + // Specialize for byte so Array.IndexOf is faster. + if (type == typeof(byte)) + { + result = new ByteEqualityComparer(); + } + // If T implements IEquatable<T> return a GenericEqualityComparer<T> + else if (typeof(IEquatable<>).MakeGenericType(type).IsAssignableFrom(type)) + { + result = CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericEqualityComparer<int>), runtimeType); + } + // Nullable does not implement IEquatable<T?> directly because that would add an extra interface call per comparison. + // Instead, it relies on EqualityComparer<T?>.Default to specialize for nullables and do the lifted comparisons if T implements IEquatable. + else if (type.IsGenericType) + { + if (type.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + result = TryCreateNullableEqualityComparer(runtimeType); + } + } + // The equality comparer for enums is specialized to avoid boxing. + else if (type.IsEnum) + { + result = TryCreateEnumEqualityComparer(runtimeType); + } + + return result ?? CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ObjectEqualityComparer<object>), runtimeType); + } + + /// <summary> + /// Creates the default <see cref="EqualityComparer{T}"/> for a nullable type. + /// </summary> + /// <param name="nullableType">The nullable type to create the default equality comparer for.</param> + private static object TryCreateNullableEqualityComparer(RuntimeType nullableType) + { + Debug.Assert(nullableType != null); + Debug.Assert(nullableType.IsGenericType && nullableType.GetGenericTypeDefinition() == typeof(Nullable<>)); + + var embeddedType = (RuntimeType)nullableType.GetGenericArguments()[0]; + + if (typeof(IEquatable<>).MakeGenericType(embeddedType).IsAssignableFrom(embeddedType)) + { + return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableEqualityComparer<int>), embeddedType); + } + + return null; + } + + /// <summary> + /// Creates the default <see cref="EqualityComparer{T}"/> for an enum type. + /// </summary> + /// <param name="enumType">The enum type to create the default equality comparer for.</param> + private static object TryCreateEnumEqualityComparer(RuntimeType enumType) + { + Debug.Assert(enumType != null); + Debug.Assert(enumType.IsEnum); + + // See the METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST and METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG cases in getILIntrinsicImplementation + // for how we cast the enum types to integral values in the comparer without boxing. + + TypeCode underlyingTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(enumType)); + + // Depending on the enum type, we need to special case the comparers so that we avoid boxing. + // Note: We have different comparers for short and sbyte, since for those types GetHashCode does not simply return the value. + // We need to preserve what they would return. + switch (underlyingTypeCode) + { + case TypeCode.Int16: + return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ShortEnumEqualityComparer<short>), enumType); + case TypeCode.SByte: + return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(SByteEnumEqualityComparer<sbyte>), enumType); + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Byte: + case TypeCode.UInt16: + return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer<int>), enumType); + case TypeCode.Int64: + case TypeCode.UInt64: + return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(LongEnumEqualityComparer<long>), enumType); + } + + return null; + } + } +} diff --git a/src/mscorlib/src/System/Collections/Generic/DebugView.cs b/src/mscorlib/src/System/Collections/Generic/DebugView.cs index 27c5011147..dc487c1411 100644 --- a/src/mscorlib/src/System/Collections/Generic/DebugView.cs +++ b/src/mscorlib/src/System/Collections/Generic/DebugView.cs @@ -13,116 +13,112 @@ ** =============================================================================*/ -namespace System.Collections.Generic { - using System; - using System.Collections.ObjectModel; - using System.Diagnostics; - using System.Diagnostics.Contracts; +using System; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Diagnostics.Contracts; +namespace System.Collections.Generic +{ // // VS IDE can't differentiate between types with the same name from different // assembly. So we need to use different names for collection debug view for // collections in mscorlib.dll and system.dll. // - internal sealed class Mscorlib_CollectionDebugView<T> { - private ICollection<T> collection; - - public Mscorlib_CollectionDebugView(ICollection<T> collection) { + internal sealed class Mscorlib_CollectionDebugView<T> + { + private ICollection<T> collection; + + public Mscorlib_CollectionDebugView(ICollection<T> collection) + { if (collection == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); - this.collection = collection; + this.collection = collection; } - + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public T[] Items { - get { + public T[] Items + { + get + { T[] items = new T[collection.Count]; collection.CopyTo(items, 0); return items; } } - } + } - internal sealed class Mscorlib_DictionaryKeyCollectionDebugView<TKey, TValue> { - private ICollection<TKey> collection; - - public Mscorlib_DictionaryKeyCollectionDebugView(ICollection<TKey> collection) { + internal sealed class Mscorlib_DictionaryKeyCollectionDebugView<TKey, TValue> + { + private ICollection<TKey> collection; + + public Mscorlib_DictionaryKeyCollectionDebugView(ICollection<TKey> collection) + { if (collection == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); - this.collection = collection; + this.collection = collection; } - + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public TKey[] Items { - get { + public TKey[] Items + { + get + { TKey[] items = new TKey[collection.Count]; collection.CopyTo(items, 0); return items; } } - } + } - internal sealed class Mscorlib_DictionaryValueCollectionDebugView<TKey, TValue> { - private ICollection<TValue> collection; - - public Mscorlib_DictionaryValueCollectionDebugView(ICollection<TValue> collection) { + internal sealed class Mscorlib_DictionaryValueCollectionDebugView<TKey, TValue> + { + private ICollection<TValue> collection; + + public Mscorlib_DictionaryValueCollectionDebugView(ICollection<TValue> collection) + { if (collection == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); - this.collection = collection; + this.collection = collection; } - + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public TValue[] Items { - get { + public TValue[] Items + { + get + { TValue[] items = new TValue[collection.Count]; collection.CopyTo(items, 0); return items; } } - } + } + + internal sealed class Mscorlib_DictionaryDebugView<K, V> + { + private IDictionary<K, V> dict; - internal sealed class Mscorlib_DictionaryDebugView<K, V> { - private IDictionary<K, V> dict; - - public Mscorlib_DictionaryDebugView(IDictionary<K, V> dictionary) { + public Mscorlib_DictionaryDebugView(IDictionary<K, V> dictionary) + { if (dictionary == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary); - this.dict = dictionary; + dict = dictionary; } - + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public KeyValuePair<K, V>[] Items { - get { + public KeyValuePair<K, V>[] Items + { + get + { KeyValuePair<K, V>[] items = new KeyValuePair<K, V>[dict.Count]; dict.CopyTo(items, 0); return items; } } - } - - internal sealed class Mscorlib_KeyedCollectionDebugView<K, T> { - private KeyedCollection<K, T> kc; - - public Mscorlib_KeyedCollectionDebugView(KeyedCollection<K, T> keyedCollection) { - if (keyedCollection == null) { - throw new ArgumentNullException(nameof(keyedCollection)); - } - Contract.EndContractBlock(); + } - kc = keyedCollection; - } - - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public T[] Items { - get { - T[] items = new T[kc.Count]; - kc.CopyTo(items, 0); - return items; - } - } - } } diff --git a/src/mscorlib/src/System/Collections/Generic/Dictionary.cs b/src/mscorlib/src/System/Collections/Generic/Dictionary.cs index 7b60e31031..409b23b541 100644 --- a/src/mscorlib/src/System/Collections/Generic/Dictionary.cs +++ b/src/mscorlib/src/System/Collections/Generic/Dictionary.cs @@ -41,20 +41,43 @@ ** to serialization such that this code doesn't need to build in ** silverlight. ===========================================================*/ -namespace System.Collections.Generic { +namespace System.Collections.Generic +{ using System; using System.Collections; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Runtime.Serialization; + /// <summary> + /// Used internally to control behavior of insertion into a <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> + internal enum InsertionBehavior : byte + { + /// <summary> + /// The default insertion behavior. + /// </summary> + None = 0, + + /// <summary> + /// Specifies that an existing entry with the same key should be overwritten if encountered. + /// </summary> + OverwriteExisting = 1, + + /// <summary> + /// Specifies that if an existing entry with the same key is encountered, an exception should be thrown. + /// </summary> + ThrowOnExisting = 2 + } + [DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))] [DebuggerDisplay("Count = {Count}")] [Serializable] - public class Dictionary<TKey,TValue>: IDictionary<TKey,TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>, ISerializable, IDeserializationCallback { - - private struct Entry { + public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>, ISerializable, IDeserializationCallback + { + private struct Entry + { public int hashCode; // Lower 31 bits of hash code, -1 if unused public int next; // Index of next entry, -1 if last public TKey key; // Key of entry @@ -71,38 +94,40 @@ namespace System.Collections.Generic { private KeyCollection keys; private ValueCollection values; private Object _syncRoot; - + // constants for serialization private const String VersionName = "Version"; private const String HashSizeName = "HashSize"; // Must save buckets.Length private const String KeyValuePairsName = "KeyValuePairs"; private const String ComparerName = "Comparer"; - public Dictionary(): this(0, null) {} + public Dictionary() : this(0, null) { } - public Dictionary(int capacity): this(capacity, null) {} + public Dictionary(int capacity) : this(capacity, null) { } - public Dictionary(IEqualityComparer<TKey> comparer): this(0, comparer) {} + public Dictionary(IEqualityComparer<TKey> comparer) : this(0, comparer) { } - public Dictionary(int capacity, IEqualityComparer<TKey> comparer) { + public Dictionary(int capacity, IEqualityComparer<TKey> comparer) + { if (capacity < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity); if (capacity > 0) Initialize(capacity); this.comparer = comparer ?? EqualityComparer<TKey>.Default; #if FEATURE_RANDOMIZED_STRING_HASHING - if (HashHelpers.s_UseRandomizedStringHashing && comparer == EqualityComparer<string>.Default) + if (HashHelpers.s_UseRandomizedStringHashing && this.comparer == EqualityComparer<string>.Default) { - this.comparer = (IEqualityComparer<TKey>) NonRandomizedStringEqualityComparer.Default; + this.comparer = (IEqualityComparer<TKey>)NonRandomizedStringEqualityComparer.Default; } #endif // FEATURE_RANDOMIZED_STRING_HASHING } - public Dictionary(IDictionary<TKey,TValue> dictionary): this(dictionary, null) {} - - public Dictionary(IDictionary<TKey,TValue> dictionary, IEqualityComparer<TKey> comparer): - this(dictionary != null? dictionary.Count: 0, comparer) { + public Dictionary(IDictionary<TKey, TValue> dictionary) : this(dictionary, null) { } - if( dictionary == null) { + public Dictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : + this(dictionary != null ? dictionary.Count : 0, comparer) + { + if (dictionary == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary); } @@ -110,138 +135,174 @@ namespace System.Collections.Generic { // avoid the enumerator allocation and overhead by looping through the entries array directly. // We only do this when dictionary is Dictionary<TKey,TValue> and not a subclass, to maintain // back-compat with subclasses that may have overridden the enumerator behavior. - if (dictionary.GetType() == typeof(Dictionary<TKey,TValue>)) { - Dictionary<TKey,TValue> d = (Dictionary<TKey,TValue>)dictionary; + if (dictionary.GetType() == typeof(Dictionary<TKey, TValue>)) + { + Dictionary<TKey, TValue> d = (Dictionary<TKey, TValue>)dictionary; int count = d.count; Entry[] entries = d.entries; - for (int i = 0; i < count; i++) { - if (entries[i].hashCode >= 0) { + for (int i = 0; i < count; i++) + { + if (entries[i].hashCode >= 0) + { Add(entries[i].key, entries[i].value); } } return; } - foreach (KeyValuePair<TKey,TValue> pair in dictionary) { + foreach (KeyValuePair<TKey, TValue> pair in dictionary) + { Add(pair.Key, pair.Value); } } - public Dictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection): - this(collection, null) { } + public Dictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) : + this(collection, null) + { } - public Dictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer): + public Dictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) : this((collection as ICollection<KeyValuePair<TKey, TValue>>)?.Count ?? 0, comparer) { - if (collection == null) { + if (collection == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); } - foreach (KeyValuePair<TKey, TValue> pair in collection) { + foreach (KeyValuePair<TKey, TValue> pair in collection) + { Add(pair.Key, pair.Value); } } - protected Dictionary(SerializationInfo info, StreamingContext context) { + protected Dictionary(SerializationInfo info, StreamingContext context) + { //We can't do anything with the keys and values until the entire graph has been deserialized //and we have a resonable estimate that GetHashCode is not going to fail. For the time being, //we'll just cache this. The graph is not valid until OnDeserialization has been called. HashHelpers.SerializationInfoTable.Add(this, info); } - - public IEqualityComparer<TKey> Comparer { - get { - return comparer; - } + + public IEqualityComparer<TKey> Comparer + { + get + { + return comparer; + } } - - public int Count { + + public int Count + { get { return count - freeCount; } } - public KeyCollection Keys { - get { + public KeyCollection Keys + { + get + { Contract.Ensures(Contract.Result<KeyCollection>() != null); if (keys == null) keys = new KeyCollection(this); return keys; } } - ICollection<TKey> IDictionary<TKey, TValue>.Keys { - get { - if (keys == null) keys = new KeyCollection(this); + ICollection<TKey> IDictionary<TKey, TValue>.Keys + { + get + { + if (keys == null) keys = new KeyCollection(this); return keys; } } - IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys { - get { - if (keys == null) keys = new KeyCollection(this); + IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys + { + get + { + if (keys == null) keys = new KeyCollection(this); return keys; } } - public ValueCollection Values { - get { + public ValueCollection Values + { + get + { Contract.Ensures(Contract.Result<ValueCollection>() != null); if (values == null) values = new ValueCollection(this); return values; } } - ICollection<TValue> IDictionary<TKey, TValue>.Values { - get { + ICollection<TValue> IDictionary<TKey, TValue>.Values + { + get + { if (values == null) values = new ValueCollection(this); return values; } } - IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values { - get { + IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values + { + get + { if (values == null) values = new ValueCollection(this); return values; } } - public TValue this[TKey key] { - get { + public TValue this[TKey key] + { + get + { int i = FindEntry(key); if (i >= 0) return entries[i].value; ThrowHelper.ThrowKeyNotFoundException(); return default(TValue); } - set { - Insert(key, value, false); + set + { + bool modified = TryInsert(key, value, InsertionBehavior.OverwriteExisting); + Debug.Assert(modified); } } - public void Add(TKey key, TValue value) { - Insert(key, value, true); + public void Add(TKey key, TValue value) + { + bool modified = TryInsert(key, value, InsertionBehavior.ThrowOnExisting); + Debug.Assert(modified); // If there was an existing key and the Add failed, an exception will already have been thrown. } - void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> keyValuePair) { + void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> keyValuePair) + { Add(keyValuePair.Key, keyValuePair.Value); } - bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> keyValuePair) { + bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> keyValuePair) + { int i = FindEntry(keyValuePair.Key); - if( i >= 0 && EqualityComparer<TValue>.Default.Equals(entries[i].value, keyValuePair.Value)) { + if (i >= 0 && EqualityComparer<TValue>.Default.Equals(entries[i].value, keyValuePair.Value)) + { return true; } return false; } - bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> keyValuePair) { + bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> keyValuePair) + { int i = FindEntry(keyValuePair.Key); - if( i >= 0 && EqualityComparer<TValue>.Default.Equals(entries[i].value, keyValuePair.Value)) { + if (i >= 0 && EqualityComparer<TValue>.Default.Equals(entries[i].value, keyValuePair.Value)) + { Remove(keyValuePair.Key); return true; } return false; } - public void Clear() { - if (count > 0) { + public void Clear() + { + if (count > 0) + { for (int i = 0; i < buckets.Length; i++) buckets[i] = -1; Array.Clear(entries, 0, count); freeList = -1; @@ -251,90 +312,106 @@ namespace System.Collections.Generic { } } - public bool ContainsKey(TKey key) { + public bool ContainsKey(TKey key) + { return FindEntry(key) >= 0; } - public bool ContainsValue(TValue value) { - if (value == null) { - for (int i = 0; i < count; i++) { + public bool ContainsValue(TValue value) + { + if (value == null) + { + for (int i = 0; i < count; i++) + { if (entries[i].hashCode >= 0 && entries[i].value == null) return true; } } - else { + else + { EqualityComparer<TValue> c = EqualityComparer<TValue>.Default; - for (int i = 0; i < count; i++) { + for (int i = 0; i < count; i++) + { if (entries[i].hashCode >= 0 && c.Equals(entries[i].value, value)) return true; } } return false; } - private void CopyTo(KeyValuePair<TKey,TValue>[] array, int index) { - if (array == null) { + private void CopyTo(KeyValuePair<TKey, TValue>[] array, int index) + { + if (array == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - - if (index < 0 || index > array.Length ) { + + if (index < 0 || index > array.Length) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - if (array.Length - index < Count) { + if (array.Length - index < Count) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); } int count = this.count; Entry[] entries = this.entries; - for (int i = 0; i < count; i++) { - if (entries[i].hashCode >= 0) { - array[index++] = new KeyValuePair<TKey,TValue>(entries[i].key, entries[i].value); + for (int i = 0; i < count; i++) + { + if (entries[i].hashCode >= 0) + { + array[index++] = new KeyValuePair<TKey, TValue>(entries[i].key, entries[i].value); } } } - public Enumerator GetEnumerator() { + public Enumerator GetEnumerator() + { return new Enumerator(this, Enumerator.KeyValuePair); } - IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() { + IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() + { return new Enumerator(this, Enumerator.KeyValuePair); - } + } - public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { - if (info==null) { + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.info); } info.AddValue(VersionName, version); - -#if FEATURE_RANDOMIZED_STRING_HASHING - info.AddValue(ComparerName, HashHelpers.GetEqualityComparerForSerialization(comparer), typeof(IEqualityComparer<TKey>)); -#else info.AddValue(ComparerName, comparer, typeof(IEqualityComparer<TKey>)); -#endif - info.AddValue(HashSizeName, buckets == null ? 0 : buckets.Length); //This is the length of the bucket array. - if( buckets != null) { + if (buckets != null) + { KeyValuePair<TKey, TValue>[] array = new KeyValuePair<TKey, TValue>[Count]; CopyTo(array, 0); info.AddValue(KeyValuePairsName, array, typeof(KeyValuePair<TKey, TValue>[])); } } - private int FindEntry(TKey key) { - if( key == null) { + private int FindEntry(TKey key) + { + if (key == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } - if (buckets != null) { + if (buckets != null) + { int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF; - for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next) { + for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next) + { if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) return i; } } return -1; } - private void Initialize(int capacity) { + 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; @@ -342,9 +419,10 @@ namespace System.Collections.Generic { freeList = -1; } - private void Insert(TKey key, TValue value, bool add) { - - if( key == null ) { + private bool TryInsert(TKey key, TValue value, InsertionBehavior behavior) + { + if (key == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } @@ -356,27 +434,38 @@ namespace System.Collections.Generic { int collisionCount = 0; #endif - for (int i = buckets[targetBucket]; i >= 0; i = entries[i].next) { - if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) { - if (add) { + for (int i = buckets[targetBucket]; i >= 0; i = entries[i].next) + { + if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) + { + if (behavior == InsertionBehavior.OverwriteExisting) + { + entries[i].value = value; + version++; + return true; + } + + if (behavior == InsertionBehavior.ThrowOnExisting) + { ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(key); } - entries[i].value = value; - version++; - return; - } + + return false; + } #if FEATURE_RANDOMIZED_STRING_HASHING collisionCount++; #endif } int index; - if (freeCount > 0) { + if (freeCount > 0) + { index = freeList; freeList = entries[index].next; freeCount--; } - else { + else + { if (count == entries.Length) { Resize(); @@ -399,52 +488,60 @@ namespace System.Collections.Generic { // Note, randomized string hashing is turned on by default on coreclr so EqualityComparer<string>.Default will // be using randomized string hashing - if (collisionCount > HashHelpers.HashCollisionThreshold && comparer == NonRandomizedStringEqualityComparer.Default) + if (collisionCount > HashHelpers.HashCollisionThreshold && comparer == NonRandomizedStringEqualityComparer.Default) { - comparer = (IEqualityComparer<TKey>) EqualityComparer<string>.Default; + comparer = (IEqualityComparer<TKey>)EqualityComparer<string>.Default; Resize(entries.Length, true); } #endif + return true; } - public virtual void OnDeserialization(Object sender) { + public virtual void OnDeserialization(Object sender) + { SerializationInfo siInfo; HashHelpers.SerializationInfoTable.TryGetValue(this, out siInfo); - - if (siInfo==null) { + + if (siInfo == null) + { // It might be necessary to call OnDeserialization from a container if the container object also implements // OnDeserialization. However, remoting will call OnDeserialization again. // We can return immediately if this function is called twice. // Note we set remove the serialization info from the table at the end of this method. return; - } - + } + int realVersion = siInfo.GetInt32(VersionName); int hashsize = siInfo.GetInt32(HashSizeName); - comparer = (IEqualityComparer<TKey>)siInfo.GetValue(ComparerName, typeof(IEqualityComparer<TKey>)); - - if( hashsize != 0) { + comparer = (IEqualityComparer<TKey>)siInfo.GetValue(ComparerName, typeof(IEqualityComparer<TKey>)); + + if (hashsize != 0) + { buckets = new int[hashsize]; for (int i = 0; i < buckets.Length; i++) buckets[i] = -1; entries = new Entry[hashsize]; freeList = -1; - KeyValuePair<TKey, TValue>[] array = (KeyValuePair<TKey, TValue>[]) + KeyValuePair<TKey, TValue>[] array = (KeyValuePair<TKey, TValue>[]) siInfo.GetValue(KeyValuePairsName, typeof(KeyValuePair<TKey, TValue>[])); - if (array==null) { + if (array == null) + { ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_MissingKeys); } - for (int i=0; i<array.Length; i++) { - if ( array[i].Key == null) { + for (int i = 0; i < array.Length; i++) + { + if (array[i].Key == null) + { ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_NullKey); } - Insert(array[i].Key, array[i].Value, true); + Add(array[i].Key, array[i].Value); } } - else { + else + { buckets = null; } @@ -452,25 +549,32 @@ namespace System.Collections.Generic { HashHelpers.SerializationInfoTable.Remove(this); } - private void Resize() { + private void Resize() + { Resize(HashHelpers.ExpandPrime(count), false); } - private void Resize(int newSize, bool forceNewHashCodes) { + private void Resize(int newSize, bool forceNewHashCodes) + { Debug.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].hashCode != -1) { + if (forceNewHashCodes) + { + for (int i = 0; i < count; i++) + { + if (newEntries[i].hashCode != -1) + { newEntries[i].hashCode = (comparer.GetHashCode(newEntries[i].key) & 0x7FFFFFFF); } } } - for (int i = 0; i < count; i++) { - if (newEntries[i].hashCode >= 0) { + for (int i = 0; i < count; i++) + { + if (newEntries[i].hashCode >= 0) + { int bucket = newEntries[i].hashCode % newSize; newEntries[i].next = newBuckets[bucket]; newBuckets[bucket] = i; @@ -480,21 +584,31 @@ namespace System.Collections.Generic { entries = newEntries; } - public bool Remove(TKey key) { - if(key == null) { + // The overload Remove(TKey key, out TValue value) is a copy of this method with one additional + // statement to copy the value for entry being removed into the output parameter. + // Code has been intentionally duplicated for performance reasons. + public bool Remove(TKey key) + { + if (key == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } - if (buckets != null) { + if (buckets != null) + { int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF; int bucket = hashCode % buckets.Length; int last = -1; - for (int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next) { - if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) { - if (last < 0) { + for (int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next) + { + if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) + { + if (last < 0) + { buckets[bucket] = entries[i].next; } - else { + else + { entries[last].next = entries[i].next; } entries[i].hashCode = -1; @@ -511,9 +625,56 @@ namespace System.Collections.Generic { return false; } - public bool TryGetValue(TKey key, out TValue value) { + // This overload is a copy of the overload Remove(TKey key) with one additional + // statement to copy the value for entry being removed into the output parameter. + // Code has been intentionally duplicated for performance reasons. + public bool Remove(TKey key, out TValue value) + { + if (key == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); + } + + if (buckets != null) + { + int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF; + int bucket = hashCode % buckets.Length; + int last = -1; + for (int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next) + { + if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) + { + if (last < 0) + { + buckets[bucket] = entries[i].next; + } + else + { + entries[last].next = entries[i].next; + } + + value = entries[i].value; + + entries[i].hashCode = -1; + entries[i].next = freeList; + entries[i].key = default(TKey); + entries[i].value = default(TValue); + freeList = i; + freeCount++; + version++; + return true; + } + } + } + value = default(TValue); + return false; + } + + public bool TryGetValue(TKey key, out TValue value) + { int i = FindEntry(key); - if (i >= 0) { + if (i >= 0) + { value = entries[i].value; return true; } @@ -536,195 +697,246 @@ namespace System.Collections.Generic { return defaultValue; } - bool ICollection<KeyValuePair<TKey,TValue>>.IsReadOnly { + public bool TryAdd(TKey key, TValue value) => TryInsert(key, value, InsertionBehavior.None); + + bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly + { get { return false; } } - void ICollection<KeyValuePair<TKey,TValue>>.CopyTo(KeyValuePair<TKey,TValue>[] array, int index) { + void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int index) + { CopyTo(array, index); } - void ICollection.CopyTo(Array array, int index) { - if (array == null) { + void ICollection.CopyTo(Array array, int index) + { + if (array == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - - if (array.Rank != 1) { + + if (array.Rank != 1) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); } - if( array.GetLowerBound(0) != 0 ) { + if (array.GetLowerBound(0) != 0) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound); } - - if (index < 0 || index > array.Length) { + + if (index < 0 || index > array.Length) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - if (array.Length - index < Count) { + if (array.Length - index < Count) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); } - - KeyValuePair<TKey,TValue>[] pairs = array as KeyValuePair<TKey,TValue>[]; - if (pairs != null) { + + KeyValuePair<TKey, TValue>[] pairs = array as KeyValuePair<TKey, TValue>[]; + if (pairs != null) + { CopyTo(pairs, index); } - else if( array is DictionaryEntry[]) { + else if (array is DictionaryEntry[]) + { DictionaryEntry[] dictEntryArray = array as DictionaryEntry[]; Entry[] entries = this.entries; - for (int i = 0; i < count; i++) { - if (entries[i].hashCode >= 0) { + for (int i = 0; i < count; i++) + { + if (entries[i].hashCode >= 0) + { dictEntryArray[index++] = new DictionaryEntry(entries[i].key, entries[i].value); } - } + } } - else { + else + { object[] objects = array as object[]; - if (objects == null) { + if (objects == null) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } - try { + try + { int count = this.count; Entry[] entries = this.entries; - for (int i = 0; i < count; i++) { - if (entries[i].hashCode >= 0) { - objects[index++] = new KeyValuePair<TKey,TValue>(entries[i].key, entries[i].value); + for (int i = 0; i < count; i++) + { + if (entries[i].hashCode >= 0) + { + objects[index++] = new KeyValuePair<TKey, TValue>(entries[i].key, entries[i].value); } } } - catch(ArrayTypeMismatchException) { + catch (ArrayTypeMismatchException) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } } } - IEnumerator IEnumerable.GetEnumerator() { + IEnumerator IEnumerable.GetEnumerator() + { return new Enumerator(this, Enumerator.KeyValuePair); } - - bool ICollection.IsSynchronized { + + bool ICollection.IsSynchronized + { get { return false; } } - object ICollection.SyncRoot { - get { - if( _syncRoot == null) { - System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); + object ICollection.SyncRoot + { + get + { + if (_syncRoot == null) + { + System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); } - return _syncRoot; + return _syncRoot; } } - bool IDictionary.IsFixedSize { + bool IDictionary.IsFixedSize + { get { return false; } } - bool IDictionary.IsReadOnly { + bool IDictionary.IsReadOnly + { get { return false; } } - ICollection IDictionary.Keys { + ICollection IDictionary.Keys + { get { return (ICollection)Keys; } } - - ICollection IDictionary.Values { + + ICollection IDictionary.Values + { get { return (ICollection)Values; } } - - object IDictionary.this[object key] { - get { - if( IsCompatibleKey(key)) { + + object IDictionary.this[object key] + { + get + { + if (IsCompatibleKey(key)) + { int i = FindEntry((TKey)key); - if (i >= 0) { - return entries[i].value; + if (i >= 0) + { + return entries[i].value; } } return null; } - set { + set + { if (key == null) { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } ThrowHelper.IfNullAndNullsAreIllegalThenThrow<TValue>(value, ExceptionArgument.value); - try { + try + { TKey tempKey = (TKey)key; - try { - this[tempKey] = (TValue)value; + try + { + this[tempKey] = (TValue)value; } - catch (InvalidCastException) { - ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(TValue)); + catch (InvalidCastException) + { + ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(TValue)); } } - catch (InvalidCastException) { + catch (InvalidCastException) + { ThrowHelper.ThrowWrongKeyTypeArgumentException(key, typeof(TKey)); } } } - private static bool IsCompatibleKey(object key) { - if( key == null) { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); - } - return (key is TKey); + private static bool IsCompatibleKey(object key) + { + if (key == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); + } + return (key is TKey); } - - void IDictionary.Add(object key, object value) { + + void IDictionary.Add(object key, object value) + { if (key == null) { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } ThrowHelper.IfNullAndNullsAreIllegalThenThrow<TValue>(value, ExceptionArgument.value); - try { + try + { TKey tempKey = (TKey)key; - try { + try + { Add(tempKey, (TValue)value); } - catch (InvalidCastException) { - ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(TValue)); + catch (InvalidCastException) + { + ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(TValue)); } } - catch (InvalidCastException) { + catch (InvalidCastException) + { ThrowHelper.ThrowWrongKeyTypeArgumentException(key, typeof(TKey)); } } - - bool IDictionary.Contains(object key) { - if(IsCompatibleKey(key)) { + + bool IDictionary.Contains(object key) + { + if (IsCompatibleKey(key)) + { return ContainsKey((TKey)key); } - + return false; } - - IDictionaryEnumerator IDictionary.GetEnumerator() { + + IDictionaryEnumerator IDictionary.GetEnumerator() + { return new Enumerator(this, Enumerator.DictEntry); } - - void IDictionary.Remove(object key) { - if(IsCompatibleKey(key)) { + + void IDictionary.Remove(object key) + { + if (IsCompatibleKey(key)) + { Remove((TKey)key); } } [Serializable] - public struct Enumerator: IEnumerator<KeyValuePair<TKey,TValue>>, + public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IDictionaryEnumerator { - private Dictionary<TKey,TValue> dictionary; + private Dictionary<TKey, TValue> dictionary; private int version; private int index; - private KeyValuePair<TKey,TValue> current; + private KeyValuePair<TKey, TValue> current; private int getEnumeratorRetType; // What should Enumerator.Current return? - + internal const int DictEntry = 1; internal const int KeyValuePair = 2; - internal Enumerator(Dictionary<TKey,TValue> dictionary, int getEnumeratorRetType) { + internal Enumerator(Dictionary<TKey, TValue> dictionary, int getEnumeratorRetType) + { this.dictionary = dictionary; version = dictionary.version; index = 0; @@ -732,15 +944,19 @@ namespace System.Collections.Generic { current = new KeyValuePair<TKey, TValue>(); } - public bool MoveNext() { - if (version != dictionary.version) { + public bool MoveNext() + { + if (version != dictionary.version) + { ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); } // 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].hashCode >= 0) { + while ((uint)index < (uint)dictionary.count) + { + if (dictionary.entries[index].hashCode >= 0) + { current = new KeyValuePair<TKey, TValue>(dictionary.entries[index].key, dictionary.entries[index].value); index++; return true; @@ -753,187 +969,236 @@ namespace System.Collections.Generic { return false; } - public KeyValuePair<TKey,TValue> Current { + public KeyValuePair<TKey, TValue> Current + { get { return current; } } - public void Dispose() { + public void Dispose() + { } - object IEnumerator.Current { - get { - if( index == 0 || (index == dictionary.count + 1)) { - ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); - } + object IEnumerator.Current + { + get + { + if (index == 0 || (index == dictionary.count + 1)) + { + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + } - if (getEnumeratorRetType == DictEntry) { + if (getEnumeratorRetType == DictEntry) + { return new System.Collections.DictionaryEntry(current.Key, current.Value); - } else { + } + else + { return new KeyValuePair<TKey, TValue>(current.Key, current.Value); } } } - void IEnumerator.Reset() { - if (version != dictionary.version) { + void IEnumerator.Reset() + { + if (version != dictionary.version) + { ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); } index = 0; - current = new KeyValuePair<TKey, TValue>(); + current = new KeyValuePair<TKey, TValue>(); } - DictionaryEntry IDictionaryEnumerator.Entry { - get { - if( index == 0 || (index == dictionary.count + 1)) { - ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); - } - - return new DictionaryEntry(current.Key, current.Value); + DictionaryEntry IDictionaryEnumerator.Entry + { + get + { + if (index == 0 || (index == dictionary.count + 1)) + { + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + } + + return new DictionaryEntry(current.Key, current.Value); } } - object IDictionaryEnumerator.Key { - get { - if( index == 0 || (index == dictionary.count + 1)) { - ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); - } - - return current.Key; + object IDictionaryEnumerator.Key + { + get + { + if (index == 0 || (index == dictionary.count + 1)) + { + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + } + + return current.Key; } } - object IDictionaryEnumerator.Value { - get { - if( index == 0 || (index == dictionary.count + 1)) { - ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); - } - - return current.Value; + object IDictionaryEnumerator.Value + { + get + { + if (index == 0 || (index == dictionary.count + 1)) + { + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + } + + return current.Value; } } } [DebuggerTypeProxy(typeof(Mscorlib_DictionaryKeyCollectionDebugView<,>))] - [DebuggerDisplay("Count = {Count}")] + [DebuggerDisplay("Count = {Count}")] [Serializable] - public sealed class KeyCollection: ICollection<TKey>, ICollection, IReadOnlyCollection<TKey> + public sealed class KeyCollection : ICollection<TKey>, ICollection, IReadOnlyCollection<TKey> { - private Dictionary<TKey,TValue> dictionary; + private Dictionary<TKey, TValue> dictionary; - public KeyCollection(Dictionary<TKey,TValue> dictionary) { - if (dictionary == null) { + public KeyCollection(Dictionary<TKey, TValue> dictionary) + { + if (dictionary == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary); } this.dictionary = dictionary; } - public Enumerator GetEnumerator() { + public Enumerator GetEnumerator() + { return new Enumerator(dictionary); } - public void CopyTo(TKey[] array, int index) { - if (array == null) { + public void CopyTo(TKey[] array, int index) + { + if (array == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (index < 0 || index > array.Length) { + if (index < 0 || index > array.Length) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - if (array.Length - index < dictionary.Count) { + if (array.Length - index < dictionary.Count) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); } - + int count = dictionary.count; Entry[] entries = dictionary.entries; - for (int i = 0; i < count; i++) { + for (int i = 0; i < count; i++) + { if (entries[i].hashCode >= 0) array[index++] = entries[i].key; } } - public int Count { + public int Count + { get { return dictionary.Count; } } - bool ICollection<TKey>.IsReadOnly { + bool ICollection<TKey>.IsReadOnly + { get { return true; } } - void ICollection<TKey>.Add(TKey item){ + void ICollection<TKey>.Add(TKey item) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet); } - - void ICollection<TKey>.Clear(){ + + void ICollection<TKey>.Clear() + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet); } - bool ICollection<TKey>.Contains(TKey item){ + bool ICollection<TKey>.Contains(TKey item) + { return dictionary.ContainsKey(item); } - bool ICollection<TKey>.Remove(TKey item){ + bool ICollection<TKey>.Remove(TKey item) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet); return false; } - - IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator() { + + IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator() + { return new Enumerator(dictionary); } - IEnumerator IEnumerable.GetEnumerator() { - return new Enumerator(dictionary); + IEnumerator IEnumerable.GetEnumerator() + { + return new Enumerator(dictionary); } - void ICollection.CopyTo(Array array, int index) { - if (array==null) { + void ICollection.CopyTo(Array array, int index) + { + if (array == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (array.Rank != 1) { + if (array.Rank != 1) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); } - if( array.GetLowerBound(0) != 0 ) { + if (array.GetLowerBound(0) != 0) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound); } - if (index < 0 || index > array.Length) { + if (index < 0 || index > array.Length) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - if (array.Length - index < dictionary.Count) { + if (array.Length - index < dictionary.Count) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); } - + TKey[] keys = array as TKey[]; - if (keys != null) { + if (keys != null) + { CopyTo(keys, index); } - else { + else + { object[] objects = array as object[]; - if (objects == null) { + if (objects == null) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } - + int count = dictionary.count; Entry[] entries = dictionary.entries; - try { - for (int i = 0; i < count; i++) { + try + { + for (int i = 0; i < count; i++) + { if (entries[i].hashCode >= 0) objects[index++] = entries[i].key; } - } - catch(ArrayTypeMismatchException) { + } + catch (ArrayTypeMismatchException) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } } } - bool ICollection.IsSynchronized { + bool ICollection.IsSynchronized + { get { return false; } } - Object ICollection.SyncRoot { + Object ICollection.SyncRoot + { get { return ((ICollection)dictionary).SyncRoot; } } @@ -944,24 +1209,30 @@ namespace System.Collections.Generic { private int index; private int version; private TKey currentKey; - - internal Enumerator(Dictionary<TKey, TValue> dictionary) { + + internal Enumerator(Dictionary<TKey, TValue> dictionary) + { this.dictionary = dictionary; version = dictionary.version; index = 0; - currentKey = default(TKey); + currentKey = default(TKey); } - public void Dispose() { + public void Dispose() + { } - public bool MoveNext() { - if (version != dictionary.version) { + public bool MoveNext() + { + if (version != dictionary.version) + { ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); } - while ((uint)index < (uint)dictionary.count) { - if (dictionary.entries[index].hashCode >= 0) { + while ((uint)index < (uint)dictionary.count) + { + if (dictionary.entries[index].hashCode >= 0) + { currentKey = dictionary.entries[index].key; index++; return true; @@ -973,153 +1244,189 @@ namespace System.Collections.Generic { currentKey = default(TKey); return false; } - - public TKey Current { - get { + + public TKey Current + { + get + { return currentKey; } } - Object System.Collections.IEnumerator.Current { - get { - if( index == 0 || (index == dictionary.count + 1)) { - ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); - } - + Object System.Collections.IEnumerator.Current + { + get + { + if (index == 0 || (index == dictionary.count + 1)) + { + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + } + return currentKey; } } - - void System.Collections.IEnumerator.Reset() { - if (version != dictionary.version) { - ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); + + void System.Collections.IEnumerator.Reset() + { + if (version != dictionary.version) + { + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); } - index = 0; + index = 0; currentKey = default(TKey); } - } + } } [DebuggerTypeProxy(typeof(Mscorlib_DictionaryValueCollectionDebugView<,>))] [DebuggerDisplay("Count = {Count}")] [Serializable] - public sealed class ValueCollection: ICollection<TValue>, ICollection, IReadOnlyCollection<TValue> + public sealed class ValueCollection : ICollection<TValue>, ICollection, IReadOnlyCollection<TValue> { - private Dictionary<TKey,TValue> dictionary; + private Dictionary<TKey, TValue> dictionary; - public ValueCollection(Dictionary<TKey,TValue> dictionary) { - if (dictionary == null) { + public ValueCollection(Dictionary<TKey, TValue> dictionary) + { + if (dictionary == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary); } this.dictionary = dictionary; } - public Enumerator GetEnumerator() { - return new Enumerator(dictionary); + public Enumerator GetEnumerator() + { + return new Enumerator(dictionary); } - public void CopyTo(TValue[] array, int index) { - if (array == null) { + public void CopyTo(TValue[] array, int index) + { + if (array == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (index < 0 || index > array.Length) { + if (index < 0 || index > array.Length) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - if (array.Length - index < dictionary.Count) { + if (array.Length - index < dictionary.Count) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); } - + int count = dictionary.count; Entry[] entries = dictionary.entries; - for (int i = 0; i < count; i++) { + for (int i = 0; i < count; i++) + { if (entries[i].hashCode >= 0) array[index++] = entries[i].value; } } - public int Count { + public int Count + { get { return dictionary.Count; } } - bool ICollection<TValue>.IsReadOnly { + bool ICollection<TValue>.IsReadOnly + { get { return true; } } - void ICollection<TValue>.Add(TValue item){ + void ICollection<TValue>.Add(TValue item) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet); } - bool ICollection<TValue>.Remove(TValue item){ + bool ICollection<TValue>.Remove(TValue item) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet); return false; } - void ICollection<TValue>.Clear(){ + void ICollection<TValue>.Clear() + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet); } - bool ICollection<TValue>.Contains(TValue item){ + bool ICollection<TValue>.Contains(TValue item) + { return dictionary.ContainsValue(item); } - IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator() { + IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator() + { return new Enumerator(dictionary); } - IEnumerator IEnumerable.GetEnumerator() { - return new Enumerator(dictionary); + IEnumerator IEnumerable.GetEnumerator() + { + return new Enumerator(dictionary); } - void ICollection.CopyTo(Array array, int index) { - if (array == null) { + void ICollection.CopyTo(Array array, int index) + { + if (array == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (array.Rank != 1) { + if (array.Rank != 1) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); } - if( array.GetLowerBound(0) != 0 ) { + if (array.GetLowerBound(0) != 0) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound); } - if (index < 0 || index > array.Length) { + if (index < 0 || index > array.Length) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } if (array.Length - index < dictionary.Count) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); - + TValue[] values = array as TValue[]; - if (values != null) { + if (values != null) + { CopyTo(values, index); } - else { + else + { object[] objects = array as object[]; - if (objects == null) { + if (objects == null) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } int count = dictionary.count; Entry[] entries = dictionary.entries; - try { - for (int i = 0; i < count; i++) { + try + { + for (int i = 0; i < count; i++) + { if (entries[i].hashCode >= 0) objects[index++] = entries[i].value; } } - catch(ArrayTypeMismatchException) { + catch (ArrayTypeMismatchException) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } } } - bool ICollection.IsSynchronized { + bool ICollection.IsSynchronized + { get { return false; } } - Object ICollection.SyncRoot { + Object ICollection.SyncRoot + { get { return ((ICollection)dictionary).SyncRoot; } } @@ -1130,24 +1437,30 @@ namespace System.Collections.Generic { private int index; private int version; private TValue currentValue; - - internal Enumerator(Dictionary<TKey, TValue> dictionary) { + + internal Enumerator(Dictionary<TKey, TValue> dictionary) + { this.dictionary = dictionary; version = dictionary.version; index = 0; currentValue = default(TValue); } - public void Dispose() { + public void Dispose() + { } - public bool MoveNext() { - if (version != dictionary.version) { + public bool MoveNext() + { + if (version != dictionary.version) + { ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); } - - while ((uint)index < (uint)dictionary.count) { - if (dictionary.entries[index].hashCode >= 0) { + + while ((uint)index < (uint)dictionary.count) + { + if (dictionary.entries[index].hashCode >= 0) + { currentValue = dictionary.entries[index].value; index++; return true; @@ -1158,28 +1471,35 @@ namespace System.Collections.Generic { currentValue = default(TValue); return false; } - - public TValue Current { - get { + + public TValue Current + { + get + { return currentValue; } } - Object System.Collections.IEnumerator.Current { - get { - if( index == 0 || (index == dictionary.count + 1)) { - ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); - } - + Object System.Collections.IEnumerator.Current + { + get + { + if (index == 0 || (index == dictionary.count + 1)) + { + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + } + return currentValue; } } - - void System.Collections.IEnumerator.Reset() { - if (version != dictionary.version) { + + void System.Collections.IEnumerator.Reset() + { + if (version != dictionary.version) + { ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); } - index = 0; + index = 0; currentValue = default(TValue); } } diff --git a/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs b/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs index 0f9259d2f3..0cd1bc1c12 100644 --- a/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs +++ b/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs @@ -7,117 +7,56 @@ using System.Collections; using System.Collections.Generic; using System.Security; +using System.Globalization; +using System.Runtime; +using System.Runtime.CompilerServices; +using System.Diagnostics.Contracts; + namespace System.Collections.Generic { - using System.Globalization; - using System.Runtime; - using System.Runtime.CompilerServices; - using System.Diagnostics.Contracts; - [Serializable] [TypeDependencyAttribute("System.Collections.Generic.ObjectEqualityComparer`1")] public abstract class EqualityComparer<T> : IEqualityComparer, IEqualityComparer<T> { - static readonly EqualityComparer<T> defaultComparer = CreateComparer(); - - public static EqualityComparer<T> Default { - get { - Contract.Ensures(Contract.Result<EqualityComparer<T>>() != null); - return defaultComparer; - } - } - - // - // Note that logic in this method is replicated in vm\compile.cpp to ensure that NGen - // saves the right instantiations - // - private static EqualityComparer<T> CreateComparer() - { - Contract.Ensures(Contract.Result<EqualityComparer<T>>() != null); - - object result = null; - RuntimeType t = (RuntimeType)typeof(T); - - // Specialize type byte for performance reasons - if (t == typeof(byte)) { - result = new ByteEqualityComparer(); - } - // If T implements IEquatable<T> return a GenericEqualityComparer<T> - else if (typeof(IEquatable<T>).IsAssignableFrom(t)) - { - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericEqualityComparer<int>), t); - } - else if (default(T) == null) // Reference type/Nullable - { - // If T is a Nullable<U> where U implements IEquatable<U> return a NullableEqualityComparer<U> - if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) { - RuntimeType u = (RuntimeType)t.GetGenericArguments()[0]; - if (typeof(IEquatable<>).MakeGenericType(u).IsAssignableFrom(u)) { - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableEqualityComparer<int>), u); - } - } - } - // See the METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST and METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG cases in getILIntrinsicImplementation - else if (t.IsEnum) { - TypeCode underlyingTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(t)); - - // Depending on the enum type, we need to special case the comparers so that we avoid boxing - // Note: We have different comparers for Short and SByte because for those types we need to make sure we call GetHashCode on the actual underlying type as the - // implementation of GetHashCode is more complex than for the other types. - switch (underlyingTypeCode) { - case TypeCode.Int16: // short - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ShortEnumEqualityComparer<short>), t); - break; - case TypeCode.SByte: - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(SByteEnumEqualityComparer<sbyte>), t); - break; - case TypeCode.Int32: - case TypeCode.UInt32: - case TypeCode.Byte: - case TypeCode.UInt16: //ushort - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer<int>), t); - break; - case TypeCode.Int64: - case TypeCode.UInt64: - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(LongEnumEqualityComparer<long>), t); - break; - } - } - - return result != null ? - (EqualityComparer<T>)result : - new ObjectEqualityComparer<T>(); // Fallback to ObjectEqualityComparer, which uses boxing - } + // To minimize generic instantiation overhead of creating the comparer per type, we keep the generic portion of the code as small + // as possible and define most of the creation logic in a non-generic class. + public static EqualityComparer<T> Default { get; } = (EqualityComparer<T>)ComparerHelpers.CreateDefaultEqualityComparer(typeof(T)); [Pure] public abstract bool Equals(T x, T y); [Pure] public abstract int GetHashCode(T obj); - internal virtual int IndexOf(T[] array, T value, int startIndex, int count) { + internal virtual int IndexOf(T[] array, T value, int startIndex, int count) + { int endIndex = startIndex + count; - for (int i = startIndex; i < endIndex; i++) { + for (int i = startIndex; i < endIndex; i++) + { if (Equals(array[i], value)) return i; } return -1; } - internal virtual int LastIndexOf(T[] array, T value, int startIndex, int count) { + internal virtual int LastIndexOf(T[] array, T value, int startIndex, int count) + { int endIndex = startIndex - count + 1; - for (int i = startIndex; i >= endIndex; i--) { + for (int i = startIndex; i >= endIndex; i--) + { if (Equals(array[i], value)) return i; } return -1; } - int IEqualityComparer.GetHashCode(object obj) { + int IEqualityComparer.GetHashCode(object obj) + { if (obj == null) return 0; if (obj is T) return GetHashCode((T)obj); ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArgumentForComparison); - return 0; - } + return 0; + } - bool IEqualityComparer.Equals(object x, object y) { + bool IEqualityComparer.Equals(object x, object y) + { if (x == y) return true; if (x == null || y == null) return false; if ((x is T) && (y is T)) return Equals((T)x, (T)y); @@ -129,11 +68,13 @@ namespace System.Collections.Generic // The methods in this class look identical to the inherited methods, but the calls // to Equal bind to IEquatable<T>.Equals(T) instead of Object.Equals(Object) [Serializable] - internal class GenericEqualityComparer<T>: EqualityComparer<T> where T: IEquatable<T> + internal class GenericEqualityComparer<T> : EqualityComparer<T> where T : IEquatable<T> { [Pure] - public override bool Equals(T x, T y) { - if (x != null) { + public override bool Equals(T x, T y) + { + if (x != null) + { if (y != null) return x.Equals(y); return false; } @@ -144,30 +85,40 @@ namespace System.Collections.Generic [Pure] public override int GetHashCode(T obj) => obj?.GetHashCode() ?? 0; - internal override int IndexOf(T[] array, T value, int startIndex, int count) { + internal override int IndexOf(T[] array, T value, int startIndex, int count) + { int endIndex = startIndex + count; - if (value == null) { - for (int i = startIndex; i < endIndex; i++) { + if (value == null) + { + for (int i = startIndex; i < endIndex; i++) + { if (array[i] == null) return i; } } - else { - for (int i = startIndex; i < endIndex; i++) { + else + { + for (int i = startIndex; i < endIndex; i++) + { if (array[i] != null && array[i].Equals(value)) return i; } } return -1; } - internal override int LastIndexOf(T[] array, T value, int startIndex, int count) { + internal override int LastIndexOf(T[] array, T value, int startIndex, int count) + { int endIndex = startIndex - count + 1; - if (value == null) { - for (int i = startIndex; i >= endIndex; i--) { + if (value == null) + { + for (int i = startIndex; i >= endIndex; i--) + { if (array[i] == null) return i; } } - else { - for (int i = startIndex; i >= endIndex; i--) { + else + { + for (int i = startIndex; i >= endIndex; i--) + { if (array[i] != null && array[i].Equals(value)) return i; } } @@ -188,8 +139,10 @@ namespace System.Collections.Generic internal sealed class NullableEqualityComparer<T> : EqualityComparer<T?> where T : struct, IEquatable<T> { [Pure] - public override bool Equals(T? x, T? y) { - if (x.HasValue) { + public override bool Equals(T? x, T? y) + { + if (x.HasValue) + { if (y.HasValue) return x.value.Equals(y.value); return false; } @@ -200,30 +153,40 @@ namespace System.Collections.Generic [Pure] public override int GetHashCode(T? obj) => obj.GetHashCode(); - internal override int IndexOf(T?[] array, T? value, int startIndex, int count) { + internal override int IndexOf(T?[] array, T? value, int startIndex, int count) + { int endIndex = startIndex + count; - if (!value.HasValue) { - for (int i = startIndex; i < endIndex; i++) { + if (!value.HasValue) + { + for (int i = startIndex; i < endIndex; i++) + { if (!array[i].HasValue) return i; } } - else { - for (int i = startIndex; i < endIndex; i++) { + else + { + for (int i = startIndex; i < endIndex; i++) + { if (array[i].HasValue && array[i].value.Equals(value.value)) return i; } } return -1; } - internal override int LastIndexOf(T?[] array, T? value, int startIndex, int count) { + internal override int LastIndexOf(T?[] array, T? value, int startIndex, int count) + { int endIndex = startIndex - count + 1; - if (!value.HasValue) { - for (int i = startIndex; i >= endIndex; i--) { + if (!value.HasValue) + { + for (int i = startIndex; i >= endIndex; i--) + { if (!array[i].HasValue) return i; } } - else { - for (int i = startIndex; i >= endIndex; i--) { + else + { + for (int i = startIndex; i >= endIndex; i--) + { if (array[i].HasValue && array[i].value.Equals(value.value)) return i; } } @@ -239,11 +202,13 @@ namespace System.Collections.Generic } [Serializable] - internal sealed class ObjectEqualityComparer<T>: EqualityComparer<T> + internal sealed class ObjectEqualityComparer<T> : EqualityComparer<T> { [Pure] - public override bool Equals(T x, T y) { - if (x != null) { + public override bool Equals(T x, T y) + { + if (x != null) + { if (y != null) return x.Equals(y); return false; } @@ -254,30 +219,40 @@ namespace System.Collections.Generic [Pure] public override int GetHashCode(T obj) => obj?.GetHashCode() ?? 0; - internal override int IndexOf(T[] array, T value, int startIndex, int count) { + internal override int IndexOf(T[] array, T value, int startIndex, int count) + { int endIndex = startIndex + count; - if (value == null) { - for (int i = startIndex; i < endIndex; i++) { + if (value == null) + { + for (int i = startIndex; i < endIndex; i++) + { if (array[i] == null) return i; } } - else { - for (int i = startIndex; i < endIndex; i++) { + else + { + for (int i = startIndex; i < endIndex; i++) + { if (array[i] != null && array[i].Equals(value)) return i; } } return -1; } - internal override int LastIndexOf(T[] array, T value, int startIndex, int count) { + internal override int LastIndexOf(T[] array, T value, int startIndex, int count) + { int endIndex = startIndex - count + 1; - if (value == null) { - for (int i = startIndex; i >= endIndex; i--) { + if (value == null) + { + for (int i = startIndex; i >= endIndex; i--) + { if (array[i] == null) return i; } } - else { - for (int i = startIndex; i >= endIndex; i--) { + else + { + for (int i = startIndex; i >= endIndex; i--) + { if (array[i] != null && array[i].Equals(value)) return i; } } @@ -299,20 +274,25 @@ namespace System.Collections.Generic // keep the perofrmance not affected till we hit collision threshold and then we switch to the comparer which is using // randomized string hashing GenericEqualityComparer<string> [Serializable] - internal class NonRandomizedStringEqualityComparer : GenericEqualityComparer<string> { - static IEqualityComparer<string> s_nonRandomizedComparer; - - internal static new IEqualityComparer<string> Default { - get { - if (s_nonRandomizedComparer == null) { - s_nonRandomizedComparer = new NonRandomizedStringEqualityComparer(); - } - return s_nonRandomizedComparer; + internal class NonRandomizedStringEqualityComparer : GenericEqualityComparer<string> + { + private static IEqualityComparer<string> s_nonRandomizedComparer; + + internal static new IEqualityComparer<string> Default + { + get + { + if (s_nonRandomizedComparer == null) + { + s_nonRandomizedComparer = new NonRandomizedStringEqualityComparer(); + } + return s_nonRandomizedComparer; } } [Pure] - public override int GetHashCode(string obj) { + public override int GetHashCode(string obj) + { if (obj == null) return 0; return obj.GetLegacyNonRandomizedHashCode(); } @@ -321,37 +301,43 @@ namespace System.Collections.Generic // Performance of IndexOf on byte array is very important for some scenarios. // We will call the C runtime function memchr, which is optimized. [Serializable] - internal sealed class ByteEqualityComparer: EqualityComparer<byte> + internal sealed class ByteEqualityComparer : EqualityComparer<byte> { [Pure] - public override bool Equals(byte x, byte y) { + public override bool Equals(byte x, byte y) + { return x == y; } [Pure] - public override int GetHashCode(byte b) { + public override int GetHashCode(byte b) + { return b.GetHashCode(); } - internal unsafe override int IndexOf(byte[] array, byte value, int startIndex, int count) { - if (array==null) + internal unsafe override int IndexOf(byte[] array, byte value, int startIndex, int count) + { + if (array == null) throw new ArgumentNullException(nameof(array)); if (startIndex < 0) - throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_Index")); + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); if (count < 0) - throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_Count")); + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); if (count > array.Length - startIndex) - throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); + throw new ArgumentException(SR.Argument_InvalidOffLen); Contract.EndContractBlock(); if (count == 0) return -1; - fixed (byte* pbytes = array) { + fixed (byte* pbytes = array) + { return Buffer.IndexOfByte(pbytes, value, startIndex, count); } } - internal override int LastIndexOf(byte[] array, byte value, int startIndex, int count) { + internal override int LastIndexOf(byte[] array, byte value, int startIndex, int count) + { int endIndex = startIndex - count + 1; - for (int i = startIndex; i >= endIndex; i--) { + for (int i = startIndex; i >= endIndex; i--) + { if (array[i] == value) return i; } return -1; @@ -362,21 +348,23 @@ namespace System.Collections.Generic obj != null && GetType() == obj.GetType(); public override int GetHashCode() => - GetType().GetHashCode(); + GetType().GetHashCode(); } [Serializable] internal class EnumEqualityComparer<T> : EqualityComparer<T> where T : struct { [Pure] - public override bool Equals(T x, T y) { + public override bool Equals(T x, T y) + { int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(x); int y_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(y); return x_final == y_final; } [Pure] - public override int GetHashCode(T obj) { + public override int GetHashCode(T obj) + { int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(obj); return x_final.GetHashCode(); } @@ -421,7 +409,8 @@ namespace System.Collections.Generic public SByteEnumEqualityComparer() { } [Pure] - public override int GetHashCode(T obj) { + public override int GetHashCode(T obj) + { int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(obj); return ((sbyte)x_final).GetHashCode(); } @@ -433,7 +422,8 @@ namespace System.Collections.Generic public ShortEnumEqualityComparer() { } [Pure] - public override int GetHashCode(T obj) { + public override int GetHashCode(T obj) + { int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(obj); return ((short)x_final).GetHashCode(); } @@ -443,14 +433,16 @@ namespace System.Collections.Generic internal sealed class LongEnumEqualityComparer<T> : EqualityComparer<T> where T : struct { [Pure] - public override bool Equals(T x, T y) { + public override bool Equals(T x, T y) + { long x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCastLong(x); long y_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCastLong(y); return x_final == y_final; } [Pure] - public override int GetHashCode(T obj) { + public override int GetHashCode(T obj) + { long x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCastLong(obj); return x_final.GetHashCode(); } diff --git a/src/mscorlib/src/System/Collections/Generic/ICollection.cs b/src/mscorlib/src/System/Collections/Generic/ICollection.cs deleted file mode 100644 index 741e8cc79b..0000000000 --- a/src/mscorlib/src/System/Collections/Generic/ICollection.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: ICollection -** -** -** -** -** Purpose: Base interface for all generic collections. -** -** -===========================================================*/ -namespace System.Collections.Generic { - using System; - using System.Runtime.CompilerServices; - using System.Diagnostics.Contracts; - - // Base interface for all collections, defining enumerators, size, and - // synchronization methods. - - // Note that T[] : IList<T>, and we want to ensure that if you use - // IList<YourValueType>, we ensure a YourValueType[] can be used - // without jitting. Hence the TypeDependencyAttribute on SZArrayHelper. - // This is a special workaround internally though - see VM\compile.cpp. - // The same attribute is on IEnumerable<T> and ICollection<T>. - [TypeDependencyAttribute("System.SZArrayHelper")] - public interface ICollection<T> : IEnumerable<T> - { - // Number of items in the collections. - int Count { get; } - - bool IsReadOnly { get; } - - void Add(T item); - - void Clear(); - - bool Contains(T item); - - // CopyTo copies a collection into an Array, starting at a particular - // index into the array. - // - void CopyTo(T[] array, int arrayIndex); - - //void CopyTo(int sourceIndex, T[] destinationArray, int destinationIndex, int count); - - bool Remove(T item); - } -} diff --git a/src/mscorlib/src/System/Collections/Generic/IComparer.cs b/src/mscorlib/src/System/Collections/Generic/IComparer.cs deleted file mode 100644 index 7b9e97ff0e..0000000000 --- a/src/mscorlib/src/System/Collections/Generic/IComparer.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IComparer -** -** -** -** -** Purpose: Interface for comparing two generic Objects. -** -** -===========================================================*/ -namespace System.Collections.Generic { - - using System; - // The generic IComparer interface implements a method that compares - // two objects. It is used in conjunction with the Sort and - // BinarySearch methods on the Array, List, and SortedList classes. - public interface IComparer<in T> - { - // Compares two objects. An implementation of this method must return a - // value less than zero if x is less than y, zero if x is equal to y, or a - // value greater than zero if x is greater than y. - // - int Compare(T x, T y); - } -} diff --git a/src/mscorlib/src/System/Collections/Generic/IDictionary.cs b/src/mscorlib/src/System/Collections/Generic/IDictionary.cs deleted file mode 100644 index 2a2da944d3..0000000000 --- a/src/mscorlib/src/System/Collections/Generic/IDictionary.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IDictionary -** -** -** -** -** Purpose: Base interface for all generic dictionaries. -** -** -===========================================================*/ -namespace System.Collections.Generic { - using System; - using System.Diagnostics.Contracts; - - // An IDictionary is a possibly unordered set of key-value pairs. - // Keys can be any non-null object. Values can be any object. - // You can look up a value in an IDictionary via the default indexed - // property, Items. - public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>> - { - // Interfaces are not serializable - // The Item property provides methods to read and edit entries - // in the Dictionary. - TValue this[TKey key] { - get; - set; - } - - // Returns a collections of the keys in this dictionary. - ICollection<TKey> Keys { - get; - } - - // Returns a collections of the values in this dictionary. - ICollection<TValue> Values { - get; - } - - // Returns whether this dictionary contains a particular key. - // - bool ContainsKey(TKey key); - - // Adds a key-value pair to the dictionary. - // - void Add(TKey key, TValue value); - - // Removes a particular key from the dictionary. - // - bool Remove(TKey key); - - bool TryGetValue(TKey key, out TValue value); - } -} diff --git a/src/mscorlib/src/System/Collections/Generic/IEnumerable.cs b/src/mscorlib/src/System/Collections/Generic/IEnumerable.cs deleted file mode 100644 index 67f35ce675..0000000000 --- a/src/mscorlib/src/System/Collections/Generic/IEnumerable.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IEnumerable -** -** -** -** -** Purpose: Interface for providing generic IEnumerators -** -** -===========================================================*/ -namespace System.Collections.Generic { - using System; - using System.Collections; - using System.Runtime.InteropServices; - using System.Runtime.CompilerServices; - using System.Diagnostics.Contracts; - - // Implement this interface if you need to support foreach semantics. - - // Note that T[] : IList<T>, and we want to ensure that if you use - // IList<YourValueType>, we ensure a YourValueType[] can be used - // without jitting. Hence the TypeDependencyAttribute on SZArrayHelper. - // This is a special workaround internally though - see VM\compile.cpp. - // The same attribute is on IList<T> and ICollection<T>. - [TypeDependencyAttribute("System.SZArrayHelper")] - public interface IEnumerable<out T> : IEnumerable - { - // Returns an IEnumerator for this enumerable Object. The enumerator provides - // a simple way to access all the contents of a collection. - /// <include file='doc\IEnumerable.uex' path='docs/doc[@for="IEnumerable.GetEnumerator"]/*' /> - new IEnumerator<T> GetEnumerator(); - } -} diff --git a/src/mscorlib/src/System/Collections/Generic/IEnumerator.cs b/src/mscorlib/src/System/Collections/Generic/IEnumerator.cs deleted file mode 100644 index 335616757b..0000000000 --- a/src/mscorlib/src/System/Collections/Generic/IEnumerator.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IEnumerator -** -** -** -** -** Purpose: Base interface for all generic enumerators. -** -** -===========================================================*/ -namespace System.Collections.Generic { - using System; - using System.Runtime.InteropServices; - - // Base interface for all generic enumerators, providing a simple approach - // to iterating over a collection. - public interface IEnumerator<out T> : IDisposable, IEnumerator - { - // Returns the current element of the enumeration. The returned value is - // undefined before the first call to MoveNext and following a - // call to MoveNext that returned false. Multiple calls to - // GetCurrent with no intervening calls to MoveNext - // will return the same object. - // - /// <include file='doc\IEnumerator.uex' path='docs/doc[@for="IEnumerator.Current"]/*' /> - new T Current { - get; - } - } -} diff --git a/src/mscorlib/src/System/Collections/Generic/IEqualityComparer.cs b/src/mscorlib/src/System/Collections/Generic/IEqualityComparer.cs deleted file mode 100644 index b6ac3be006..0000000000 --- a/src/mscorlib/src/System/Collections/Generic/IEqualityComparer.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// - -namespace System.Collections.Generic { - using System; - - // The generic IEqualityComparer interface implements methods to if check two objects are equal - // and generate Hashcode for an object. - // It is use in Dictionary class. - public interface IEqualityComparer<in T> - { - bool Equals(T x, T y); - int GetHashCode(T obj); - } -} - diff --git a/src/mscorlib/src/System/Collections/Generic/IList.cs b/src/mscorlib/src/System/Collections/Generic/IList.cs deleted file mode 100644 index 75ca0a9b00..0000000000 --- a/src/mscorlib/src/System/Collections/Generic/IList.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IList -** -** -** -** -** Purpose: Base interface for all generic lists. -** -** -===========================================================*/ -namespace System.Collections.Generic { - - using System; - using System.Collections; - using System.Runtime.CompilerServices; - using System.Diagnostics.Contracts; - - // An IList is an ordered collection of objects. The exact ordering - // is up to the implementation of the list, ranging from a sorted - // order to insertion order. - - // Note that T[] : IList<T>, and we want to ensure that if you use - // IList<YourValueType>, we ensure a YourValueType[] can be used - // without jitting. Hence the TypeDependencyAttribute on SZArrayHelper. - // This is a special workaround internally though - see VM\compile.cpp. - // The same attribute is on IEnumerable<T> and ICollection<T>. - [TypeDependencyAttribute("System.SZArrayHelper")] - public interface IList<T> : ICollection<T> - { - // The Item property provides methods to read and edit entries in the List. - T this[int index] { - get; - set; - } - - // Returns the index of a particular item, if it is in the list. - // Returns -1 if the item isn't in the list. - int IndexOf(T item); - - // Inserts value into the list at position index. - // index must be non-negative and less than or equal to the - // number of elements in the list. If index equals the number - // of items in the list, then value is appended to the end. - void Insert(int index, T item); - - // Removes the item at position index. - void RemoveAt(int index); - } -} diff --git a/src/mscorlib/src/System/Collections/Generic/IReadOnlyCollection.cs b/src/mscorlib/src/System/Collections/Generic/IReadOnlyCollection.cs deleted file mode 100644 index 13bc718760..0000000000 --- a/src/mscorlib/src/System/Collections/Generic/IReadOnlyCollection.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IReadOnlyCollection<T> -** -** -** -** Purpose: Base interface for read-only generic lists. -** -===========================================================*/ -using System; -using System.Diagnostics.Contracts; -using System.Runtime.CompilerServices; - -namespace System.Collections.Generic -{ - - // Provides a read-only, covariant view of a generic list. - - // Note that T[] : IReadOnlyList<T>, and we want to ensure that if you use - // IList<YourValueType>, we ensure a YourValueType[] can be used - // without jitting. Hence the TypeDependencyAttribute on SZArrayHelper. - // This is a special workaround internally though - see VM\compile.cpp. - // The same attribute is on IList<T>, IEnumerable<T>, ICollection<T>, and IReadOnlyList<T>. - [TypeDependencyAttribute("System.SZArrayHelper")] - // If we ever implement more interfaces on IReadOnlyCollection, we should also update RuntimeTypeCache.PopulateInterfaces() in rttype.cs - public interface IReadOnlyCollection<out T> : IEnumerable<T> - { - int Count { get; } - } -} diff --git a/src/mscorlib/src/System/Collections/Generic/IReadOnlyDictionary.cs b/src/mscorlib/src/System/Collections/Generic/IReadOnlyDictionary.cs deleted file mode 100644 index 3603b9a4ea..0000000000 --- a/src/mscorlib/src/System/Collections/Generic/IReadOnlyDictionary.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IReadOnlyDictionary<TKey, TValue> -** -** -** -** Purpose: Base interface for read-only generic dictionaries. -** -===========================================================*/ -using System; -using System.Diagnostics.Contracts; - -namespace System.Collections.Generic -{ - // Provides a read-only view of a generic dictionary. - public interface IReadOnlyDictionary<TKey, TValue> : IReadOnlyCollection<KeyValuePair<TKey, TValue>> - { - bool ContainsKey(TKey key); - bool TryGetValue(TKey key, out TValue value); - - TValue this[TKey key] { get; } - IEnumerable<TKey> Keys { get; } - IEnumerable<TValue> Values { get; } - } -} diff --git a/src/mscorlib/src/System/Collections/Generic/IReadOnlyList.cs b/src/mscorlib/src/System/Collections/Generic/IReadOnlyList.cs deleted file mode 100644 index 77366f0b2f..0000000000 --- a/src/mscorlib/src/System/Collections/Generic/IReadOnlyList.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IReadOnlyList<T> -** -** -** -** Purpose: Base interface for read-only generic lists. -** -===========================================================*/ -using System; -using System.Diagnostics.Contracts; -using System.Runtime.CompilerServices; - -namespace System.Collections.Generic -{ - - // Provides a read-only, covariant view of a generic list. - - // Note that T[] : IReadOnlyList<T>, and we want to ensure that if you use - // IList<YourValueType>, we ensure a YourValueType[] can be used - // without jitting. Hence the TypeDependencyAttribute on SZArrayHelper. - // This is a special workaround internally though - see VM\compile.cpp. - // The same attribute is on IList<T>, IEnumerable<T>, ICollection<T> and IReadOnlyCollection<T>. - [TypeDependencyAttribute("System.SZArrayHelper")] - // If we ever implement more interfaces on IReadOnlyList, we should also update RuntimeTypeCache.PopulateInterfaces() in rttype.cs - public interface IReadOnlyList<out T> : IReadOnlyCollection<T> - { - T this[int index] { get; } - } -} diff --git a/src/mscorlib/src/System/Collections/Generic/KeyNotFoundException.cs b/src/mscorlib/src/System/Collections/Generic/KeyNotFoundException.cs deleted file mode 100644 index 1cd18cf808..0000000000 --- a/src/mscorlib/src/System/Collections/Generic/KeyNotFoundException.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================================= -** -** -** -** -** -** Purpose: Exception class for Hashtable and Dictionary. -** -** -=============================================================================*/ - -namespace System.Collections.Generic { - - using System; - using System.Runtime.Remoting; - using System.Runtime.Serialization; - - [Serializable] - public class KeyNotFoundException : SystemException, ISerializable { - - public KeyNotFoundException () - : base(Environment.GetResourceString("Arg_KeyNotFound")) { - SetErrorCode(System.__HResults.COR_E_KEYNOTFOUND); - } - - public KeyNotFoundException(String message) - : base(message) { - SetErrorCode(System.__HResults.COR_E_KEYNOTFOUND); - } - - public KeyNotFoundException(String message, Exception innerException) - : base(message, innerException) { - SetErrorCode(System.__HResults.COR_E_KEYNOTFOUND); - } - - - protected KeyNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { - } - } -} diff --git a/src/mscorlib/src/System/Collections/Generic/KeyValuePair.cs b/src/mscorlib/src/System/Collections/Generic/KeyValuePair.cs deleted file mode 100644 index ba98adad7d..0000000000 --- a/src/mscorlib/src/System/Collections/Generic/KeyValuePair.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: KeyValuePair -** -** -** -** -** Purpose: Generic key-value pair for dictionary enumerators. -** -** -===========================================================*/ -namespace System.Collections.Generic { - - using System; - using System.ComponentModel; - using System.Text; - - // Provides the Create factory method for KeyValuePair<TKey, TValue>. - public static class KeyValuePair - { - // Creates a new KeyValuePair<TKey, TValue> from the given values. - public static KeyValuePair<TKey, TValue> Create<TKey, TValue>(TKey key, TValue value) - { - return new KeyValuePair<TKey, TValue>(key, value); - } - } - - // A KeyValuePair holds a key and a value from a dictionary. - // It is used by the IEnumerable<T> implementation for both IDictionary<TKey, TValue> - // and IReadOnlyDictionary<TKey, TValue>. - [Serializable] - public struct KeyValuePair<TKey, TValue> { - private TKey key; - private TValue value; - - public KeyValuePair(TKey key, TValue value) { - this.key = key; - this.value = value; - } - - public TKey Key { - get { return key; } - } - - public TValue Value { - get { return value; } - } - - public override string ToString() { - StringBuilder s = StringBuilderCache.Acquire(); - s.Append('['); - if( Key != null) { - s.Append(Key.ToString()); - } - s.Append(", "); - if( Value != null) { - s.Append(Value.ToString()); - } - s.Append(']'); - return StringBuilderCache.GetStringAndRelease(s); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out TKey key, out TValue value) - { - key = Key; - value = Value; - } - } -} diff --git a/src/mscorlib/src/System/Collections/Generic/List.cs b/src/mscorlib/src/System/Collections/Generic/List.cs index 362e26599d..67d1668aad 100644 --- a/src/mscorlib/src/System/Collections/Generic/List.cs +++ b/src/mscorlib/src/System/Collections/Generic/List.cs @@ -12,15 +12,15 @@ ** ** ===========================================================*/ -namespace System.Collections.Generic { - using System; - using System.Runtime; - using System.Runtime.Versioning; - using System.Diagnostics; - using System.Diagnostics.Contracts; - using System.Collections.ObjectModel; +using System; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Collections.ObjectModel; +using System.Runtime.CompilerServices; +namespace System.Collections.Generic +{ // Implements a variable-size List that uses an array of objects to store the // elements. A List has a capacity, which is the allocated length // of the internal array. As elements are added to a List, the capacity @@ -40,22 +40,24 @@ namespace System.Collections.Generic { private int _version; [NonSerialized] private Object _syncRoot; - - static readonly T[] _emptyArray = new T[0]; - + + private static readonly T[] _emptyArray = new T[0]; + // Constructs a List. The list is initially empty and has a capacity // of zero. Upon adding the first element to the list the capacity is // increased to _defaultCapacity, and then increased in multiples of two // as required. - public List() { + public List() + { _items = _emptyArray; } - + // Constructs a List with a given initial capacity. The list is // initially empty, but will have room for the given number of elements // before any reallocations are required. // - public List(int capacity) { + public List(int capacity) + { if (capacity < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); Contract.EndContractBlock(); @@ -64,116 +66,142 @@ namespace System.Collections.Generic { else _items = new T[capacity]; } - + // Constructs a List, copying the contents of the given collection. The // size and capacity of the new list will both be equal to the size of the // given collection. // - public List(IEnumerable<T> collection) { - if (collection==null) + public List(IEnumerable<T> collection) + { + if (collection == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); Contract.EndContractBlock(); ICollection<T> c = collection as ICollection<T>; - if( c != null) { + if (c != null) + { int count = c.Count; if (count == 0) { _items = _emptyArray; } - else { + else + { _items = new T[count]; c.CopyTo(_items, 0); _size = count; } - } - else { + } + else + { _size = 0; _items = _emptyArray; AddEnumerable(collection); } } - + // Gets and sets the capacity of this list. The capacity is the size of // the internal array used to hold items. When set, the internal // array of the list is reallocated to the given capacity. // - public int Capacity { - get { + public int Capacity + { + get + { Contract.Ensures(Contract.Result<int>() >= 0); return _items.Length; } - set { - if (value < _size) { + set + { + if (value < _size) + { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity); } Contract.EndContractBlock(); - if (value != _items.Length) { - if (value > 0) { + if (value != _items.Length) + { + if (value > 0) + { T[] newItems = new T[value]; - if (_size > 0) { + if (_size > 0) + { Array.Copy(_items, 0, newItems, 0, _size); } _items = newItems; } - else { + else + { _items = _emptyArray; } } } } - + // Read-only property describing how many elements are in the List. - public int Count { - get { + public int Count + { + get + { Contract.Ensures(Contract.Result<int>() >= 0); - return _size; + return _size; } } - bool System.Collections.IList.IsFixedSize { + bool System.Collections.IList.IsFixedSize + { get { return false; } } - + // Is this List read-only? - bool ICollection<T>.IsReadOnly { + bool ICollection<T>.IsReadOnly + { get { return false; } } - bool System.Collections.IList.IsReadOnly { + bool System.Collections.IList.IsReadOnly + { get { return false; } } // Is this List synchronized (thread-safe)? - bool System.Collections.ICollection.IsSynchronized { + bool System.Collections.ICollection.IsSynchronized + { get { return false; } } - + // Synchronization root for this object. - Object System.Collections.ICollection.SyncRoot { - get { - if( _syncRoot == null) { - System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); + Object System.Collections.ICollection.SyncRoot + { + get + { + if (_syncRoot == null) + { + System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); } return _syncRoot; } } // Sets or Gets the element at the given index. // - public T this[int index] { - get { + public T this[int index] + { + get + { // Following trick can reduce the range check by one - if ((uint) index >= (uint)_size) { + if ((uint)index >= (uint)_size) + { ThrowHelper.ThrowArgumentOutOfRange_IndexException(); } Contract.EndContractBlock(); - return _items[index]; + return _items[index]; } - set { - if ((uint) index >= (uint)_size) { + set + { + if ((uint)index >= (uint)_size) + { ThrowHelper.ThrowArgumentOutOfRange_IndexException(); } Contract.EndContractBlock(); @@ -182,24 +210,30 @@ namespace System.Collections.Generic { } } - private static bool IsCompatibleObject(object value) { + private static bool IsCompatibleObject(object value) + { // Non-null values are fine. Only accept nulls if T is a class or Nullable<U>. // Note that default(T) is not equal to null for value types except when T is Nullable<U>. return ((value is T) || (value == null && default(T) == null)); } - Object System.Collections.IList.this[int index] { - get { + Object System.Collections.IList.this[int index] + { + get + { return this[index]; } - set { + set + { ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(value, ExceptionArgument.value); - try { - this[index] = (T)value; + try + { + this[index] = (T)value; } - catch (InvalidCastException) { - ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T)); + catch (InvalidCastException) + { + ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T)); } } } @@ -207,22 +241,44 @@ namespace System.Collections.Generic { // Adds the given object to the end of this list. The size of the list is // increased by one. If required, the capacity of the list is doubled // before adding the new element. - // - public void Add(T item) { - if (_size == _items.Length) EnsureCapacity(_size + 1); - _items[_size++] = item; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(T item) + { + var array = _items; + var size = _size; _version++; + if ((uint)size < (uint)array.Length) + { + _size = size + 1; + array[size] = item; + } + else + { + AddWithResize(item); + } + } + + // Non-inline from List.Add to improve its code quality as uncommon path + [MethodImpl(MethodImplOptions.NoInlining)] + private void AddWithResize(T item) + { + var size = _size; + EnsureCapacity(size + 1); + _size = size + 1; + _items[size] = item; } int System.Collections.IList.Add(Object item) { ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item); - try { - Add((T) item); + try + { + Add((T)item); } - catch (InvalidCastException) { - ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T)); + catch (InvalidCastException) + { + ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T)); } return Count - 1; @@ -233,17 +289,19 @@ namespace System.Collections.Generic { // required, the capacity of the list is increased to twice the previous // capacity or the new size, whichever is larger. // - public void AddRange(IEnumerable<T> collection) { + public void AddRange(IEnumerable<T> collection) + { Contract.Ensures(Count >= Contract.OldValue(Count)); InsertRange(_size, collection); } - public ReadOnlyCollection<T> AsReadOnly() { + public ReadOnlyCollection<T> AsReadOnly() + { Contract.Ensures(Contract.Result<ReadOnlyCollection<T>>() != null); return new ReadOnlyCollection<T>(this); } - + // Searches a section of the list for a given element using a binary search // algorithm. Elements of the list are compared to the search value using // the given IComparer interface. If comparer is null, elements of @@ -264,7 +322,8 @@ namespace System.Collections.Generic { // The method uses the Array.BinarySearch method to perform the // search. // - public int BinarySearch(int index, int count, T item, IComparer<T> comparer) { + public int BinarySearch(int index, int count, T item, IComparer<T> comparer) + { if (index < 0) ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); if (count < 0) @@ -276,7 +335,7 @@ namespace System.Collections.Generic { return Array.BinarySearch<T>(_items, index, count, item, comparer); } - + public int BinarySearch(T item) { Contract.Ensures(Contract.Result<int>() <= Count); @@ -289,17 +348,27 @@ namespace System.Collections.Generic { return BinarySearch(0, Count, item, comparer); } - + // Clears the contents of List. - public void Clear() { - if (_size > 0) + public void Clear() + { + if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) { - Array.Clear(_items, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references. + int size = _size; _size = 0; + _version++; + if (size > 0) + { + Array.Clear(_items, 0, size); // Clear the elements so that the gc can reclaim the references. + } + } + else + { + _size = 0; + _version++; } - _version++; } - + // Contains returns true if the specified element is in the List. // It does a linear, O(n) search. Equality is determined by calling // EqualityComparer<T>.Default.Equals(). @@ -319,21 +388,25 @@ namespace System.Collections.Generic { bool System.Collections.IList.Contains(Object item) { - if(IsCompatibleObject(item)) { - return Contains((T) item); + if (IsCompatibleObject(item)) + { + return Contains((T)item); } return false; } - public List<TOutput> ConvertAll<TOutput>(Converter<T,TOutput> converter) { - if( converter == null) { + public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter) + { + if (converter == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.converter); } Contract.EndContractBlock(); List<TOutput> list = new List<TOutput>(_size); - for( int i = 0; i< _size; i++) { + for (int i = 0; i < _size; i++) + { list._items[i] = converter(_items[i]); } list._size = _size; @@ -343,43 +416,51 @@ namespace System.Collections.Generic { // Copies this List into array, which must be of a // compatible array type. // - public void CopyTo(T[] array) { + public void CopyTo(T[] array) + { CopyTo(array, 0); } // Copies this List into array, which must be of a // compatible array type. // - void System.Collections.ICollection.CopyTo(Array array, int arrayIndex) { - if ((array != null) && (array.Rank != 1)) { + void System.Collections.ICollection.CopyTo(Array array, int arrayIndex) + { + if ((array != null) && (array.Rank != 1)) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); } Contract.EndContractBlock(); - try { + try + { // Array.Copy will check for NULL. Array.Copy(_items, 0, array, arrayIndex, _size); } - catch(ArrayTypeMismatchException){ + catch (ArrayTypeMismatchException) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } } - + // Copies a section of this list to the given array at the given index. // // The method uses the Array.Copy method to copy the elements. // - public void CopyTo(int index, T[] array, int arrayIndex, int count) { - if (_size - index < count) { + public void CopyTo(int index, T[] array, int arrayIndex, int count) + { + if (_size - index < count) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen); } Contract.EndContractBlock(); - + // Delegate rest of error checking to Array.Copy. Array.Copy(_items, index, array, arrayIndex, count); } - public void CopyTo(T[] array, int arrayIndex) { + public void CopyTo(T[] array, int arrayIndex) + { // Delegate rest of error checking to Array.Copy. Array.Copy(_items, 0, array, arrayIndex, _size); } @@ -388,9 +469,11 @@ namespace System.Collections.Generic { // value. If the current capacity of the list is less than min, the // capacity is increased to twice the current capacity or to min, // whichever is larger. - private void EnsureCapacity(int min) { - if (_items.Length < min) { - int newCapacity = _items.Length == 0? _defaultCapacity : _items.Length * 2; + private void EnsureCapacity(int min) + { + if (_items.Length < min) + { + int newCapacity = _items.Length == 0 ? _defaultCapacity : _items.Length * 2; // Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow. // Note that this check works even when _items.Length overflowed thanks to the (uint) cast if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength; @@ -398,62 +481,77 @@ namespace System.Collections.Generic { Capacity = newCapacity; } } - - public bool Exists(Predicate<T> match) { + + public bool Exists(Predicate<T> match) + { return FindIndex(match) != -1; } - public T Find(Predicate<T> match) { - if( match == null) { + public T Find(Predicate<T> match) + { + if (match == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } Contract.EndContractBlock(); - for(int i = 0 ; i < _size; i++) { - if(match(_items[i])) { + for (int i = 0; i < _size; i++) + { + if (match(_items[i])) + { return _items[i]; } } return default(T); } - - public List<T> FindAll(Predicate<T> match) { - if( match == null) { + + public List<T> FindAll(Predicate<T> match) + { + if (match == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } Contract.EndContractBlock(); - List<T> list = new List<T>(); - for(int i = 0 ; i < _size; i++) { - if(match(_items[i])) { + List<T> list = new List<T>(); + for (int i = 0; i < _size; i++) + { + if (match(_items[i])) + { list.Add(_items[i]); } } return list; } - - public int FindIndex(Predicate<T> match) { + + public int FindIndex(Predicate<T> match) + { Contract.Ensures(Contract.Result<int>() >= -1); Contract.Ensures(Contract.Result<int>() < Count); return FindIndex(0, _size, match); } - - public int FindIndex(int startIndex, Predicate<T> match) { + + public int FindIndex(int startIndex, Predicate<T> match) + { Contract.Ensures(Contract.Result<int>() >= -1); Contract.Ensures(Contract.Result<int>() < startIndex + Count); return FindIndex(startIndex, _size - startIndex, match); } - - public int FindIndex(int startIndex, int count, Predicate<T> match) { - if( (uint)startIndex > (uint)_size ) { - ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index(); + + public int FindIndex(int startIndex, int count, Predicate<T> match) + { + if ((uint)startIndex > (uint)_size) + { + ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index(); } - if (count < 0 || startIndex > _size - count) { + if (count < 0 || startIndex > _size - count) + { ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count(); } - if( match == null) { + if (match == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } Contract.Ensures(Contract.Result<int>() >= -1); @@ -461,83 +559,103 @@ namespace System.Collections.Generic { Contract.EndContractBlock(); int endIndex = startIndex + count; - for( int i = startIndex; i < endIndex; i++) { - if( match(_items[i])) return i; + for (int i = startIndex; i < endIndex; i++) + { + if (match(_items[i])) return i; } return -1; } - - public T FindLast(Predicate<T> match) { - if( match == null) { + + public T FindLast(Predicate<T> match) + { + if (match == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } Contract.EndContractBlock(); - for(int i = _size - 1 ; i >= 0; i--) { - if(match(_items[i])) { + for (int i = _size - 1; i >= 0; i--) + { + if (match(_items[i])) + { return _items[i]; } } return default(T); } - public int FindLastIndex(Predicate<T> match) { + public int FindLastIndex(Predicate<T> match) + { Contract.Ensures(Contract.Result<int>() >= -1); Contract.Ensures(Contract.Result<int>() < Count); return FindLastIndex(_size - 1, _size, match); } - - public int FindLastIndex(int startIndex, Predicate<T> match) { + + public int FindLastIndex(int startIndex, Predicate<T> match) + { Contract.Ensures(Contract.Result<int>() >= -1); Contract.Ensures(Contract.Result<int>() <= startIndex); return FindLastIndex(startIndex, startIndex + 1, match); } - public int FindLastIndex(int startIndex, int count, Predicate<T> match) { - if( match == null) { + public int FindLastIndex(int startIndex, int count, Predicate<T> match) + { + if (match == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } Contract.Ensures(Contract.Result<int>() >= -1); Contract.Ensures(Contract.Result<int>() <= startIndex); Contract.EndContractBlock(); - if(_size == 0) { + if (_size == 0) + { // Special case for 0 length List - if( startIndex != -1) { + if (startIndex != -1) + { ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index(); } } - else { + else + { // Make sure we're not out of range - if ( (uint)startIndex >= (uint)_size) { + if ((uint)startIndex >= (uint)_size) + { ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index(); } } - + // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0. - if (count < 0 || startIndex - count + 1 < 0) { + if (count < 0 || startIndex - count + 1 < 0) + { ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count(); } - + int endIndex = startIndex - count; - for( int i = startIndex; i > endIndex; i--) { - if( match(_items[i])) { + for (int i = startIndex; i > endIndex; i--) + { + if (match(_items[i])) + { return i; } } return -1; } - public void ForEach(Action<T> action) { - if( action == null) { + public void ForEach(Action<T> action) + { + if (action == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.action); } Contract.EndContractBlock(); int version = _version; - for(int i = 0 ; i < _size; i++) { - if (version != _version) { + for (int i = 0; i < _size; i++) + { + if (version != _version) + { break; } action(_items[i]); @@ -552,36 +670,42 @@ namespace System.Collections.Generic { // while an enumeration is in progress, the MoveNext and // GetObject methods of the enumerator will throw an exception. // - public Enumerator GetEnumerator() { + public Enumerator GetEnumerator() + { return new Enumerator(this); } - /// <internalonly/> - IEnumerator<T> IEnumerable<T>.GetEnumerator() { + IEnumerator<T> IEnumerable<T>.GetEnumerator() + { return new Enumerator(this); } - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { return new Enumerator(this); } - public List<T> GetRange(int index, int count) { - if (index < 0) { + public List<T> GetRange(int index, int count) + { + if (index < 0) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - if (count < 0) { + if (count < 0) + { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } - if (_size - index < count) { - ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen); + if (_size - index < count) + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen); } Contract.Ensures(Contract.Result<List<T>>() != null); Contract.EndContractBlock(); List<T> list = new List<T>(count); - Array.Copy(_items, index, list._items, 0, count); + Array.Copy(_items, index, list._items, 0, count); list._size = count; return list; } @@ -595,7 +719,8 @@ namespace System.Collections.Generic { // This method uses the Array.IndexOf method to perform the // search. // - public int IndexOf(T item) { + public int IndexOf(T item) + { Contract.Ensures(Contract.Result<int>() >= -1); Contract.Ensures(Contract.Result<int>() < Count); return Array.IndexOf(_items, item, 0, _size); @@ -603,7 +728,8 @@ namespace System.Collections.Generic { int System.Collections.IList.IndexOf(Object item) { - if(IsCompatibleObject(item)) { + if (IsCompatibleObject(item)) + { return IndexOf((T)item); } return -1; @@ -618,7 +744,8 @@ namespace System.Collections.Generic { // This method uses the Array.IndexOf method to perform the // search. // - public int IndexOf(T item, int index) { + public int IndexOf(T item, int index) + { if (index > _size) ThrowHelper.ThrowArgumentOutOfRange_IndexException(); Contract.Ensures(Contract.Result<int>() >= -1); @@ -636,46 +763,52 @@ namespace System.Collections.Generic { // This method uses the Array.IndexOf method to perform the // search. // - public int IndexOf(T item, int index, int count) { + public int IndexOf(T item, int index, int count) + { if (index > _size) ThrowHelper.ThrowArgumentOutOfRange_IndexException(); - if (count <0 || index > _size - count) ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count(); + if (count < 0 || index > _size - count) ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count(); Contract.Ensures(Contract.Result<int>() >= -1); Contract.Ensures(Contract.Result<int>() < Count); Contract.EndContractBlock(); return Array.IndexOf(_items, item, index, count); } - + // Inserts an element into this list at a given index. The size of the list // is increased by one. If required, the capacity of the list is doubled // before inserting the new element. // - public void Insert(int index, T item) { + public void Insert(int index, T item) + { // Note that insertions at the end are legal. - if ((uint) index > (uint)_size) { + if ((uint)index > (uint)_size) + { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_ListInsert); } Contract.EndContractBlock(); if (_size == _items.Length) EnsureCapacity(_size + 1); - if (index < _size) { + if (index < _size) + { Array.Copy(_items, index, _items, index + 1, _size - index); } _items[index] = item; - _size++; + _size++; _version++; } - + void System.Collections.IList.Insert(int index, Object item) { ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item); - try { - Insert(index, (T) item); + try + { + Insert(index, (T)item); } - catch (InvalidCastException) { - ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T)); + catch (InvalidCastException) + { + ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T)); } } @@ -684,44 +817,55 @@ namespace System.Collections.Generic { // capacity or the new size, whichever is larger. Ranges may be added // to the end of the list by setting index to the List's size. // - public void InsertRange(int index, IEnumerable<T> collection) { - if (collection==null) { + public void InsertRange(int index, IEnumerable<T> collection) + { + if (collection == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); } - - if ((uint)index > (uint)_size) { + + if ((uint)index > (uint)_size) + { ThrowHelper.ThrowArgumentOutOfRange_IndexException(); } Contract.EndContractBlock(); ICollection<T> c = collection as ICollection<T>; - if( c != null ) { // if collection is ICollection<T> + if (c != null) + { // if collection is ICollection<T> int count = c.Count; - if (count > 0) { + if (count > 0) + { EnsureCapacity(_size + count); - if (index < _size) { + if (index < _size) + { Array.Copy(_items, index, _items, index + count, _size - index); } - + // If we're inserting a List into itself, we want to be able to deal with that. - if (this == c) { + if (this == c) + { // Copy first part of _items to insert location Array.Copy(_items, 0, _items, index, index); // Copy last part of _items back to inserted location - Array.Copy(_items, index+count, _items, index*2, _size-index); + Array.Copy(_items, index + count, _items, index * 2, _size - index); } - else { + else + { c.CopyTo(_items, index); } _size += count; - } + } } - else if (index < _size) { + else if (index < _size) + { // We're inserting a lazy enumerable. Call Insert on each of the constituent items. - using(IEnumerator<T> en = collection.GetEnumerator()) { - while(en.MoveNext()) { - Insert(index++, en.Current); - } + using (IEnumerator<T> en = collection.GetEnumerator()) + { + while (en.MoveNext()) + { + Insert(index++, en.Current); + } } } else @@ -729,9 +873,9 @@ namespace System.Collections.Generic { // We're adding a lazy enumerable because the index is at the end of this list. AddEnumerable(collection); } - _version++; + _version++; } - + // Returns the index of the last occurrence of a given value in a range of // this list. The list is searched backwards, starting at the end // and ending at the first element in the list. The elements of the list @@ -744,10 +888,12 @@ namespace System.Collections.Generic { { Contract.Ensures(Contract.Result<int>() >= -1); Contract.Ensures(Contract.Result<int>() < Count); - if (_size == 0) { // Special case for empty list + if (_size == 0) + { // Special case for empty list return -1; } - else { + else + { return LastIndexOf(item, _size - 1, _size); } } @@ -780,39 +926,47 @@ namespace System.Collections.Generic { // This method uses the Array.LastIndexOf method to perform the // search. // - public int LastIndexOf(T item, int index, int count) { - if ((Count != 0) && (index < 0)) { + public int LastIndexOf(T item, int index, int count) + { + if ((Count != 0) && (index < 0)) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - if ((Count !=0) && (count < 0)) { + if ((Count != 0) && (count < 0)) + { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } Contract.Ensures(Contract.Result<int>() >= -1); Contract.Ensures(((Count == 0) && (Contract.Result<int>() == -1)) || ((Count > 0) && (Contract.Result<int>() <= index))); Contract.EndContractBlock(); - if (_size == 0) { // Special case for empty list + if (_size == 0) + { // Special case for empty list return -1; } - if (index >= _size) { + if (index >= _size) + { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_BiggerThanCollection); } - if (count > index + 1) { + if (count > index + 1) + { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_BiggerThanCollection); - } + } return Array.LastIndexOf(_items, item, index, count); } - + // Removes the element at the given index. The size of the list is // decreased by one. // - public bool Remove(T item) { + public bool Remove(T item) + { int index = IndexOf(item); - if (index >= 0) { + if (index >= 0) + { RemoveAt(index); return true; } @@ -822,39 +976,48 @@ namespace System.Collections.Generic { void System.Collections.IList.Remove(Object item) { - if(IsCompatibleObject(item)) { - Remove((T) item); + if (IsCompatibleObject(item)) + { + Remove((T)item); } } // This method removes all items which matches the predicate. // The complexity is O(n). - public int RemoveAll(Predicate<T> match) { - if( match == null) { + public int RemoveAll(Predicate<T> match) + { + if (match == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } Contract.Ensures(Contract.Result<int>() >= 0); Contract.Ensures(Contract.Result<int>() <= Contract.OldValue(Count)); Contract.EndContractBlock(); - + int freeIndex = 0; // the first free slot in items array // Find the first item which needs to be removed. - while( freeIndex < _size && !match(_items[freeIndex])) freeIndex++; - if( freeIndex >= _size) return 0; - + while (freeIndex < _size && !match(_items[freeIndex])) freeIndex++; + if (freeIndex >= _size) return 0; + int current = freeIndex + 1; - while( current < _size) { + while (current < _size) + { // Find the first item which needs to be kept. - while( current < _size && match(_items[current])) current++; + while (current < _size && match(_items[current])) current++; - if( current < _size) { + if (current < _size) + { // copy item to the free slot. _items[freeIndex++] = _items[current++]; } - } - - Array.Clear(_items, freeIndex, _size - freeIndex); + } + + if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) + { + Array.Clear(_items, freeIndex, _size - freeIndex); // Clear the elements so that the gc can reclaim the references. + } + int result = _size - freeIndex; _size = freeIndex; _version++; @@ -864,61 +1027,80 @@ namespace System.Collections.Generic { // Removes the element at the given index. The size of the list is // decreased by one. // - public void RemoveAt(int index) { - if ((uint)index >= (uint)_size) { + public void RemoveAt(int index) + { + if ((uint)index >= (uint)_size) + { ThrowHelper.ThrowArgumentOutOfRange_IndexException(); } Contract.EndContractBlock(); _size--; - if (index < _size) { + if (index < _size) + { Array.Copy(_items, index + 1, _items, index, _size - index); } - _items[_size] = default(T); + if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) + { + _items[_size] = default(T); + } _version++; } - + // Removes a range of elements from this list. // - public void RemoveRange(int index, int count) { - if (index < 0) { + public void RemoveRange(int index, int count) + { + if (index < 0) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - if (count < 0) { + if (count < 0) + { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } - + if (_size - index < count) ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen); Contract.EndContractBlock(); - - if (count > 0) { + + if (count > 0) + { int i = _size; _size -= count; - if (index < _size) { + if (index < _size) + { Array.Copy(_items, index + count, _items, index, _size - index); } - Array.Clear(_items, _size, count); + _version++; + if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) + { + Array.Clear(_items, _size, count); + } } } - + // Reverses the elements in this list. - public void Reverse() { + public void Reverse() + { Reverse(0, Count); } - + // Reverses the elements in a range of this list. Following a call to this // method, an element in the range given by index and count // which was previously located at index i will now be located at // index index + (index + count - i - 1). // - public void Reverse(int index, int count) { - if (index < 0) { + public void Reverse(int index, int count) + { + if (index < 0) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - - if (count < 0) { + + if (count < 0) + { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } @@ -926,12 +1108,13 @@ namespace System.Collections.Generic { ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen); Contract.EndContractBlock(); - if (count > 1) { + if (count > 1) + { Array.Reverse(_items, index, count); } _version++; } - + // Sorts the elements in this list. Uses the default comparer and // Array.Sort. public void Sort() @@ -954,32 +1137,39 @@ namespace System.Collections.Generic { // // This method uses the Array.Sort method to sort the elements. // - public void Sort(int index, int count, IComparer<T> comparer) { - if (index < 0) { + public void Sort(int index, int count, IComparer<T> comparer) + { + if (index < 0) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - - if (count < 0) { + + if (count < 0) + { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } - + if (_size - index < count) ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen); Contract.EndContractBlock(); - if (count > 1) { + if (count > 1) + { Array.Sort<T>(_items, index, count, comparer); } _version++; } - public void Sort(Comparison<T> comparison) { - if( comparison == null) { + public void Sort(Comparison<T> comparison) + { + if (comparison == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.comparison); } Contract.EndContractBlock(); - if (_size > 1) { + if (_size > 1) + { ArraySortHelper<T>.Sort(_items, 0, _size, comparison); } _version++; @@ -987,7 +1177,8 @@ namespace System.Collections.Generic { // ToArray returns an array containing the contents of the List. // This requires copying the List, which is an O(n) operation. - public T[] ToArray() { + public T[] ToArray() + { Contract.Ensures(Contract.Result<T[]>() != null); Contract.Ensures(Contract.Result<T[]>().Length == Count); @@ -1000,7 +1191,7 @@ namespace System.Collections.Generic { Array.Copy(_items, 0, array, 0, _size); return array; } - + // Sets the capacity of this list to the size of the list. This method can // be used to minimize a list's memory overhead once it is known that no // new elements will be added to the list. To completely clear a list and @@ -1010,21 +1201,27 @@ namespace System.Collections.Generic { // list.Clear(); // list.TrimExcess(); // - public void TrimExcess() { - int threshold = (int)(((double)_items.Length) * 0.9); - if( _size < threshold ) { - Capacity = _size; + public void TrimExcess() + { + int threshold = (int)(((double)_items.Length) * 0.9); + if (_size < threshold) + { + Capacity = _size; } - } + } - public bool TrueForAll(Predicate<T> match) { - if( match == null) { + public bool TrueForAll(Predicate<T> match) + { + if (match == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } Contract.EndContractBlock(); - for(int i = 0 ; i < _size; i++) { - if( !match(_items[i])) { + for (int i = 0; i < _size; i++) + { + if (!match(_items[i])) + { return false; } } @@ -1064,23 +1261,25 @@ namespace System.Collections.Generic { private int version; private T current; - internal Enumerator(List<T> list) { + internal Enumerator(List<T> list) + { this.list = list; index = 0; version = list._version; current = default(T); } - public void Dispose() { + public void Dispose() + { } - public bool MoveNext() { - + public bool MoveNext() + { List<T> localList = list; - if (version == localList._version && ((uint)index < (uint)localList._size)) - { - current = localList._items[index]; + if (version == localList._version && ((uint)index < (uint)localList._size)) + { + current = localList._items[index]; index++; return true; } @@ -1088,40 +1287,47 @@ namespace System.Collections.Generic { } private bool MoveNextRare() - { - if (version != list._version) { + { + if (version != list._version) + { ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); } index = list._size + 1; current = default(T); - return false; + return false; } - public T Current { - get { + public T Current + { + get + { return current; } } - Object System.Collections.IEnumerator.Current { - get { - if( index == 0 || index == list._size + 1) { - ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + Object System.Collections.IEnumerator.Current + { + get + { + if (index == 0 || index == list._size + 1) + { + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); } return Current; } } - - void System.Collections.IEnumerator.Reset() { - if (version != list._version) { + + void System.Collections.IEnumerator.Reset() + { + if (version != list._version) + { ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); } - + index = 0; current = default(T); } - } } } diff --git a/src/mscorlib/src/System/Collections/Hashtable.cs b/src/mscorlib/src/System/Collections/Hashtable.cs index d1831dd97d..e2fd57ea4d 100644 --- a/src/mscorlib/src/System/Collections/Hashtable.cs +++ b/src/mscorlib/src/System/Collections/Hashtable.cs @@ -13,12 +13,13 @@ ** ===========================================================*/ -namespace System.Collections { +namespace System.Collections +{ using System; using System.Runtime; using System.Runtime.Serialization; using System.Diagnostics; - using System.Threading; + using System.Threading; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Diagnostics.Contracts; @@ -66,7 +67,8 @@ namespace System.Collections { [DebuggerTypeProxy(typeof(System.Collections.Hashtable.HashtableDebugView))] [DebuggerDisplay("Count = {Count}")] [Serializable] - internal class Hashtable : IDictionary, ISerializable, IDeserializationCallback, ICloneable { + internal class Hashtable : IDictionary, ISerializable, IDeserializationCallback, ICloneable + { /* Implementation Notes: The generic Dictionary was copied from Hashtable's source - any bug @@ -121,7 +123,7 @@ namespace System.Collections { -- */ - + internal const Int32 HashPrime = 101; private const Int32 InitialSize = 3; private const String LoadFactorName = "LoadFactor"; @@ -132,31 +134,32 @@ namespace System.Collections { private const String KeysName = "Keys"; private const String ValuesName = "Values"; private const String KeyComparerName = "KeyComparer"; - + // Deleted entries have their key set to buckets - + // The hash table data. // This cannot be serialised - private struct bucket { + private struct bucket + { public Object key; public Object val; public int hash_coll; // Store hash code; sign bit means there was a collision. } - + private bucket[] buckets; - + // The total number of entries in the hash table. - private int count; - + private int count; + // The total number of collision bits set in the hashtable private int occupancy; - - private int loadsize; - private float loadFactor; - + + private int loadsize; + private float loadFactor; + private volatile int version; - private volatile bool isWriterInProgress; - + private volatile bool isWriterInProgress; + private ICollection keys; private ICollection values; @@ -165,15 +168,16 @@ namespace System.Collections { // Note: this constructor is a bogus constructor that does nothing // and is for use only with SyncHashtable. - internal Hashtable( bool trash ) + internal Hashtable(bool trash) { } // Constructs a new hashtable. The hashtable is created with an initial // capacity of zero and a load factor of 1.0. - public Hashtable() : this(0, 1.0f) { + public Hashtable() : this(0, 1.0f) + { } - + // Constructs a new hashtable with the given initial capacity and a load // factor of 1.0. The capacity argument serves as an indication of // the number of entries the hashtable will contain. When this number (or @@ -181,9 +185,10 @@ namespace System.Collections { // eliminate a number of resizing operations that would otherwise be // performed when elements are added to the hashtable. // - public Hashtable(int capacity) : this(capacity, 1.0f) { + public Hashtable(int capacity) : this(capacity, 1.0f) + { } - + // Constructs a new hashtable with the given initial capacity and load // factor. The capacity argument serves as an indication of the // number of entries the hashtable will contain. When this number (or an @@ -195,19 +200,20 @@ namespace System.Collections { // increased memory consumption. A load factor of 1.0 generally provides // the best balance between speed and size. // - public Hashtable(int capacity, float loadFactor) { + public Hashtable(int capacity, float loadFactor) + { if (capacity < 0) - throw new ArgumentOutOfRangeException(nameof(capacity), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_NeedNonNegNum); if (!(loadFactor >= 0.1f && loadFactor <= 1.0f)) - throw new ArgumentOutOfRangeException(nameof(loadFactor), Environment.GetResourceString("ArgumentOutOfRange_HashtableLoadFactor", .1, 1.0)); + throw new ArgumentOutOfRangeException(nameof(loadFactor), SR.Format(SR.ArgumentOutOfRange_HashtableLoadFactor, .1, 1.0)); Contract.EndContractBlock(); - + // Based on perf work, .72 is the optimal load factor for this table. this.loadFactor = 0.72f * loadFactor; double rawsize = capacity / this.loadFactor; if (rawsize > Int32.MaxValue) - throw new ArgumentException(Environment.GetResourceString("Arg_HTCapacityOverflow")); + throw new ArgumentException(SR.Arg_HTCapacityOverflow); // Avoid awfully small sizes int hashsize = (rawsize > InitialSize) ? HashHelpers.GetPrime((int)rawsize) : InitialSize; @@ -216,18 +222,21 @@ namespace System.Collections { loadsize = (int)(this.loadFactor * hashsize); isWriterInProgress = false; // Based on the current algorithm, loadsize must be less than hashsize. - Debug.Assert( loadsize < hashsize, "Invalid hashtable loadsize!"); + Debug.Assert(loadsize < hashsize, "Invalid hashtable loadsize!"); } - - public Hashtable(int capacity, float loadFactor, IEqualityComparer equalityComparer) : this(capacity, loadFactor) { - this._keycomparer = equalityComparer; + + public Hashtable(int capacity, float loadFactor, IEqualityComparer equalityComparer) : this(capacity, loadFactor) + { + _keycomparer = equalityComparer; } - public Hashtable(IEqualityComparer equalityComparer) : this(0, 1.0f, equalityComparer) { + public Hashtable(IEqualityComparer equalityComparer) : this(0, 1.0f, equalityComparer) + { } - - public Hashtable(int capacity, IEqualityComparer equalityComparer) - : this(capacity, 1.0f, equalityComparer) { + + public Hashtable(int capacity, IEqualityComparer equalityComparer) + : this(capacity, 1.0f, equalityComparer) + { } // InitHash is basically an implementation of classic DoubleHashing (see http://en.wikipedia.org/wiki/Double_hashing) @@ -250,11 +259,12 @@ namespace System.Collections { // The out parameter seed is h1(key), while the out parameter // incr is h2(key, hashSize). Callers of this function should // add incr each time through a loop. - private uint InitHash(Object key, int hashsize, out uint seed, out uint incr) { + private uint InitHash(Object key, int hashsize, out uint seed, out uint incr) + { // Hashcode must be positive. Also, we must not use the sign bit, since // that is used for the collision bit. - uint hashcode = (uint) GetHash(key) & 0x7FFFFFFF; - seed = (uint) hashcode; + uint hashcode = (uint)GetHash(key) & 0x7FFFFFFF; + seed = (uint)hashcode; // Restriction: incr MUST be between 1 and hashsize - 1, inclusive for // the modular arithmetic to work correctly. This guarantees you'll // visit every bucket in the table exactly once within hashsize @@ -268,64 +278,72 @@ namespace System.Collections { // ArgumentException is thrown if the key is null or if the key is already // present in the hashtable. // - public virtual void Add(Object key, Object value) { + public virtual void Add(Object key, Object value) + { Insert(key, value, true); } // Removes all entries from this hashtable. - public virtual void Clear() { + public virtual void Clear() + { Debug.Assert(!isWriterInProgress, "Race condition detected in usages of Hashtable - multiple threads appear to be writing to a Hashtable instance simultaneously! Don't do that - use Hashtable.Synchronized."); if (count == 0 && occupancy == 0) return; isWriterInProgress = true; - for (int i = 0; i < buckets.Length; i++){ + for (int i = 0; i < buckets.Length; i++) + { buckets[i].hash_coll = 0; buckets[i].key = null; buckets[i].val = null; } - + count = 0; occupancy = 0; - UpdateVersion(); - isWriterInProgress = false; + UpdateVersion(); + isWriterInProgress = false; } - + // Clone returns a virtually identical copy of this hash table. This does // a shallow copy - the Objects in the table aren't cloned, only the references // to those Objects. public virtual Object Clone() - { + { bucket[] lbuckets = buckets; - Hashtable ht = new Hashtable(count,_keycomparer); + Hashtable ht = new Hashtable(count, _keycomparer); ht.version = version; ht.loadFactor = loadFactor; ht.count = 0; int bucket = lbuckets.Length; - while (bucket > 0) { + while (bucket > 0) + { bucket--; Object keyv = lbuckets[bucket].key; - if ((keyv!= null) && (keyv != lbuckets)) { + if ((keyv != null) && (keyv != lbuckets)) + { ht[keyv] = lbuckets[bucket].val; } } return ht; } - + // Checks if this hashtable contains the given key. - public virtual bool Contains(Object key) { + public virtual bool Contains(Object key) + { return ContainsKey(key); } - + // Checks if this hashtable contains an entry with the given key. This is // an O(1) operation. // - public virtual bool ContainsKey(Object key) { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + public virtual bool ContainsKey(Object key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } Contract.EndContractBlock(); @@ -334,68 +352,76 @@ namespace System.Collections { // Take a snapshot of buckets, in case another thread resizes table bucket[] lbuckets = buckets; uint hashcode = InitHash(key, lbuckets.Length, out seed, out incr); - int ntry = 0; - + int ntry = 0; + bucket b; - int bucketNumber = (int) (seed % (uint)lbuckets.Length); - do { + int bucketNumber = (int)(seed % (uint)lbuckets.Length); + do + { b = lbuckets[bucketNumber]; - if (b.key == null) { + if (b.key == null) + { return false; } - if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && - KeyEquals (b.key, key)) + if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && + KeyEquals(b.key, key)) return true; - bucketNumber = (int) (((long)bucketNumber + incr)% (uint)lbuckets.Length); + bucketNumber = (int)(((long)bucketNumber + incr) % (uint)lbuckets.Length); } while (b.hash_coll < 0 && ++ntry < lbuckets.Length); return false; } - + // Copies the keys of this hashtable to a given array starting at a given // index. This method is used by the implementation of the CopyTo method in // the KeyCollection class. - private void CopyKeys(Array array, int arrayIndex) { + private void CopyKeys(Array array, int arrayIndex) + { Contract.Requires(array != null); Contract.Requires(array.Rank == 1); bucket[] lbuckets = buckets; - for (int i = lbuckets.Length; --i >= 0;) { + for (int i = lbuckets.Length; --i >= 0;) + { Object keyv = lbuckets[i].key; - if ((keyv != null) && (keyv != buckets)){ + if ((keyv != null) && (keyv != buckets)) + { array.SetValue(keyv, arrayIndex++); } - } + } } // Copies the keys of this hashtable to a given array starting at a given // index. This method is used by the implementation of the CopyTo method in // the KeyCollection class. - private void CopyEntries(Array array, int arrayIndex) { + private void CopyEntries(Array array, int arrayIndex) + { Contract.Requires(array != null); Contract.Requires(array.Rank == 1); bucket[] lbuckets = buckets; - for (int i = lbuckets.Length; --i >= 0;) { + for (int i = lbuckets.Length; --i >= 0;) + { Object keyv = lbuckets[i].key; - if ((keyv != null) && (keyv != buckets)){ - DictionaryEntry entry = new DictionaryEntry(keyv,lbuckets[i].val); + if ((keyv != null) && (keyv != buckets)) + { + DictionaryEntry entry = new DictionaryEntry(keyv, lbuckets[i].val); array.SetValue(entry, arrayIndex++); } } } - + // Copies the values in this hash table to an array at // a given index. Note that this only copies values, and not keys. public virtual void CopyTo(Array array, int arrayIndex) { if (array == null) - throw new ArgumentNullException(nameof(array), Environment.GetResourceString("ArgumentNull_Array")); + throw new ArgumentNullException(nameof(array), SR.ArgumentNull_Array); if (array.Rank != 1) - throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported")); - if (arrayIndex < 0) - throw new ArgumentOutOfRangeException(nameof(arrayIndex), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentException(SR.Arg_RankMultiDimNotSupported); + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException(nameof(arrayIndex), SR.ArgumentOutOfRange_NeedNonNegNum); if (array.Length - arrayIndex < Count) - throw new ArgumentException(Environment.GetResourceString("Arg_ArrayPlusOffTooSmall")); + throw new ArgumentException(SR.Arg_ArrayPlusOffTooSmall); Contract.EndContractBlock(); CopyEntries(array, arrayIndex); } @@ -404,40 +430,46 @@ namespace System.Collections { // Copies the values of this hashtable to a given array starting at a given // index. This method is used by the implementation of the CopyTo method in // the ValueCollection class. - private void CopyValues(Array array, int arrayIndex) { + private void CopyValues(Array array, int arrayIndex) + { Contract.Requires(array != null); Contract.Requires(array.Rank == 1); bucket[] lbuckets = buckets; - for (int i = lbuckets.Length; --i >= 0;) { + for (int i = lbuckets.Length; --i >= 0;) + { Object keyv = lbuckets[i].key; - if ((keyv != null) && (keyv != buckets)){ + if ((keyv != null) && (keyv != buckets)) + { array.SetValue(lbuckets[i].val, arrayIndex++); } } } - + // Returns the value associated with the given key. If an entry with the // given key is not found, the returned value is null. // - public virtual Object this[Object key] { - get { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + public virtual Object this[Object key] + { + get + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } Contract.EndContractBlock(); uint seed; uint incr; - + // Take a snapshot of buckets, in case another thread does a resize bucket[] lbuckets = buckets; uint hashcode = InitHash(key, lbuckets.Length, out seed, out incr); - int ntry = 0; - + int ntry = 0; + bucket b; - int bucketNumber = (int) (seed % (uint)lbuckets.Length); + int bucketNumber = (int)(seed % (uint)lbuckets.Length); do { int currentversion; @@ -459,35 +491,39 @@ namespace System.Collections { // we will see the 'isWriterProgress' flag to be true or 'version' is changed in the reader. // int spinCount = 0; - do { + do + { // this is violate read, following memory accesses can not be moved ahead of it. currentversion = version; - b = lbuckets[bucketNumber]; + b = lbuckets[bucketNumber]; // The contention between reader and writer shouldn't happen frequently. // But just in case this will burn CPU, yield the control of CPU if we spinned a few times. // 8 is just a random number I pick. - if( (++spinCount) % 8 == 0 ) { + if ((++spinCount) % 8 == 0) + { Thread.Sleep(1); // 1 means we are yeilding control to all threads, including low-priority ones. } - } while ( isWriterInProgress || (currentversion != version) ); + } while (isWriterInProgress || (currentversion != version)); - if (b.key == null) { + if (b.key == null) + { return null; } - if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && - KeyEquals (b.key, key)) + if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && + KeyEquals(b.key, key)) return b.val; - bucketNumber = (int) (((long)bucketNumber + incr)% (uint)lbuckets.Length); + bucketNumber = (int)(((long)bucketNumber + incr) % (uint)lbuckets.Length); } while (b.hash_coll < 0 && ++ntry < lbuckets.Length); return null; } - set { + set + { Insert(key, value, false); } } - + // Increases the bucket count of this hashtable. This method is called from // the Insert method when the actual load factor of the hashtable reaches // the upper limit specified when the hashtable was constructed. The number @@ -495,27 +531,30 @@ namespace System.Collections { // that is larger than twice the current number of buckets, and the entries // in the hashtable are redistributed into the new buckets using the cached // hashcodes. - private void expand() { + private void expand() + { int rawsize = HashHelpers.ExpandPrime(buckets.Length); rehash(rawsize, false); } // We occationally need to rehash the table to clean up the collision bits. - private void rehash() { - rehash( buckets.Length, false ); + private void rehash() + { + rehash(buckets.Length, false); } - private void UpdateVersion() { + private void UpdateVersion() + { // Version might become negative when version is Int32.MaxValue, but the oddity will be still be correct. // So we don't need to special case this. version++; } - private void rehash( int newsize, bool forceNewHashCode ) { - + private void rehash(int newsize, bool forceNewHashCode) + { // reset occupancy - occupancy=0; - + occupancy = 0; + // Don't replace any internal state until we've finished adding to the // new bucket[]. This serves two purposes: // 1) Allow concurrent readers to see valid hashtable contents @@ -523,12 +562,14 @@ namespace System.Collections { // 2) Protect against an OutOfMemoryException while allocating this // new bucket[]. bucket[] newBuckets = new bucket[newsize]; - + // rehash table into new buckets int nb; - for (nb = 0; nb < buckets.Length; nb++){ + for (nb = 0; nb < buckets.Length; nb++) + { bucket oldb = buckets[nb]; - if ((oldb.key != null) && (oldb.key != buckets)) { + if ((oldb.key != null) && (oldb.key != buckets)) + { int hashcode = ((forceNewHashCode ? GetHash(oldb.key) : oldb.hash_coll) & 0x7FFFFFFF); putEntry(newBuckets, oldb.key, oldb.val, hashcode); } @@ -551,7 +592,8 @@ namespace System.Collections { // in progress, the MoveNext and Current methods of the // enumerator will throw an exception. // - IEnumerator IEnumerable.GetEnumerator() { + IEnumerator IEnumerable.GetEnumerator() + { return new HashtableEnumerator(this, HashtableEnumerator.DictEntry); } @@ -560,10 +602,11 @@ namespace System.Collections { // in progress, the MoveNext and Current methods of the // enumerator will throw an exception. // - public virtual IDictionaryEnumerator GetEnumerator() { + public virtual IDictionaryEnumerator GetEnumerator() + { return new HashtableEnumerator(this, HashtableEnumerator.DictEntry); } - + // Internal method to get the hash code for an Object. This will call // GetHashCode() on each object if you haven't provided an IHashCodeProvider // instance. Otherwise, it calls hcp.GetHashCode(obj). @@ -575,16 +618,19 @@ namespace System.Collections { } // Is this Hashtable read-only? - public virtual bool IsReadOnly { + public virtual bool IsReadOnly + { get { return false; } } - public virtual bool IsFixedSize { + public virtual bool IsFixedSize + { get { return false; } } // Is this Hashtable synchronized? See SyncRoot property - public virtual bool IsSynchronized { + public virtual bool IsSynchronized + { get { return false; } } @@ -595,11 +641,12 @@ namespace System.Collections { protected virtual bool KeyEquals(Object item, Object key) { Debug.Assert(key != null, "key can't be null here!"); - if( Object.ReferenceEquals(buckets, item)) { + if (Object.ReferenceEquals(buckets, item)) + { return false; } - if (Object.ReferenceEquals(item,key)) + if (Object.ReferenceEquals(item, key)) return true; if (_keycomparer != null) @@ -616,13 +663,15 @@ namespace System.Collections { // to the hash table are reflected in this collection. It is not // a static copy of all the keys in the hash table. // - public virtual ICollection Keys { - get { + public virtual ICollection Keys + { + get + { if (keys == null) keys = new KeyCollection(this); - return keys; + return keys; } } - + // Returns a collection representing the values of this hashtable. The // order in which the returned collection represents the values is // unspecified, but it is guaranteed to be the same order in which a @@ -633,39 +682,45 @@ namespace System.Collections { // to the hash table are reflected in this collection. It is not // a static copy of all the keys in the hash table. // - public virtual ICollection Values { - get { + public virtual ICollection Values + { + get + { if (values == null) values = new ValueCollection(this); - return values; + return values; } } - + // Inserts an entry into this hashtable. This method is called from the Set // and Add methods. If the add parameter is true and the given key already // exists in the hashtable, an exception is thrown. - private void Insert (Object key, Object nvalue, bool add) { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + private void Insert(Object key, Object nvalue, bool add) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } Contract.EndContractBlock(); - if (count >= loadsize) { + if (count >= loadsize) + { expand(); } - else if(occupancy > loadsize && count > 100) { + else if (occupancy > loadsize && count > 100) + { rehash(); } - + uint seed; uint incr; // Assume we only have one thread writing concurrently. Modify // buckets to contain new data, as long as we insert in the right order. uint hashcode = InitHash(key, buckets.Length, out seed, out incr); - int ntry = 0; + int ntry = 0; int emptySlotNumber = -1; // We use the empty slot number to cache the first empty slot. We chose to reuse slots // create by remove that have the collision bit set over using up new slots. - int bucketNumber = (int) (seed % (uint)buckets.Length); - do { - + int bucketNumber = (int)(seed % (uint)buckets.Length); + do + { // Set emptySlot number to current bucket if it is the first available bucket that we have seen // that once contained an entry and also has had a collision. // We need to search this entire collision chain because we have to ensure that there are no @@ -676,9 +731,9 @@ namespace System.Collections { // Insert the key/value pair into this bucket if this bucket is empty and has never contained an entry // OR // This bucket once contained an entry but there has never been a collision - if ((buckets[bucketNumber].key == null) || - (buckets[bucketNumber].key == buckets && ((buckets[bucketNumber].hash_coll & unchecked(0x80000000))==0))) { - + if ((buckets[bucketNumber].key == null) || + (buckets[bucketNumber].key == buckets && ((buckets[bucketNumber].hash_coll & unchecked(0x80000000)) == 0))) + { // If we have found an available bucket that has never had a collision, but we've seen an available // bucket in the past that has the collision bit set, use the previous bucket instead if (emptySlotNumber != -1) // Reuse slot @@ -688,11 +743,11 @@ namespace System.Collections { // code until the value & key are set appropriately. isWriterInProgress = true; buckets[bucketNumber].val = nvalue; - buckets[bucketNumber].key = key; - buckets[bucketNumber].hash_coll |= (int) hashcode; + buckets[bucketNumber].key = key; + buckets[bucketNumber].hash_coll |= (int)hashcode; count++; UpdateVersion(); - isWriterInProgress = false; + isWriterInProgress = false; return; } @@ -700,29 +755,33 @@ namespace System.Collections { // The current bucket is in use // OR // it is available, but has had the collision bit set and we have already found an available bucket - if (((buckets[bucketNumber].hash_coll & 0x7FFFFFFF) == hashcode) && - KeyEquals (buckets[bucketNumber].key, key)) { - if (add) { - throw new ArgumentException(Environment.GetResourceString("Argument_AddingDuplicate__", buckets[bucketNumber].key, key)); + if (((buckets[bucketNumber].hash_coll & 0x7FFFFFFF) == hashcode) && + KeyEquals(buckets[bucketNumber].key, key)) + { + if (add) + { + throw new ArgumentException(SR.Format(SR.Argument_AddingDuplicate__, buckets[bucketNumber].key, key)); } isWriterInProgress = true; buckets[bucketNumber].val = nvalue; UpdateVersion(); - isWriterInProgress = false; + isWriterInProgress = false; return; } // The current bucket is full, and we have therefore collided. We need to set the collision bit // UNLESS // we have remembered an available slot previously. - if (emptySlotNumber == -1) {// We don't need to set the collision bit here since we already have an empty slot - if( buckets[bucketNumber].hash_coll >= 0 ) { + if (emptySlotNumber == -1) + {// We don't need to set the collision bit here since we already have an empty slot + if (buckets[bucketNumber].hash_coll >= 0) + { buckets[bucketNumber].hash_coll |= unchecked((int)0x80000000); occupancy++; } } - bucketNumber = (int) (((long)bucketNumber + incr)% (uint)buckets.Length); + bucketNumber = (int)(((long)bucketNumber + incr) % (uint)buckets.Length); } while (++ntry < buckets.Length); // This code is here if and only if there were no buckets without a collision bit set in the entire table @@ -732,11 +791,11 @@ namespace System.Collections { // code until the value & key are set appropriately. isWriterInProgress = true; buckets[emptySlotNumber].val = nvalue; - buckets[emptySlotNumber].key = key; - buckets[emptySlotNumber].hash_coll |= (int) hashcode; + buckets[emptySlotNumber].key = key; + buckets[emptySlotNumber].hash_coll |= (int)hashcode; count++; - UpdateVersion(); - isWriterInProgress = false; + UpdateVersion(); + isWriterInProgress = false; return; } @@ -745,40 +804,44 @@ namespace System.Collections { // Then verify that our double hash function (h2, described at top of file) // meets the requirements described above. You should never see this assert. Debug.Assert(false, "hash table insert failed! Load factor too high, or our double hashing function is incorrect."); - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HashInsertFailed")); + throw new InvalidOperationException(SR.InvalidOperation_HashInsertFailed); } - - private void putEntry (bucket[] newBuckets, Object key, Object nvalue, int hashcode) + + private void putEntry(bucket[] newBuckets, Object key, Object nvalue, int hashcode) { Debug.Assert(hashcode >= 0, "hashcode >= 0"); // make sure collision bit (sign bit) wasn't set. - uint seed = (uint) hashcode; + uint seed = (uint)hashcode; uint incr = (uint)(1 + ((seed * HashPrime) % ((uint)newBuckets.Length - 1))); - int bucketNumber = (int) (seed % (uint)newBuckets.Length); - do { - - if ((newBuckets[bucketNumber].key == null) || (newBuckets[bucketNumber].key == buckets)) { + int bucketNumber = (int)(seed % (uint)newBuckets.Length); + do + { + if ((newBuckets[bucketNumber].key == null) || (newBuckets[bucketNumber].key == buckets)) + { newBuckets[bucketNumber].val = nvalue; newBuckets[bucketNumber].key = key; newBuckets[bucketNumber].hash_coll |= hashcode; return; } - - if( newBuckets[bucketNumber].hash_coll >= 0 ) { - newBuckets[bucketNumber].hash_coll |= unchecked((int)0x80000000); + + if (newBuckets[bucketNumber].hash_coll >= 0) + { + newBuckets[bucketNumber].hash_coll |= unchecked((int)0x80000000); occupancy++; } - bucketNumber = (int) (((long)bucketNumber + incr)% (uint)newBuckets.Length); + bucketNumber = (int)(((long)bucketNumber + incr) % (uint)newBuckets.Length); } while (true); } - + // Removes an entry from this hashtable. If an entry with the specified // key exists in the hashtable, it is removed. An ArgumentException is // thrown if the key is null. // - public virtual void Remove(Object key) { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + public virtual void Remove(Object key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } Contract.EndContractBlock(); Debug.Assert(!isWriterInProgress, "Race condition detected in usages of Hashtable - multiple threads appear to be writing to a Hashtable instance simultaneously! Don't do that - use Hashtable.Synchronized."); @@ -788,124 +851,135 @@ namespace System.Collections { // Assuming only one concurrent writer, write directly into buckets. uint hashcode = InitHash(key, buckets.Length, out seed, out incr); int ntry = 0; - + bucket b; - int bn = (int) (seed % (uint)buckets.Length); // bucketNumber - do { + int bn = (int)(seed % (uint)buckets.Length); // bucketNumber + do + { b = buckets[bn]; - if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && - KeyEquals (b.key, key)) { + if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && + KeyEquals(b.key, key)) + { isWriterInProgress = true; // Clear hash_coll field, then key, then value buckets[bn].hash_coll &= unchecked((int)0x80000000); - if (buckets[bn].hash_coll != 0) { + if (buckets[bn].hash_coll != 0) + { buckets[bn].key = buckets; - } - else { + } + else + { buckets[bn].key = null; } buckets[bn].val = null; // Free object references sooner & simplify ContainsValue. count--; UpdateVersion(); - isWriterInProgress = false; + isWriterInProgress = false; return; } - bn = (int) (((long)bn + incr)% (uint)buckets.Length); + bn = (int)(((long)bn + incr) % (uint)buckets.Length); } while (b.hash_coll < 0 && ++ntry < buckets.Length); - //throw new ArgumentException(Environment.GetResourceString("Arg_RemoveArgNotFound")); + //throw new ArgumentException(SR.Arg_RemoveArgNotFound); } - + // Returns the object to synchronize on for this hash table. - public virtual Object SyncRoot { - get { - if( _syncRoot == null) { - System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); + public virtual Object SyncRoot + { + get + { + if (_syncRoot == null) + { + System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); } - return _syncRoot; + return _syncRoot; } } - + // Returns the number of associations in this hashtable. // - public virtual int Count { + public virtual int Count + { get { return count; } } - + // Returns a thread-safe wrapper for a Hashtable. // - public static Hashtable Synchronized(Hashtable table) { - if (table==null) + public static Hashtable Synchronized(Hashtable table) + { + if (table == null) throw new ArgumentNullException(nameof(table)); Contract.EndContractBlock(); return new SyncHashtable(table); } - + // // The ISerializable Implementation // - public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { - if (info==null) { + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { throw new ArgumentNullException(nameof(info)); } Contract.EndContractBlock(); // This is imperfect - it only works well if all other writes are // also using our synchronized wrapper. But it's still a good idea. - lock (SyncRoot) { + lock (SyncRoot) + { // This method hasn't been fully tweaked to be safe for a concurrent writer. int oldVersion = version; - info.AddValue(LoadFactorName, loadFactor); - info.AddValue(VersionName, version); - - // - // We need to maintain serialization compatibility with Everett and RTM. - // If the comparer is null or a compatible comparer, serialize Hashtable - // in a format that can be deserialized on Everett and RTM. - // - // Also, if the Hashtable is using randomized hashing, serialize the old - // view of the _keycomparer so perevious frameworks don't see the new types + info.AddValue(LoadFactorName, loadFactor); + info.AddValue(VersionName, version); + + // + // We need to maintain serialization compatibility with Everett and RTM. + // If the comparer is null or a compatible comparer, serialize Hashtable + // in a format that can be deserialized on Everett and RTM. + // #pragma warning disable 618 -#if FEATURE_RANDOMIZED_STRING_HASHING - IEqualityComparer keyComparerForSerilization = (IEqualityComparer) HashHelpers.GetEqualityComparerForSerialization(_keycomparer); -#else - IEqualityComparer keyComparerForSerilization = _keycomparer; -#endif + IEqualityComparer keyComparerForSerilization = _keycomparer; - if( keyComparerForSerilization == null) { - info.AddValue(ComparerName, null,typeof(IComparer)); - info.AddValue(HashCodeProviderName, null, typeof(IHashCodeProvider)); - } - else if(keyComparerForSerilization is CompatibleComparer) { - CompatibleComparer c = keyComparerForSerilization as CompatibleComparer; - info.AddValue(ComparerName, c.Comparer, typeof(IComparer)); - info.AddValue(HashCodeProviderName, c.HashCodeProvider, typeof(IHashCodeProvider)); - } - else { - info.AddValue(KeyComparerName, keyComparerForSerilization, typeof(IEqualityComparer)); - } + if (keyComparerForSerilization == null) + { + info.AddValue(ComparerName, null, typeof(IComparer)); + info.AddValue(HashCodeProviderName, null, typeof(IHashCodeProvider)); + } + else if (keyComparerForSerilization is CompatibleComparer) + { + CompatibleComparer c = keyComparerForSerilization as CompatibleComparer; + info.AddValue(ComparerName, c.Comparer, typeof(IComparer)); + info.AddValue(HashCodeProviderName, c.HashCodeProvider, typeof(IHashCodeProvider)); + } + else + { + info.AddValue(KeyComparerName, keyComparerForSerilization, typeof(IEqualityComparer)); + } #pragma warning restore 618 - info.AddValue(HashSizeName, buckets.Length); //This is the length of the bucket array. - Object [] serKeys = new Object[count]; - Object [] serValues = new Object[count]; - CopyKeys(serKeys, 0); - CopyValues(serValues,0); - info.AddValue(KeysName, serKeys, typeof(Object[])); - info.AddValue(ValuesName, serValues, typeof(Object[])); + info.AddValue(HashSizeName, buckets.Length); //This is the length of the bucket array. + Object[] serKeys = new Object[count]; + Object[] serValues = new Object[count]; + CopyKeys(serKeys, 0); + CopyValues(serValues, 0); + info.AddValue(KeysName, serKeys, typeof(Object[])); + info.AddValue(ValuesName, serValues, typeof(Object[])); // Explicitly check to see if anyone changed the Hashtable while we // were serializing it. That's a race condition in their code. if (version != oldVersion) - throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumFailedVersion)); - } + throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumFailedVersion)); + } } - + // // DeserializationEvent Listener // - public virtual void OnDeserialization(Object sender) { - if (buckets!=null) { + public virtual void OnDeserialization(Object sender) + { + if (buckets != null) + { // Somebody had a dependency on this hashtable and fixed us up before the ObjectManager got to it. return; } @@ -913,8 +987,9 @@ namespace System.Collections { SerializationInfo siInfo; HashHelpers.SerializationInfoTable.TryGetValue(this, out siInfo); - if (siInfo==null) { - throw new SerializationException(Environment.GetResourceString("Serialization_InvalidOnDeser")); + if (siInfo == null) + { + throw new SerializationException(SR.Serialization_InvalidOnDeser); } int hashsize = 0; @@ -924,14 +999,14 @@ namespace System.Collections { IHashCodeProvider hcp = null; #pragma warning restore 618 - Object [] serKeys = null; - Object [] serValues = null; + Object[] serKeys = null; + Object[] serValues = null; SerializationInfoEnumerator enumerator = siInfo.GetEnumerator(); - while( enumerator.MoveNext()) + while (enumerator.MoveNext()) { - switch( enumerator.Name) + switch (enumerator.Name) { case LoadFactorName: loadFactor = siInfo.GetSingle(LoadFactorName); @@ -939,7 +1014,7 @@ namespace System.Collections { case HashSizeName: hashsize = siInfo.GetInt32(HashSizeName); break; - case KeyComparerName: + case KeyComparerName: _keycomparer = (IEqualityComparer)siInfo.GetValue(KeyComparerName, typeof(IEqualityComparer)); break; case ComparerName: @@ -959,129 +1034,148 @@ namespace System.Collections { } } - loadsize = (int)(loadFactor*hashsize); + loadsize = (int)(loadFactor * hashsize); // V1 object doesn't has _keycomparer field. - if ( (_keycomparer == null) && ( (c != null) || (hcp != null) ) ){ - _keycomparer = new CompatibleComparer(c,hcp); + if ((_keycomparer == null) && ((c != null) || (hcp != null))) + { + _keycomparer = new CompatibleComparer(c, hcp); } buckets = new bucket[hashsize]; - - if (serKeys==null) { - throw new SerializationException(Environment.GetResourceString("Serialization_MissingKeys")); + + if (serKeys == null) + { + throw new SerializationException(SR.Serialization_MissingKeys); } - if (serValues==null) { - throw new SerializationException(Environment.GetResourceString("Serialization_MissingValues")); + if (serValues == null) + { + throw new SerializationException(SR.Serialization_MissingValues); } - if (serKeys.Length!=serValues.Length) { - throw new SerializationException(Environment.GetResourceString("Serialization_KeyValueDifferentSizes")); + if (serKeys.Length != serValues.Length) + { + throw new SerializationException(SR.Serialization_KeyValueDifferentSizes); } - for (int i=0; i<serKeys.Length; i++) { - if (serKeys[i]==null) { - throw new SerializationException(Environment.GetResourceString("Serialization_NullKey")); + for (int i = 0; i < serKeys.Length; i++) + { + if (serKeys[i] == null) + { + throw new SerializationException(SR.Serialization_NullKey); } Insert(serKeys[i], serValues[i], true); } - + version = siInfo.GetInt32(VersionName); - + HashHelpers.SerializationInfoTable.Remove(this); } - - + + // Implements a Collection for the keys of a hashtable. An instance of this // class is created by the GetKeys method of a hashtable. [Serializable] private class KeyCollection : ICollection { private Hashtable _hashtable; - - internal KeyCollection(Hashtable hashtable) { + + internal KeyCollection(Hashtable hashtable) + { _hashtable = hashtable; } - - public virtual void CopyTo(Array array, int arrayIndex) { - if (array==null) + + public virtual void CopyTo(Array array, int arrayIndex) + { + if (array == null) throw new ArgumentNullException(nameof(array)); if (array.Rank != 1) - throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported")); - if (arrayIndex < 0) - throw new ArgumentOutOfRangeException(nameof(arrayIndex), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentException(SR.Arg_RankMultiDimNotSupported); + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException(nameof(arrayIndex), SR.ArgumentOutOfRange_NeedNonNegNum); Contract.EndContractBlock(); if (array.Length - arrayIndex < _hashtable.count) - throw new ArgumentException(Environment.GetResourceString("Arg_ArrayPlusOffTooSmall")); + throw new ArgumentException(SR.Arg_ArrayPlusOffTooSmall); _hashtable.CopyKeys(array, arrayIndex); } - - public virtual IEnumerator GetEnumerator() { + + public virtual IEnumerator GetEnumerator() + { return new HashtableEnumerator(_hashtable, HashtableEnumerator.Keys); } - - public virtual bool IsSynchronized { + + public virtual bool IsSynchronized + { get { return _hashtable.IsSynchronized; } } - public virtual Object SyncRoot { + public virtual Object SyncRoot + { get { return _hashtable.SyncRoot; } } - public virtual int Count { + public virtual int Count + { get { return _hashtable.count; } } } - + // Implements a Collection for the values of a hashtable. An instance of // this class is created by the GetValues method of a hashtable. [Serializable] private class ValueCollection : ICollection { private Hashtable _hashtable; - - internal ValueCollection(Hashtable hashtable) { + + internal ValueCollection(Hashtable hashtable) + { _hashtable = hashtable; } - - public virtual void CopyTo(Array array, int arrayIndex) { - if (array==null) + + public virtual void CopyTo(Array array, int arrayIndex) + { + if (array == null) throw new ArgumentNullException(nameof(array)); if (array.Rank != 1) - throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported")); - if (arrayIndex < 0) - throw new ArgumentOutOfRangeException(nameof(arrayIndex), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentException(SR.Arg_RankMultiDimNotSupported); + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException(nameof(arrayIndex), SR.ArgumentOutOfRange_NeedNonNegNum); Contract.EndContractBlock(); if (array.Length - arrayIndex < _hashtable.count) - throw new ArgumentException(Environment.GetResourceString("Arg_ArrayPlusOffTooSmall")); + throw new ArgumentException(SR.Arg_ArrayPlusOffTooSmall); _hashtable.CopyValues(array, arrayIndex); } - - public virtual IEnumerator GetEnumerator() { + + public virtual IEnumerator GetEnumerator() + { return new HashtableEnumerator(_hashtable, HashtableEnumerator.Values); } - - public virtual bool IsSynchronized { + + public virtual bool IsSynchronized + { get { return _hashtable.IsSynchronized; } } - public virtual Object SyncRoot { + public virtual Object SyncRoot + { get { return _hashtable.SyncRoot; } } - public virtual int Count { + public virtual int Count + { get { return _hashtable.count; } } } - + // Synchronized wrapper for hashtable [Serializable] private class SyncHashtable : Hashtable, IEnumerable { protected Hashtable _table; - - internal SyncHashtable(Hashtable table) : base(false) { + + internal SyncHashtable(Hashtable table) : base(false) + { _table = table; } - + /*================================GetObjectData================================= **Action: Return a serialization info containing a reference to _table. We need @@ -1093,115 +1187,148 @@ namespace System.Collections { ** context -- the StreamingContext for the current serialization (ignored) **Exceptions: ArgumentNullException if info is null. ==============================================================================*/ - public override void GetObjectData(SerializationInfo info, StreamingContext context) { - if (info==null) { + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { throw new ArgumentNullException(nameof(info)); } Contract.EndContractBlock(); // Our serialization code hasn't been fully tweaked to be safe // for a concurrent writer. - lock (_table.SyncRoot) { - info.AddValue("ParentTable", _table, typeof(Hashtable)); - } + lock (_table.SyncRoot) + { + info.AddValue("ParentTable", _table, typeof(Hashtable)); + } } - public override int Count { + public override int Count + { get { return _table.Count; } } - - public override bool IsReadOnly { + + public override bool IsReadOnly + { get { return _table.IsReadOnly; } } - public override bool IsFixedSize { + public override bool IsFixedSize + { get { return _table.IsFixedSize; } } - - public override bool IsSynchronized { + + public override bool IsSynchronized + { get { return true; } } - public override Object this[Object key] { - get { - return _table[key]; + public override Object this[Object key] + { + get + { + return _table[key]; } - set { - lock(_table.SyncRoot) { + set + { + lock (_table.SyncRoot) + { _table[key] = value; } } } - - public override Object SyncRoot { + + public override Object SyncRoot + { get { return _table.SyncRoot; } } - - public override void Add(Object key, Object value) { - lock(_table.SyncRoot) { + + public override void Add(Object key, Object value) + { + lock (_table.SyncRoot) + { _table.Add(key, value); } } - - public override void Clear() { - lock(_table.SyncRoot) { + + public override void Clear() + { + lock (_table.SyncRoot) + { _table.Clear(); } } - - public override bool Contains(Object key) { + + public override bool Contains(Object key) + { return _table.Contains(key); } - - public override bool ContainsKey(Object key) { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + + public override bool ContainsKey(Object key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } Contract.EndContractBlock(); return _table.ContainsKey(key); } - - public override void CopyTo(Array array, int arrayIndex) { - lock (_table.SyncRoot) { + + public override void CopyTo(Array array, int arrayIndex) + { + lock (_table.SyncRoot) + { _table.CopyTo(array, arrayIndex); } } - public override Object Clone() { - lock (_table.SyncRoot) { + public override Object Clone() + { + lock (_table.SyncRoot) + { return Hashtable.Synchronized((Hashtable)_table.Clone()); } } - - IEnumerator IEnumerable.GetEnumerator() { + + IEnumerator IEnumerable.GetEnumerator() + { return _table.GetEnumerator(); } - - public override IDictionaryEnumerator GetEnumerator() { + + public override IDictionaryEnumerator GetEnumerator() + { return _table.GetEnumerator(); } - - public override ICollection Keys { - get { - lock(_table.SyncRoot) { + + public override ICollection Keys + { + get + { + lock (_table.SyncRoot) + { return _table.Keys; } } } - - public override ICollection Values { - get { - lock(_table.SyncRoot) { + + public override ICollection Values + { + get + { + lock (_table.SyncRoot) + { return _table.Values; } } } - - public override void Remove(Object key) { - lock(_table.SyncRoot) { + + public override void Remove(Object key) + { + lock (_table.SyncRoot) + { _table.Remove(key); } } - + /*==============================OnDeserialization=============================== **Action: Does nothing. We have to implement this because our parent HT implements it, ** but it doesn't do anything meaningful. The real work will be done when we @@ -1210,13 +1337,13 @@ namespace System.Collections { **Arguments: None **Exceptions: None ==============================================================================*/ - public override void OnDeserialization(Object sender) { + public override void OnDeserialization(Object sender) + { return; } - } - - + + // Implements an enumerator for a hashtable. The enumerator uses the // internal version number of the hashtabke to ensure that no modifications // are made to the hashtable while an enumeration is in progress. @@ -1230,12 +1357,13 @@ namespace System.Collections { private int getObjectRetType; // What should GetObject return? private Object currentKey; private Object currentValue; - + internal const int Keys = 1; internal const int Values = 2; internal const int DictEntry = 3; - - internal HashtableEnumerator(Hashtable hashtable, int getObjRetType) { + + internal HashtableEnumerator(Hashtable hashtable, int getObjRetType) + { this.hashtable = hashtable; bucket = hashtable.buckets.Length; version = hashtable.version; @@ -1243,23 +1371,29 @@ namespace System.Collections { getObjectRetType = getObjRetType; } - public Object Clone() { + public Object Clone() + { return MemberwiseClone(); } - - public virtual Object Key { - get { - if (current == false) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted)); + + public virtual Object Key + { + get + { + if (current == false) throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumNotStarted)); return currentKey; } } - - public virtual bool MoveNext() { - if (version != hashtable.version) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumFailedVersion)); - while (bucket > 0) { + + public virtual bool MoveNext() + { + if (version != hashtable.version) throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumFailedVersion)); + while (bucket > 0) + { bucket--; Object keyv = hashtable.buckets[bucket].key; - if ((keyv!= null) && (keyv != hashtable.buckets)) { + if ((keyv != null) && (keyv != hashtable.buckets)) + { currentKey = keyv; currentValue = hashtable.buckets[bucket].val; current = true; @@ -1269,54 +1403,61 @@ namespace System.Collections { current = false; return false; } - - public virtual DictionaryEntry Entry { - get { - if (current == false) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumOpCantHappen)); + + public virtual DictionaryEntry Entry + { + get + { + if (current == false) throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumOpCantHappen)); return new DictionaryEntry(currentKey, currentValue); } } - - - public virtual Object Current { - get { - if (current == false) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumOpCantHappen)); - - if (getObjectRetType==Keys) + + + public virtual Object Current + { + get + { + if (current == false) throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumOpCantHappen)); + + if (getObjectRetType == Keys) return currentKey; - else if (getObjectRetType==Values) + else if (getObjectRetType == Values) return currentValue; - else + else return new DictionaryEntry(currentKey, currentValue); } } - - public virtual Object Value { - get { - if (current == false) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumOpCantHappen)); + + public virtual Object Value + { + get + { + if (current == false) throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumOpCantHappen)); return currentValue; } } - - public virtual void Reset() { - if (version != hashtable.version) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumFailedVersion)); + + public virtual void Reset() + { + if (version != hashtable.version) throw new InvalidOperationException(SR.GetResourceString(ResId.InvalidOperation_EnumFailedVersion)); current = false; bucket = hashtable.buckets.Length; currentKey = null; currentValue = null; } } - + // internal debug view class for hashtable - internal class HashtableDebugView { - private Hashtable hashtable; - } + internal class HashtableDebugView + { + private Hashtable hashtable; + } } [FriendAccessAllowed] internal static class HashHelpers { - #if FEATURE_RANDOMIZED_STRING_HASHING public const int HashCollisionThreshold = 100; public static bool s_UseRandomizedStringHashing = String.UseRandomizedHashing(); @@ -1344,11 +1485,11 @@ namespace System.Collections { // object until OnDeserialization is called. private static ConditionalWeakTable<object, SerializationInfo> s_SerializationInfoTable; - internal static ConditionalWeakTable<object, SerializationInfo> SerializationInfoTable - { - get - { - if(s_SerializationInfoTable == null) + internal static ConditionalWeakTable<object, SerializationInfo> SerializationInfoTable + { + get + { + if (s_SerializationInfoTable == null) { ConditionalWeakTable<object, SerializationInfo> newTable = new ConditionalWeakTable<object, SerializationInfo>(); Interlocked.CompareExchange(ref s_SerializationInfoTable, newTable, null); @@ -1356,15 +1497,14 @@ namespace System.Collections { return s_SerializationInfoTable; } - } - public static bool IsPrime(int candidate) + public static bool IsPrime(int candidate) { - if ((candidate & 1) != 0) + if ((candidate & 1) != 0) { - int limit = (int)Math.Sqrt (candidate); - for (int divisor = 3; divisor <= limit; divisor+=2) + int limit = (int)Math.Sqrt(candidate); + for (int divisor = 3; divisor <= limit; divisor += 2) { if ((candidate % divisor) == 0) return false; @@ -1374,13 +1514,13 @@ namespace System.Collections { return (candidate == 2); } - public static int GetPrime(int min) + public static int GetPrime(int min) { if (min < 0) - throw new ArgumentException(Environment.GetResourceString("Arg_HTCapacityOverflow")); + throw new ArgumentException(SR.Arg_HTCapacityOverflow); Contract.EndContractBlock(); - for (int i = 0; i < primes.Length; i++) + for (int i = 0; i < primes.Length; i++) { int prime = primes[i]; if (prime >= min) return prime; @@ -1388,7 +1528,7 @@ namespace System.Collections { //outside of our predefined table. //compute the hard way. - for (int i = (min | 1); i < Int32.MaxValue;i+=2) + for (int i = (min | 1); i < Int32.MaxValue; i += 2) { if (IsPrime(i) && ((i - 1) % Hashtable.HashPrime != 0)) return i; @@ -1405,7 +1545,7 @@ namespace System.Collections { // Note that this check works even when _items.Length overflowed thanks to the (uint) cast if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize) { - Debug.Assert( MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength"); + Debug.Assert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength"); return MaxPrimeArrayLength; } @@ -1415,29 +1555,5 @@ namespace System.Collections { // This is the maximum prime smaller than Array.MaxArrayLength public const int MaxPrimeArrayLength = 0x7FEFFFFD; - -#if FEATURE_RANDOMIZED_STRING_HASHING - - public static object GetEqualityComparerForSerialization(object comparer) - { - if(comparer == null) - { - return null; - } - - IWellKnownStringEqualityComparer cmp = comparer as IWellKnownStringEqualityComparer; - - if(cmp != null) - { - return cmp.GetEqualityComparerForSerialization(); - } - - return comparer; - } - - private const int bufferSize = 1024; - private static int currentIndex = bufferSize; - private static readonly object lockObj = new Object(); -#endif // FEATURE_RANDOMIZED_STRING_HASHING } } diff --git a/src/mscorlib/src/System/Collections/ICollection.cs b/src/mscorlib/src/System/Collections/ICollection.cs deleted file mode 100644 index 088928a0ef..0000000000 --- a/src/mscorlib/src/System/Collections/ICollection.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: ICollection -** -** -** -** -** Purpose: Base interface for all collections. -** -** -===========================================================*/ -namespace System.Collections { - using System; - using System.Diagnostics.Contracts; - - // Base interface for all collections, defining enumerators, size, and - // synchronization methods. - public interface ICollection : IEnumerable - { - // Interfaces are not serialable - // CopyTo copies a collection into an Array, starting at a particular - // index into the array. - // - void CopyTo(Array array, int index); - - // Number of items in the collections. - int Count - { get; } - - - // SyncRoot will return an Object to use for synchronization - // (thread safety). You can use this object in your code to take a - // lock on the collection, even if this collection is a wrapper around - // another collection. The intent is to tunnel through to a real - // implementation of a collection, and use one of the internal objects - // found in that code. - // - // In the absense of a static Synchronized method on a collection, - // the expected usage for SyncRoot would look like this: - // - // ICollection col = ... - // lock (col.SyncRoot) { - // // Some operation on the collection, which is now thread safe. - // // This may include multiple operations. - // } - // - // - // The system-provided collections have a static method called - // Synchronized which will create a thread-safe wrapper around the - // collection. All access to the collection that you want to be - // thread-safe should go through that wrapper collection. However, if - // you need to do multiple calls on that collection (such as retrieving - // two items, or checking the count then doing something), you should - // NOT use our thread-safe wrapper since it only takes a lock for the - // duration of a single method call. Instead, use Monitor.Enter/Exit - // or your language's equivalent to the C# lock keyword as mentioned - // above. - // - // For collections with no publically available underlying store, the - // expected implementation is to simply return the this pointer. Note - // that the this pointer may not be sufficient for collections that - // wrap other collections; those should return the underlying - // collection's SyncRoot property. - Object SyncRoot - { get; } - - // Is this collection synchronized (i.e., thread-safe)? If you want a - // thread-safe collection, you can use SyncRoot as an object to - // synchronize your collection with. If you're using one of the - // collections in System.Collections, you could call the static - // Synchronized method to get a thread-safe wrapper around the - // underlying collection. - bool IsSynchronized - { get; } - } -} diff --git a/src/mscorlib/src/System/Collections/IComparer.cs b/src/mscorlib/src/System/Collections/IComparer.cs deleted file mode 100644 index 574af1a768..0000000000 --- a/src/mscorlib/src/System/Collections/IComparer.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IComparer -** -** -** -** -** Purpose: Interface for comparing two Objects. -** -** -===========================================================*/ -namespace System.Collections { - - using System; - // The IComparer interface implements a method that compares two objects. It is - // used in conjunction with the Sort and BinarySearch methods on - // the Array and List classes. - // - // Interfaces are not serializable - public interface IComparer { - // Compares two objects. An implementation of this method must return a - // value less than zero if x is less than y, zero if x is equal to y, or a - // value greater than zero if x is greater than y. - // - int Compare(Object x, Object y); - } -} diff --git a/src/mscorlib/src/System/Collections/IDictionary.cs b/src/mscorlib/src/System/Collections/IDictionary.cs deleted file mode 100644 index 519d53ed55..0000000000 --- a/src/mscorlib/src/System/Collections/IDictionary.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IDictionary -** -** -** -** -** Purpose: Base interface for all dictionaries. -** -** -===========================================================*/ -namespace System.Collections { - using System; - using System.Diagnostics.Contracts; - - // An IDictionary is a possibly unordered set of key-value pairs. - // Keys can be any non-null object. Values can be any object. - // You can look up a value in an IDictionary via the default indexed - // property, Items. - public interface IDictionary : ICollection - { - // Interfaces are not serializable - // The Item property provides methods to read and edit entries - // in the Dictionary. - Object this[Object key] { - get; - set; - } - - // Returns a collections of the keys in this dictionary. - ICollection Keys { - get; - } - - // Returns a collections of the values in this dictionary. - ICollection Values { - get; - } - - // Returns whether this dictionary contains a particular key. - // - bool Contains(Object key); - - // Adds a key-value pair to the dictionary. - // - void Add(Object key, Object value); - - // Removes all pairs from the dictionary. - void Clear(); - - bool IsReadOnly - { get; } - - bool IsFixedSize - { get; } - - // Returns an IDictionaryEnumerator for this dictionary. - new IDictionaryEnumerator GetEnumerator(); - - // Removes a particular key from the dictionary. - // - void Remove(Object key); - } -} diff --git a/src/mscorlib/src/System/Collections/IDictionaryEnumerator.cs b/src/mscorlib/src/System/Collections/IDictionaryEnumerator.cs deleted file mode 100644 index 2f1add682c..0000000000 --- a/src/mscorlib/src/System/Collections/IDictionaryEnumerator.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IDictionaryEnumerator -** -** -** -** -** Purpose: Base interface for dictionary enumerators. -** -** -===========================================================*/ -namespace System.Collections { - // Interfaces are not serializable - - using System; - // This interface represents an enumerator that allows sequential access to the - // elements of a dictionary. Upon creation, an enumerator is conceptually - // positioned before the first element of the enumeration. The first call to the - // MoveNext method brings the first element of the enumeration into view, - // and each successive call to MoveNext brings the next element into - // view until MoveNext returns false, indicating that there are no more - // elements to enumerate. Following each call to MoveNext, the - // Key and Value methods are used to obtain the key and - // value of the element currently in view. The values returned by calls to - // Key and Value are undefined before the first call to - // MoveNext and following a call to MoveNext that returned false. - // Enumerators are typically used in while loops of the form - // - // IDictionaryEnumerator e = ...; - // while (e.MoveNext()) { - // Object key = e.Key; - // Object value = e.Value; - // ... - // } - // - // The IDictionaryEnumerator interface extends the IEnumerator - // inerface and can thus be used as a regular enumerator. The Current - // method of an IDictionaryEnumerator returns a DictionaryEntry containing - // the current key and value pair. However, the GetEntry method will - // return the same DictionaryEntry and avoids boxing the DictionaryEntry (boxing - // is somewhat expensive). - // - public interface IDictionaryEnumerator : IEnumerator - { - // Returns the key of the current element of the enumeration. The returned - // value is undefined before the first call to GetNext and following - // a call to GetNext that returned false. Multiple calls to - // GetKey with no intervening calls to GetNext will return - // the same object. - // - Object Key { - get; - } - - // Returns the value of the current element of the enumeration. The - // returned value is undefined before the first call to GetNext and - // following a call to GetNext that returned false. Multiple calls - // to GetValue with no intervening calls to GetNext will - // return the same object. - // - Object Value { - get; - } - - // GetBlock will copy dictionary values into the given Array. It will either - // fill up the array, or if there aren't enough elements, it will - // copy as much as possible into the Array. The number of elements - // copied is returned. - // - DictionaryEntry Entry { - get; - } - } -} diff --git a/src/mscorlib/src/System/Collections/IEnumerable.cs b/src/mscorlib/src/System/Collections/IEnumerable.cs deleted file mode 100644 index 1d8e71cf07..0000000000 --- a/src/mscorlib/src/System/Collections/IEnumerable.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IEnumerable -** -** -** -** -** Purpose: Interface for classes providing IEnumerators -** -** -===========================================================*/ -namespace System.Collections { - using System; - using System.Diagnostics.Contracts; - using System.Runtime.InteropServices; - - // Implement this interface if you need to support VB's foreach semantics. - // Also, COM classes that support an enumerator will also implement this interface. - [Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")] - public interface IEnumerable - { - // Interfaces are not serializable - // Returns an IEnumerator for this enumerable Object. The enumerator provides - // a simple way to access all the contents of a collection. - [Pure] - [DispId(-4)] - IEnumerator GetEnumerator(); - } -} diff --git a/src/mscorlib/src/System/Collections/IEnumerator.cs b/src/mscorlib/src/System/Collections/IEnumerator.cs deleted file mode 100644 index 4c4fc085e8..0000000000 --- a/src/mscorlib/src/System/Collections/IEnumerator.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IEnumerator -** -** -** -** -** Purpose: Base interface for all enumerators. -** -** -===========================================================*/ -namespace System.Collections { - using System; - using System.Runtime.InteropServices; - - // Base interface for all enumerators, providing a simple approach - // to iterating over a collection. - [Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")] - public interface IEnumerator - { - // Interfaces are not serializable - // Advances the enumerator to the next element of the enumeration and - // returns a boolean indicating whether an element is available. Upon - // creation, an enumerator is conceptually positioned before the first - // element of the enumeration, and the first call to MoveNext - // brings the first element of the enumeration into view. - // - bool MoveNext(); - - // Returns the current element of the enumeration. The returned value is - // undefined before the first call to MoveNext and following a - // call to MoveNext that returned false. Multiple calls to - // GetCurrent with no intervening calls to MoveNext - // will return the same object. - // - Object Current { - get; - } - - // Resets the enumerator to the beginning of the enumeration, starting over. - // The preferred behavior for Reset is to return the exact same enumeration. - // This means if you modify the underlying collection then call Reset, your - // IEnumerator will be invalid, just as it would have been if you had called - // MoveNext or Current. - // - void Reset(); - } -} diff --git a/src/mscorlib/src/System/Collections/IEqualityComparer.cs b/src/mscorlib/src/System/Collections/IEqualityComparer.cs deleted file mode 100644 index f591b11152..0000000000 --- a/src/mscorlib/src/System/Collections/IEqualityComparer.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IEqualityComparer -** -** -** -** -** Purpose: A mechanism to expose a simplified infrastructure for -** Comparing objects in collections. -** -** -===========================================================*/ -namespace System.Collections { - - using System; - // An IEqualityComparer is a mechanism to consume custom performant comparison infrastructure - // that can be consumed by some of the common collections. - public interface IEqualityComparer { - bool Equals(Object x, Object y); - int GetHashCode(Object obj); - } -} diff --git a/src/mscorlib/src/System/Collections/IHashCodeProvider.cs b/src/mscorlib/src/System/Collections/IHashCodeProvider.cs index 0ae1e3295b..fa4738ab64 100644 --- a/src/mscorlib/src/System/Collections/IHashCodeProvider.cs +++ b/src/mscorlib/src/System/Collections/IHashCodeProvider.cs @@ -13,17 +13,19 @@ ** ** ===========================================================*/ -namespace System.Collections { - - using System; + +using System; + +namespace System.Collections +{ // Provides a mechanism for a hash table user to override the default // GetHashCode() function on Objects, providing their own hash function. [Obsolete("Please use IEqualityComparer instead.")] - internal interface IHashCodeProvider + internal interface IHashCodeProvider { // Interfaces are not serializable // Returns a hash code for the given object. // - int GetHashCode (Object obj); + int GetHashCode(Object obj); } } diff --git a/src/mscorlib/src/System/Collections/IList.cs b/src/mscorlib/src/System/Collections/IList.cs deleted file mode 100644 index 8b63400852..0000000000 --- a/src/mscorlib/src/System/Collections/IList.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** Interface: IList -** -** -** -** -** Purpose: Base interface for all Lists. -** -** -===========================================================*/ -namespace System.Collections { - - using System; - using System.Diagnostics.Contracts; - - // An IList is an ordered collection of objects. The exact ordering - // is up to the implementation of the list, ranging from a sorted - // order to insertion order. - public interface IList : ICollection - { - // The Item property provides methods to read and edit entries in the List. - Object this[int index] { - get; - set; - } - - // Adds an item to the list. The exact position in the list is - // implementation-dependent, so while ArrayList may always insert - // in the last available location, a SortedList most likely would not. - // The return value is the position the new element was inserted in. - int Add(Object value); - - // Returns whether the list contains a particular item. - bool Contains(Object value); - - // Removes all items from the list. - void Clear(); - - bool IsReadOnly - { get; } - - - bool IsFixedSize - { - get; - } - - - // Returns the index of a particular item, if it is in the list. - // Returns -1 if the item isn't in the list. - int IndexOf(Object value); - - // Inserts value into the list at position index. - // index must be non-negative and less than or equal to the - // number of elements in the list. If index equals the number - // of items in the list, then value is appended to the end. - void Insert(int index, Object value); - - // Removes an item from the list. - void Remove(Object value); - - // Removes the item at position index. - void RemoveAt(int index); - } -} diff --git a/src/mscorlib/src/System/Collections/IStructuralComparable.cs b/src/mscorlib/src/System/Collections/IStructuralComparable.cs deleted file mode 100644 index 1b6f3aff7a..0000000000 --- a/src/mscorlib/src/System/Collections/IStructuralComparable.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; - -namespace System.Collections { - - public interface IStructuralComparable { - Int32 CompareTo(Object other, IComparer comparer); - } -} diff --git a/src/mscorlib/src/System/Collections/IStructuralEquatable.cs b/src/mscorlib/src/System/Collections/IStructuralEquatable.cs deleted file mode 100644 index 5a5295fc38..0000000000 --- a/src/mscorlib/src/System/Collections/IStructuralEquatable.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -namespace System.Collections { - - public interface IStructuralEquatable { - Boolean Equals(Object other, IEqualityComparer comparer); - int GetHashCode(IEqualityComparer comparer); - } -} diff --git a/src/mscorlib/src/System/Collections/ListDictionaryInternal.cs b/src/mscorlib/src/System/Collections/ListDictionaryInternal.cs index 617c33707a..3f92038d4f 100644 --- a/src/mscorlib/src/System/Collections/ListDictionaryInternal.cs +++ b/src/mscorlib/src/System/Collections/ListDictionaryInternal.cs @@ -11,55 +11,70 @@ ** ** ===========================================================*/ + using System.Diagnostics.Contracts; -namespace System.Collections { + +namespace System.Collections +{ /// This is a simple implementation of IDictionary using a singly linked list. This /// will be smaller and faster than a Hashtable if the number of elements is 10 or less. /// This should not be used if performance is important for large numbers of elements. [Serializable] - internal class ListDictionaryInternal: IDictionary { - DictionaryNode head; - int version; - int count; + internal class ListDictionaryInternal : IDictionary + { + private DictionaryNode head; + private int version; + private int count; [NonSerialized] private Object _syncRoot; - public ListDictionaryInternal() { + public ListDictionaryInternal() + { } - public Object this[Object key] { - get { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + public Object this[Object key] + { + get + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } Contract.EndContractBlock(); DictionaryNode node = head; - while (node != null) { - if ( node.key.Equals(key) ) { + while (node != null) + { + if (node.key.Equals(key)) + { return node.value; } node = node.next; } return null; } - set { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + set + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } Contract.EndContractBlock(); - + version++; DictionaryNode last = null; DictionaryNode node; - for (node = head; node != null; node = node.next) { - if( node.key.Equals(key) ) { + for (node = head; node != null; node = node.next) + { + if (node.key.Equals(key)) + { break; - } + } last = node; } - if (node != null) { + if (node != null) + { // Found it node.value = value; return; @@ -68,78 +83,100 @@ namespace System.Collections { DictionaryNode newNode = new DictionaryNode(); newNode.key = key; newNode.value = value; - if (last != null) { + if (last != null) + { last.next = newNode; } - else { + else + { head = newNode; } count++; } } - public int Count { - get { + public int Count + { + get + { return count; } - } + } - public ICollection Keys { - get { + public ICollection Keys + { + get + { return new NodeKeyValueCollection(this, true); } } - public bool IsReadOnly { - get { + public bool IsReadOnly + { + get + { return false; } } - public bool IsFixedSize { - get { + public bool IsFixedSize + { + get + { return false; } } - public bool IsSynchronized { - get { + public bool IsSynchronized + { + get + { return false; } } - public Object SyncRoot { - get { - if( _syncRoot == null) { - System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); + public Object SyncRoot + { + get + { + if (_syncRoot == null) + { + System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); } - return _syncRoot; + return _syncRoot; } } - public ICollection Values { - get { + public ICollection Values + { + get + { return new NodeKeyValueCollection(this, false); } } - public void Add(Object key, Object value) { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + public void Add(Object key, Object value) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } Contract.EndContractBlock(); - + version++; DictionaryNode last = null; DictionaryNode node; - for (node = head; node != null; node = node.next) { - if (node.key.Equals(key)) { - throw new ArgumentException(Environment.GetResourceString("Argument_AddingDuplicate__", node.key, key)); - } + for (node = head; node != null; node = node.next) + { + if (node.key.Equals(key)) + { + throw new ArgumentException(SR.Format(SR.Argument_AddingDuplicate__, node.key, key)); + } last = node; } - if (node != null) { + if (node != null) + { // Found it node.value = value; return; @@ -148,265 +185,328 @@ namespace System.Collections { DictionaryNode newNode = new DictionaryNode(); newNode.key = key; newNode.value = value; - if (last != null) { + if (last != null) + { last.next = newNode; } - else { + else + { head = newNode; } count++; } - public void Clear() { + public void Clear() + { count = 0; head = null; version++; } - public bool Contains(Object key) { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + public bool Contains(Object key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } Contract.EndContractBlock(); - for (DictionaryNode node = head; node != null; node = node.next) { - if (node.key.Equals(key)) { + for (DictionaryNode node = head; node != null; node = node.next) + { + if (node.key.Equals(key)) + { return true; } } return false; } - public void CopyTo(Array array, int index) { - if (array==null) + public void CopyTo(Array array, int index) + { + if (array == null) throw new ArgumentNullException(nameof(array)); - + if (array.Rank != 1) - throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported")); + throw new ArgumentException(SR.Arg_RankMultiDimNotSupported); if (index < 0) - throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); - if ( array.Length - index < this.Count ) - throw new ArgumentException( Environment.GetResourceString("ArgumentOutOfRange_Index"), nameof(index)); + if (array.Length - index < this.Count) + throw new ArgumentException(SR.ArgumentOutOfRange_Index, nameof(index)); Contract.EndContractBlock(); - for (DictionaryNode node = head; node != null; node = node.next) { + for (DictionaryNode node = head; node != null; node = node.next) + { array.SetValue(new DictionaryEntry(node.key, node.value), index); index++; } } - public IDictionaryEnumerator GetEnumerator() { + public IDictionaryEnumerator GetEnumerator() + { return new NodeEnumerator(this); } - IEnumerator IEnumerable.GetEnumerator() { + IEnumerator IEnumerable.GetEnumerator() + { return new NodeEnumerator(this); } - public void Remove(Object key) { - if (key == null) { - throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); + public void Remove(Object key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } Contract.EndContractBlock(); version++; DictionaryNode last = null; DictionaryNode node; - for (node = head; node != null; node = node.next) { - if (node.key.Equals(key)) { + for (node = head; node != null; node = node.next) + { + if (node.key.Equals(key)) + { break; - } + } last = node; } - if (node == null) { + if (node == null) + { return; - } - if (node == head) { + } + if (node == head) + { head = node.next; - } else { + } + else + { last.next = node.next; } count--; } - private class NodeEnumerator : IDictionaryEnumerator { - ListDictionaryInternal list; - DictionaryNode current; - int version; - bool start; + private class NodeEnumerator : IDictionaryEnumerator + { + private ListDictionaryInternal list; + private DictionaryNode current; + private int version; + private bool start; - public NodeEnumerator(ListDictionaryInternal list) { + public NodeEnumerator(ListDictionaryInternal list) + { this.list = list; version = list.version; start = true; current = null; } - public Object Current { - get { + public Object Current + { + get + { return Entry; } } - public DictionaryEntry Entry { - get { - if (current == null) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumOpCantHappen")); + public DictionaryEntry Entry + { + get + { + if (current == null) + { + throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen); } return new DictionaryEntry(current.key, current.value); } } - public Object Key { - get { - if (current == null) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumOpCantHappen")); + public Object Key + { + get + { + if (current == null) + { + throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen); } return current.key; } } - public Object Value { - get { - if (current == null) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumOpCantHappen")); + public Object Value + { + get + { + if (current == null) + { + throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen); } return current.value; } } - public bool MoveNext() { - if (version != list.version) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion")); + public bool MoveNext() + { + if (version != list.version) + { + throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion); } - if (start) { + if (start) + { current = list.head; start = false; } - else { - if( current != null ) { + else + { + if (current != null) + { current = current.next; } } return (current != null); } - public void Reset() { - if (version != list.version) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion")); + public void Reset() + { + if (version != list.version) + { + throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion); } start = true; current = null; } - } - private class NodeKeyValueCollection : ICollection { - ListDictionaryInternal list; - bool isKeys; + private class NodeKeyValueCollection : ICollection + { + private ListDictionaryInternal list; + private bool isKeys; - public NodeKeyValueCollection(ListDictionaryInternal list, bool isKeys) { + public NodeKeyValueCollection(ListDictionaryInternal list, bool isKeys) + { this.list = list; this.isKeys = isKeys; } - void ICollection.CopyTo(Array array, int index) { - if (array==null) + void ICollection.CopyTo(Array array, int index) + { + if (array == null) throw new ArgumentNullException(nameof(array)); if (array.Rank != 1) - throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported")); + throw new ArgumentException(SR.Arg_RankMultiDimNotSupported); if (index < 0) - throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); Contract.EndContractBlock(); - if (array.Length - index < list.Count) - throw new ArgumentException(Environment.GetResourceString("ArgumentOutOfRange_Index"), nameof(index)); - for (DictionaryNode node = list.head; node != null; node = node.next) { + if (array.Length - index < list.Count) + throw new ArgumentException(SR.ArgumentOutOfRange_Index, nameof(index)); + for (DictionaryNode node = list.head; node != null; node = node.next) + { array.SetValue(isKeys ? node.key : node.value, index); index++; } } - int ICollection.Count { - get { + int ICollection.Count + { + get + { int count = 0; - for (DictionaryNode node = list.head; node != null; node = node.next) { + for (DictionaryNode node = list.head; node != null; node = node.next) + { count++; } return count; } - } + } - bool ICollection.IsSynchronized { - get { + bool ICollection.IsSynchronized + { + get + { return false; } } - Object ICollection.SyncRoot { - get { + Object ICollection.SyncRoot + { + get + { return list.SyncRoot; } } - IEnumerator IEnumerable.GetEnumerator() { + IEnumerator IEnumerable.GetEnumerator() + { return new NodeKeyValueEnumerator(list, isKeys); } - private class NodeKeyValueEnumerator: IEnumerator { - ListDictionaryInternal list; - DictionaryNode current; - int version; - bool isKeys; - bool start; + private class NodeKeyValueEnumerator : IEnumerator + { + private ListDictionaryInternal list; + private DictionaryNode current; + private int version; + private bool isKeys; + private bool start; - public NodeKeyValueEnumerator(ListDictionaryInternal list, bool isKeys) { + public NodeKeyValueEnumerator(ListDictionaryInternal list, bool isKeys) + { this.list = list; this.isKeys = isKeys; - this.version = list.version; - this.start = true; - this.current = null; + version = list.version; + start = true; + current = null; } - public Object Current { - get { - if (current == null) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumOpCantHappen")); + public Object Current + { + get + { + if (current == null) + { + throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen); } return isKeys ? current.key : current.value; } } - public bool MoveNext() { - if (version != list.version) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion")); + public bool MoveNext() + { + if (version != list.version) + { + throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion); } - if (start) { + if (start) + { current = list.head; start = false; } - else { - if( current != null) { + else + { + if (current != null) + { current = current.next; } } return (current != null); } - public void Reset() { - if (version != list.version) { - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion")); + public void Reset() + { + if (version != list.version) + { + throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion); } start = true; current = null; } - } + } } [Serializable] - private class DictionaryNode { + private class DictionaryNode + { public Object key; public Object value; public DictionaryNode next; diff --git a/src/mscorlib/src/System/Collections/ObjectModel/Collection.cs b/src/mscorlib/src/System/Collections/ObjectModel/Collection.cs index b3b19fb616..d9801dfaaf 100644 --- a/src/mscorlib/src/System/Collections/ObjectModel/Collection.cs +++ b/src/mscorlib/src/System/Collections/ObjectModel/Collection.cs @@ -4,50 +4,59 @@ // +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime; + namespace System.Collections.ObjectModel { - using System; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - using System.Runtime; - [Serializable] [DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))] - [DebuggerDisplay("Count = {Count}")] - public class Collection<T>: IList<T>, IList, IReadOnlyList<T> + [DebuggerDisplay("Count = {Count}")] + public class Collection<T> : IList<T>, IList, IReadOnlyList<T> { - IList<T> items; + private IList<T> items; [NonSerialized] private Object _syncRoot; - public Collection() { + public Collection() + { items = new List<T>(); } - public Collection(IList<T> list) { - if (list == null) { + public Collection(IList<T> list) + { + if (list == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.list); } items = list; } - public int Count { + public int Count + { get { return items.Count; } } - protected IList<T> Items { + protected IList<T> Items + { get { return items; } } - public T this[int index] { + public T this[int index] + { get { return items[index]; } - set { - if( items.IsReadOnly) { + set + { + if (items.IsReadOnly) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - - if (index < 0 || index >= items.Count) { + + if (index < 0 || index >= items.Count) + { ThrowHelper.ThrowArgumentOutOfRange_IndexException(); } @@ -55,154 +64,192 @@ namespace System.Collections.ObjectModel } } - public void Add(T item) { - if( items.IsReadOnly) { + public void Add(T item) + { + if (items.IsReadOnly) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - + int index = items.Count; InsertItem(index, item); } - public void Clear() { - if( items.IsReadOnly) { + public void Clear() + { + if (items.IsReadOnly) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - + ClearItems(); } - public void CopyTo(T[] array, int index) { + public void CopyTo(T[] array, int index) + { items.CopyTo(array, index); } - public bool Contains(T item) { + public bool Contains(T item) + { return items.Contains(item); } - public IEnumerator<T> GetEnumerator() { + public IEnumerator<T> GetEnumerator() + { return items.GetEnumerator(); } - public int IndexOf(T item) { + public int IndexOf(T item) + { return items.IndexOf(item); } - public void Insert(int index, T item) { - if (items.IsReadOnly) { + public void Insert(int index, T item) + { + if (items.IsReadOnly) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - if (index < 0 || index > items.Count) { + if (index < 0 || index > items.Count) + { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_ListInsert); } InsertItem(index, item); } - public bool Remove(T item) { - if( items.IsReadOnly) { + public bool Remove(T item) + { + if (items.IsReadOnly) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - + int index = items.IndexOf(item); if (index < 0) return false; RemoveItem(index); return true; } - public void RemoveAt(int index) { - if( items.IsReadOnly) { + public void RemoveAt(int index) + { + if (items.IsReadOnly) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - if (index < 0 || index >= items.Count) { + if (index < 0 || index >= items.Count) + { ThrowHelper.ThrowArgumentOutOfRange_IndexException(); } RemoveItem(index); } - protected virtual void ClearItems() { + protected virtual void ClearItems() + { items.Clear(); } - protected virtual void InsertItem(int index, T item) { + protected virtual void InsertItem(int index, T item) + { items.Insert(index, item); } - - protected virtual void RemoveItem(int index) { + + protected virtual void RemoveItem(int index) + { items.RemoveAt(index); } - protected virtual void SetItem(int index, T item) { + protected virtual void SetItem(int index, T item) + { items[index] = item; } - - bool ICollection<T>.IsReadOnly { - get { - return items.IsReadOnly; + + bool ICollection<T>.IsReadOnly + { + get + { + return items.IsReadOnly; } } - - IEnumerator IEnumerable.GetEnumerator() { + + IEnumerator IEnumerable.GetEnumerator() + { return ((IEnumerable)items).GetEnumerator(); } - bool ICollection.IsSynchronized { + bool ICollection.IsSynchronized + { get { return false; } } - object ICollection.SyncRoot { - get { - if( _syncRoot == null) { + object ICollection.SyncRoot + { + get + { + if (_syncRoot == null) + { ICollection c = items as ICollection; - if( c != null) { + if (c != null) + { _syncRoot = c.SyncRoot; } - else { - System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); + else + { + System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); } } - return _syncRoot; + return _syncRoot; } } - void ICollection.CopyTo(Array array, int index) { - if (array == null) { + void ICollection.CopyTo(Array array, int index) + { + if (array == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - - if (array.Rank != 1) { + + if (array.Rank != 1) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); } - if( array.GetLowerBound(0) != 0 ) { + if (array.GetLowerBound(0) != 0) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound); } - - if (index < 0 ) { + + if (index < 0) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - if (array.Length - index < Count) { + if (array.Length - index < Count) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); } T[] tArray = array as T[]; - if (tArray != null) { - items.CopyTo(tArray , index); + if (tArray != null) + { + items.CopyTo(tArray, index); } - else { + else + { // // Catch the obvious case assignment will fail. // We can found all possible problems by doing the check though. // For example, if the element type of the Array is derived from T, // we can't figure out if we can successfully copy the element beforehand. // - Type targetType = array.GetType().GetElementType(); + Type targetType = array.GetType().GetElementType(); Type sourceType = typeof(T); - if(!(targetType.IsAssignableFrom(sourceType) || sourceType.IsAssignableFrom(targetType))) { + if (!(targetType.IsAssignableFrom(sourceType) || sourceType.IsAssignableFrom(targetType))) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } @@ -211,51 +258,62 @@ namespace System.Collections.ObjectModel // widening of primitive types here. // object[] objects = array as object[]; - if( objects == null) { + if (objects == null) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } int count = items.Count; - try { - for (int i = 0; i < count; i++) { + try + { + for (int i = 0; i < count; i++) + { objects[index++] = items[i]; } } - catch(ArrayTypeMismatchException) { + catch (ArrayTypeMismatchException) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } - } + } } - object IList.this[int index] { + object IList.this[int index] + { get { return items[index]; } - set { + set + { ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(value, ExceptionArgument.value); - try { - this[index] = (T)value; + try + { + this[index] = (T)value; } - catch (InvalidCastException) { - ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T)); + catch (InvalidCastException) + { + ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T)); } - } } - bool IList.IsReadOnly { - get { + bool IList.IsReadOnly + { + get + { return items.IsReadOnly; } } - bool IList.IsFixedSize { - get { + bool IList.IsFixedSize + { + get + { // There is no IList<T>.IsFixedSize, so we must assume that only // readonly collections are fixed size, if our internal item // collection does not implement IList. Note that Array implements // IList, and therefore T[] and U[] will be fixed-size. IList list = items as IList; - if(list != null) + if (list != null) { return list.IsFixedSize; } @@ -263,62 +321,77 @@ namespace System.Collections.ObjectModel } } - int IList.Add(object value) { - if( items.IsReadOnly) { + int IList.Add(object value) + { + if (items.IsReadOnly) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(value, ExceptionArgument.value); - - try { + + try + { Add((T)value); } - catch (InvalidCastException) { - ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T)); - } - + catch (InvalidCastException) + { + ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T)); + } + return this.Count - 1; } - bool IList.Contains(object value) { - if(IsCompatibleObject(value)) { - return Contains((T) value); + bool IList.Contains(object value) + { + if (IsCompatibleObject(value)) + { + return Contains((T)value); } return false; } - int IList.IndexOf(object value) { - if(IsCompatibleObject(value)) { + int IList.IndexOf(object value) + { + if (IsCompatibleObject(value)) + { return IndexOf((T)value); - } + } return -1; } - void IList.Insert(int index, object value) { - if( items.IsReadOnly) { + void IList.Insert(int index, object value) + { + if (items.IsReadOnly) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(value, ExceptionArgument.value); - - try { + + try + { Insert(index, (T)value); } - catch (InvalidCastException) { - ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T)); - } - + catch (InvalidCastException) + { + ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T)); + } } - void IList.Remove(object value) { - if( items.IsReadOnly) { + void IList.Remove(object value) + { + if (items.IsReadOnly) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - if(IsCompatibleObject(value)) { - Remove((T) value); - } + if (IsCompatibleObject(value)) + { + Remove((T)value); + } } - private static bool IsCompatibleObject(object value) { + private static bool IsCompatibleObject(object value) + { // Non-null values are fine. Only accept nulls if T is a class or Nullable<U>. // Note that default(T) is not equal to null for value types except when T is Nullable<U>. return ((value is T) || (value == null && default(T) == null)); diff --git a/src/mscorlib/src/System/Collections/ObjectModel/KeyedCollection.cs b/src/mscorlib/src/System/Collections/ObjectModel/KeyedCollection.cs deleted file mode 100644 index 3fe7716203..0000000000 --- a/src/mscorlib/src/System/Collections/ObjectModel/KeyedCollection.cs +++ /dev/null @@ -1,244 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// - -namespace System.Collections.ObjectModel -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Diagnostics.Contracts; - - [Serializable] - [DebuggerTypeProxy(typeof(Mscorlib_KeyedCollectionDebugView<,>))] - [DebuggerDisplay("Count = {Count}")] - public abstract class KeyedCollection<TKey,TItem>: Collection<TItem> - { - const int defaultThreshold = 0; - - IEqualityComparer<TKey> comparer; - Dictionary<TKey,TItem> dict; - int keyCount; - int threshold; - - protected KeyedCollection(): this(null, defaultThreshold) {} - - protected KeyedCollection(IEqualityComparer<TKey> comparer): this(comparer, defaultThreshold) {} - - - protected KeyedCollection(IEqualityComparer<TKey> comparer, int dictionaryCreationThreshold) - : base(new List<TItem>()) { // Be explicit about the use of List<T> so we can foreach over - // Items internally without enumerator allocations. - if (comparer == null) { - comparer = EqualityComparer<TKey>.Default; - } - - if (dictionaryCreationThreshold == -1) { - dictionaryCreationThreshold = int.MaxValue; - } - - if( dictionaryCreationThreshold < -1) { - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.dictionaryCreationThreshold, ExceptionResource.ArgumentOutOfRange_InvalidThreshold); - } - - this.comparer = comparer; - this.threshold = dictionaryCreationThreshold; - } - - /// <summary> - /// Enables the use of foreach internally without allocations using <see cref="List{T}"/>'s struct enumerator. - /// </summary> - new private List<TItem> Items { - get { - Debug.Assert(base.Items is List<TItem>); - - return (List<TItem>)base.Items; - } - } - - public IEqualityComparer<TKey> Comparer { - get { - return comparer; - } - } - - public TItem this[TKey key] { - get { - if( key == null) { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); - } - - if (dict != null) { - return dict[key]; - } - - foreach (TItem item in Items) { - if (comparer.Equals(GetKeyForItem(item), key)) return item; - } - - ThrowHelper.ThrowKeyNotFoundException(); - return default(TItem); - } - } - - public bool Contains(TKey key) { - if( key == null) { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); - } - - if (dict != null) { - return dict.ContainsKey(key); - } - - foreach (TItem item in Items) { - if (comparer.Equals(GetKeyForItem(item), key)) return true; - } - return false; - } - - private bool ContainsItem(TItem item) { - TKey key; - if( (dict == null) || ((key = GetKeyForItem(item)) == null)) { - return Items.Contains(item); - } - - TItem itemInDict; - bool exist = dict.TryGetValue(key, out itemInDict); - if( exist) { - return EqualityComparer<TItem>.Default.Equals(itemInDict, item); - } - return false; - } - - public bool Remove(TKey key) { - if( key == null) { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); - } - - if (dict != null) { - if (dict.ContainsKey(key)) { - return Remove(dict[key]); - } - - return false; - } - - for (int i = 0; i < Items.Count; i++) { - if (comparer.Equals(GetKeyForItem(Items[i]), key)) { - RemoveItem(i); - return true; - } - } - return false; - } - - protected IDictionary<TKey,TItem> Dictionary { - get { return dict; } - } - - protected void ChangeItemKey(TItem item, TKey newKey) { - // check if the item exists in the collection - if( !ContainsItem(item)) { - ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_ItemNotExist); - } - - TKey oldKey = GetKeyForItem(item); - if (!comparer.Equals(oldKey, newKey)) { - if (newKey != null) { - AddKey(newKey, item); - } - - if (oldKey != null) { - RemoveKey(oldKey); - } - } - } - - protected override void ClearItems() { - base.ClearItems(); - if (dict != null) { - dict.Clear(); - } - - keyCount = 0; - } - - protected abstract TKey GetKeyForItem(TItem item); - - protected override void InsertItem(int index, TItem item) { - TKey key = GetKeyForItem(item); - if (key != null) { - AddKey(key, item); - } - base.InsertItem(index, item); - } - - protected override void RemoveItem(int index) { - TKey key = GetKeyForItem(Items[index]); - if (key != null) { - RemoveKey(key); - } - base.RemoveItem(index); - } - - protected override void SetItem(int index, TItem item) { - TKey newKey = GetKeyForItem(item); - TKey oldKey = GetKeyForItem(Items[index]); - - if (comparer.Equals(oldKey, newKey)) { - if (newKey != null && dict != null) { - dict[newKey] = item; - } - } - else { - if (newKey != null) { - AddKey(newKey, item); - } - - if (oldKey != null) { - RemoveKey(oldKey); - } - } - base.SetItem(index, item); - } - - private void AddKey(TKey key, TItem item) { - if (dict != null) { - dict.Add(key, item); - } - else if (keyCount == threshold) { - CreateDictionary(); - dict.Add(key, item); - } - else { - if (Contains(key)) { - ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate); - } - - keyCount++; - } - } - - private void CreateDictionary() { - dict = new Dictionary<TKey,TItem>(comparer); - foreach (TItem item in Items) { - TKey key = GetKeyForItem(item); - if (key != null) { - dict.Add(key, item); - } - } - } - - private void RemoveKey(TKey key) { - Debug.Assert(key != null, "key shouldn't be null!"); - if (dict != null) { - dict.Remove(key); - } - else { - keyCount--; - } - } - } -} diff --git a/src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyCollection.cs b/src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyCollection.cs index 10c48cf76d..b484879c27 100644 --- a/src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyCollection.cs +++ b/src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyCollection.cs @@ -4,150 +4,184 @@ // +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime; + namespace System.Collections.ObjectModel { - using System; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - using System.Runtime; - [Serializable] [DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))] - [DebuggerDisplay("Count = {Count}")] - public class ReadOnlyCollection<T>: IList<T>, IList, IReadOnlyList<T> + [DebuggerDisplay("Count = {Count}")] + public class ReadOnlyCollection<T> : IList<T>, IList, IReadOnlyList<T> { - IList<T> list; + private IList<T> list; [NonSerialized] private Object _syncRoot; - public ReadOnlyCollection(IList<T> list) { - if (list == null) { + public ReadOnlyCollection(IList<T> list) + { + if (list == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.list); } this.list = list; } - public int Count { + public int Count + { get { return list.Count; } } - public T this[int index] { + public T this[int index] + { get { return list[index]; } } - public bool Contains(T value) { + public bool Contains(T value) + { return list.Contains(value); } - public void CopyTo(T[] array, int index) { + public void CopyTo(T[] array, int index) + { list.CopyTo(array, index); } - public IEnumerator<T> GetEnumerator() { + public IEnumerator<T> GetEnumerator() + { return list.GetEnumerator(); } - public int IndexOf(T value) { + public int IndexOf(T value) + { return list.IndexOf(value); } - protected IList<T> Items { - get { + protected IList<T> Items + { + get + { return list; } } - bool ICollection<T>.IsReadOnly { + bool ICollection<T>.IsReadOnly + { get { return true; } } - - T IList<T>.this[int index] { + + T IList<T>.this[int index] + { get { return list[index]; } - set { + set + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } } - void ICollection<T>.Add(T value) { + void ICollection<T>.Add(T value) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - - void ICollection<T>.Clear() { + + void ICollection<T>.Clear() + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - void IList<T>.Insert(int index, T value) { + void IList<T>.Insert(int index, T value) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - bool ICollection<T>.Remove(T value) { + bool ICollection<T>.Remove(T value) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); return false; } - void IList<T>.RemoveAt(int index) { + void IList<T>.RemoveAt(int index) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - IEnumerator IEnumerable.GetEnumerator() { + IEnumerator IEnumerable.GetEnumerator() + { return ((IEnumerable)list).GetEnumerator(); } - bool ICollection.IsSynchronized { + bool ICollection.IsSynchronized + { get { return false; } } - object ICollection.SyncRoot { - get { - if( _syncRoot == null) { + object ICollection.SyncRoot + { + get + { + if (_syncRoot == null) + { ICollection c = list as ICollection; - if( c != null) { + if (c != null) + { _syncRoot = c.SyncRoot; } - else { - System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); + else + { + System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); } } - return _syncRoot; + return _syncRoot; } } - void ICollection.CopyTo(Array array, int index) { - if (array==null) { + void ICollection.CopyTo(Array array, int index) + { + if (array == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (array.Rank != 1) { - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); + if (array.Rank != 1) + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); } - if( array.GetLowerBound(0) != 0 ) { + if (array.GetLowerBound(0) != 0) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound); } - - if (index < 0) { + + if (index < 0) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - if (array.Length - index < Count) { + if (array.Length - index < Count) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); } T[] items = array as T[]; - if (items != null) { + if (items != null) + { list.CopyTo(items, index); } - else { + else + { // // Catch the obvious case assignment will fail. // We can found all possible problems by doing the check though. // For example, if the element type of the Array is derived from T, // we can't figure out if we can successfully copy the element beforehand. // - Type targetType = array.GetType().GetElementType(); + Type targetType = array.GetType().GetElementType(); Type sourceType = typeof(T); - if(!(targetType.IsAssignableFrom(sourceType) || sourceType.IsAssignableFrom(targetType))) { + if (!(targetType.IsAssignableFrom(sourceType) || sourceType.IsAssignableFrom(targetType))) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } @@ -156,76 +190,94 @@ namespace System.Collections.ObjectModel // widening of primitive types here. // object[] objects = array as object[]; - if( objects == null) { + if (objects == null) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } int count = list.Count; - try { - for (int i = 0; i < count; i++) { + try + { + for (int i = 0; i < count; i++) + { objects[index++] = list[i]; } } - catch(ArrayTypeMismatchException) { + catch (ArrayTypeMismatchException) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } } } - bool IList.IsFixedSize { + bool IList.IsFixedSize + { get { return true; } } - bool IList.IsReadOnly { + bool IList.IsReadOnly + { get { return true; } } - object IList.this[int index] { + object IList.this[int index] + { get { return list[index]; } - set { + set + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } } - int IList.Add(object value) { + int IList.Add(object value) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); return -1; } - void IList.Clear() { - ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + void IList.Clear() + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - private static bool IsCompatibleObject(object value) { + private static bool IsCompatibleObject(object value) + { // Non-null values are fine. Only accept nulls if T is a class or Nullable<U>. // Note that default(T) is not equal to null for value types except when T is Nullable<U>. return ((value is T) || (value == null && default(T) == null)); } - bool IList.Contains(object value) { - if(IsCompatibleObject(value)) { - return Contains((T) value); + bool IList.Contains(object value) + { + if (IsCompatibleObject(value)) + { + return Contains((T)value); } return false; } - int IList.IndexOf(object value) { - if(IsCompatibleObject(value)) { + int IList.IndexOf(object value) + { + if (IsCompatibleObject(value)) + { return IndexOf((T)value); } return -1; } - void IList.Insert(int index, object value) { + void IList.Insert(int index, object value) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - void IList.Remove(object value) { - ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + void IList.Remove(object value) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - void IList.RemoveAt(int index) { + void IList.RemoveAt(int index) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); - } + } } } diff --git a/src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs b/src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs index 5c9e8c44c6..ebf86cdc58 100644 --- a/src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs +++ b/src/mscorlib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs @@ -11,18 +11,18 @@ ** ===========================================================*/ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; + namespace System.Collections.ObjectModel { - using System; - using System.Collections; - using System.Collections.Generic; - using System.Diagnostics; - using System.Diagnostics.Contracts; - [Serializable] [DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))] [DebuggerDisplay("Count = {Count}")] - public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue> + internal class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue> { private readonly IDictionary<TKey, TValue> m_dictionary; [NonSerialized] @@ -32,32 +32,41 @@ namespace System.Collections.ObjectModel [NonSerialized] private ValueCollection m_values; - public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary) { - if (dictionary == null) { + public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary) + { + if (dictionary == null) + { throw new ArgumentNullException(nameof(dictionary)); } Contract.EndContractBlock(); m_dictionary = dictionary; } - protected IDictionary<TKey, TValue> Dictionary { + protected IDictionary<TKey, TValue> Dictionary + { get { return m_dictionary; } } - public KeyCollection Keys { - get { + public KeyCollection Keys + { + get + { Contract.Ensures(Contract.Result<KeyCollection>() != null); - if (m_keys == null) { + if (m_keys == null) + { m_keys = new KeyCollection(m_dictionary.Keys); } return m_keys; } } - public ValueCollection Values { - get { + public ValueCollection Values + { + get + { Contract.Ensures(Contract.Result<ValueCollection>() != null); - if (m_values == null) { + if (m_values == null) + { m_values = new ValueCollection(m_dictionary.Values); } return m_values; @@ -66,46 +75,59 @@ namespace System.Collections.ObjectModel #region IDictionary<TKey, TValue> Members - public bool ContainsKey(TKey key) { + public bool ContainsKey(TKey key) + { return m_dictionary.ContainsKey(key); } - ICollection<TKey> IDictionary<TKey, TValue>.Keys { - get { + ICollection<TKey> IDictionary<TKey, TValue>.Keys + { + get + { return Keys; } } - public bool TryGetValue(TKey key, out TValue value) { + public bool TryGetValue(TKey key, out TValue value) + { return m_dictionary.TryGetValue(key, out value); } - ICollection<TValue> IDictionary<TKey, TValue>.Values { - get { + ICollection<TValue> IDictionary<TKey, TValue>.Values + { + get + { return Values; } } - public TValue this[TKey key] { - get { + public TValue this[TKey key] + { + get + { return m_dictionary[key]; } } - void IDictionary<TKey, TValue>.Add(TKey key, TValue value) { + void IDictionary<TKey, TValue>.Add(TKey key, TValue value) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - bool IDictionary<TKey, TValue>.Remove(TKey key) { + bool IDictionary<TKey, TValue>.Remove(TKey key) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); return false; } - TValue IDictionary<TKey, TValue>.this[TKey key] { - get { + TValue IDictionary<TKey, TValue>.this[TKey key] + { + get + { return m_dictionary[key]; } - set { + set + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } } @@ -114,31 +136,38 @@ namespace System.Collections.ObjectModel #region ICollection<KeyValuePair<TKey, TValue>> Members - public int Count { + public int Count + { get { return m_dictionary.Count; } } - bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) { + bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) + { return m_dictionary.Contains(item); } - void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { + void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) + { m_dictionary.CopyTo(array, arrayIndex); } - bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly { + bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly + { get { return true; } } - void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) { + void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - void ICollection<KeyValuePair<TKey, TValue>>.Clear() { + void ICollection<KeyValuePair<TKey, TValue>>.Clear() + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) { + bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); return false; } @@ -147,7 +176,8 @@ namespace System.Collections.ObjectModel #region IEnumerable<KeyValuePair<TKey, TValue>> Members - public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { + public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() + { return m_dictionary.GetEnumerator(); } @@ -155,7 +185,8 @@ namespace System.Collections.ObjectModel #region IEnumerable Members - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { return ((IEnumerable)m_dictionary).GetEnumerator(); } @@ -163,131 +194,170 @@ namespace System.Collections.ObjectModel #region IDictionary Members - private static bool IsCompatibleKey(object key) { - if (key == null) { + private static bool IsCompatibleKey(object key) + { + if (key == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } return key is TKey; } - void IDictionary.Add(object key, object value) { + void IDictionary.Add(object key, object value) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - void IDictionary.Clear() { + void IDictionary.Clear() + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - bool IDictionary.Contains(object key) { + bool IDictionary.Contains(object key) + { return IsCompatibleKey(key) && ContainsKey((TKey)key); } - IDictionaryEnumerator IDictionary.GetEnumerator() { + IDictionaryEnumerator IDictionary.GetEnumerator() + { IDictionary d = m_dictionary as IDictionary; - if (d != null) { + if (d != null) + { return d.GetEnumerator(); } return new DictionaryEnumerator(m_dictionary); } - bool IDictionary.IsFixedSize { + bool IDictionary.IsFixedSize + { get { return true; } } - bool IDictionary.IsReadOnly { + bool IDictionary.IsReadOnly + { get { return true; } } - ICollection IDictionary.Keys { - get { + ICollection IDictionary.Keys + { + get + { return Keys; } } - void IDictionary.Remove(object key) { + void IDictionary.Remove(object key) + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } - ICollection IDictionary.Values { - get { + ICollection IDictionary.Values + { + get + { return Values; } } - object IDictionary.this[object key] { - get { - if (IsCompatibleKey(key)) { + object IDictionary.this[object key] + { + get + { + if (IsCompatibleKey(key)) + { return this[(TKey)key]; } return null; } - set { + set + { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } } - void ICollection.CopyTo(Array array, int index) { - if (array == null) { + void ICollection.CopyTo(Array array, int index) + { + if (array == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (array.Rank != 1) { + if (array.Rank != 1) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); } - if (array.GetLowerBound(0) != 0) { + if (array.GetLowerBound(0) != 0) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound); } - if (index < 0 || index > array.Length) { + if (index < 0 || index > array.Length) + { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - if (array.Length - index < Count) { + if (array.Length - index < Count) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); } KeyValuePair<TKey, TValue>[] pairs = array as KeyValuePair<TKey, TValue>[]; - if (pairs != null) { + if (pairs != null) + { m_dictionary.CopyTo(pairs, index); } - else { + else + { DictionaryEntry[] dictEntryArray = array as DictionaryEntry[]; - if (dictEntryArray != null) { - foreach (var item in m_dictionary) { + if (dictEntryArray != null) + { + foreach (var item in m_dictionary) + { dictEntryArray[index++] = new DictionaryEntry(item.Key, item.Value); } } - else { + else + { object[] objects = array as object[]; - if (objects == null) { + if (objects == null) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } - try { - foreach (var item in m_dictionary) { + try + { + foreach (var item in m_dictionary) + { objects[index++] = new KeyValuePair<TKey, TValue>(item.Key, item.Value); } } - catch (ArrayTypeMismatchException) { + catch (ArrayTypeMismatchException) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } } } } - bool ICollection.IsSynchronized { + bool ICollection.IsSynchronized + { get { return false; } } - object ICollection.SyncRoot { - get { - if (m_syncRoot == null) { + object ICollection.SyncRoot + { + get + { + if (m_syncRoot == null) + { ICollection c = m_dictionary as ICollection; - if (c != null) { + if (c != null) + { m_syncRoot = c.SyncRoot; } - else { + else + { System.Threading.Interlocked.CompareExchange<Object>(ref m_syncRoot, new Object(), null); } } @@ -296,36 +366,44 @@ namespace System.Collections.ObjectModel } [Serializable] - private struct DictionaryEnumerator : IDictionaryEnumerator { + private struct DictionaryEnumerator : IDictionaryEnumerator + { private readonly IDictionary<TKey, TValue> m_dictionary; private IEnumerator<KeyValuePair<TKey, TValue>> m_enumerator; - public DictionaryEnumerator(IDictionary<TKey, TValue> dictionary) { + public DictionaryEnumerator(IDictionary<TKey, TValue> dictionary) + { m_dictionary = dictionary; m_enumerator = m_dictionary.GetEnumerator(); } - public DictionaryEntry Entry { + public DictionaryEntry Entry + { get { return new DictionaryEntry(m_enumerator.Current.Key, m_enumerator.Current.Value); } } - public object Key { + public object Key + { get { return m_enumerator.Current.Key; } } - public object Value { + public object Value + { get { return m_enumerator.Current.Value; } } - public object Current { + public object Current + { get { return Entry; } } - public bool MoveNext() { + public bool MoveNext() + { return m_enumerator.MoveNext(); } - public void Reset() { + public void Reset() + { m_enumerator.Reset(); } } @@ -334,14 +412,18 @@ namespace System.Collections.ObjectModel #region IReadOnlyDictionary members - IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys { - get { + IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys + { + get + { return Keys; } } - IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values { - get { + IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values + { + get + { return Values; } } @@ -351,14 +433,16 @@ namespace System.Collections.ObjectModel [DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))] [DebuggerDisplay("Count = {Count}")] [Serializable] - public sealed class KeyCollection : ICollection<TKey>, ICollection, IReadOnlyCollection<TKey> { + public sealed class KeyCollection : ICollection<TKey>, ICollection, IReadOnlyCollection<TKey> + { private readonly ICollection<TKey> m_collection; [NonSerialized] private Object m_syncRoot; internal KeyCollection(ICollection<TKey> collection) { - if (collection == null) { + if (collection == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); } m_collection = collection; @@ -386,11 +470,13 @@ namespace System.Collections.ObjectModel m_collection.CopyTo(array, arrayIndex); } - public int Count { + public int Count + { get { return m_collection.Count; } } - bool ICollection<TKey>.IsReadOnly { + bool ICollection<TKey>.IsReadOnly + { get { return true; } } @@ -413,7 +499,8 @@ namespace System.Collections.ObjectModel #region IEnumerable Members - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { return ((IEnumerable)m_collection).GetEnumerator(); } @@ -421,22 +508,29 @@ namespace System.Collections.ObjectModel #region ICollection Members - void ICollection.CopyTo(Array array, int index) { + void ICollection.CopyTo(Array array, int index) + { ReadOnlyDictionaryHelpers.CopyToNonGenericICollectionHelper<TKey>(m_collection, array, index); } - bool ICollection.IsSynchronized { + bool ICollection.IsSynchronized + { get { return false; } } - object ICollection.SyncRoot { - get { - if (m_syncRoot == null) { + object ICollection.SyncRoot + { + get + { + if (m_syncRoot == null) + { ICollection c = m_collection as ICollection; - if (c != null) { + if (c != null) + { m_syncRoot = c.SyncRoot; } - else { + else + { System.Threading.Interlocked.CompareExchange<Object>(ref m_syncRoot, new Object(), null); } } @@ -450,14 +544,16 @@ namespace System.Collections.ObjectModel [DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))] [DebuggerDisplay("Count = {Count}")] [Serializable] - public sealed class ValueCollection : ICollection<TValue>, ICollection, IReadOnlyCollection<TValue> { + public sealed class ValueCollection : ICollection<TValue>, ICollection, IReadOnlyCollection<TValue> + { private readonly ICollection<TValue> m_collection; [NonSerialized] private Object m_syncRoot; internal ValueCollection(ICollection<TValue> collection) { - if (collection == null) { + if (collection == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); } m_collection = collection; @@ -485,11 +581,13 @@ namespace System.Collections.ObjectModel m_collection.CopyTo(array, arrayIndex); } - public int Count { + public int Count + { get { return m_collection.Count; } } - bool ICollection<TValue>.IsReadOnly { + bool ICollection<TValue>.IsReadOnly + { get { return true; } } @@ -512,7 +610,8 @@ namespace System.Collections.ObjectModel #region IEnumerable Members - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { return ((IEnumerable)m_collection).GetEnumerator(); } @@ -520,22 +619,29 @@ namespace System.Collections.ObjectModel #region ICollection Members - void ICollection.CopyTo(Array array, int index) { + void ICollection.CopyTo(Array array, int index) + { ReadOnlyDictionaryHelpers.CopyToNonGenericICollectionHelper<TValue>(m_collection, array, index); } - bool ICollection.IsSynchronized { + bool ICollection.IsSynchronized + { get { return false; } } - object ICollection.SyncRoot { - get { - if (m_syncRoot == null) { + object ICollection.SyncRoot + { + get + { + if (m_syncRoot == null) + { ICollection c = m_collection as ICollection; - if (c != null) { + if (c != null) + { m_syncRoot = c.SyncRoot; } - else { + else + { System.Threading.Interlocked.CompareExchange<Object>(ref m_syncRoot, new Object(), null); } } @@ -555,38 +661,46 @@ namespace System.Collections.ObjectModel // Abstracted away to avoid redundant implementations. internal static void CopyToNonGenericICollectionHelper<T>(ICollection<T> collection, Array array, int index) { - if (array == null) { + if (array == null) + { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (array.Rank != 1) { + if (array.Rank != 1) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); } - if (array.GetLowerBound(0) != 0) { + if (array.GetLowerBound(0) != 0) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound); } - if (index < 0) { + if (index < 0) + { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.arrayIndex, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } - if (array.Length - index < collection.Count) { + if (array.Length - index < collection.Count) + { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); } // Easy out if the ICollection<T> implements the non-generic ICollection ICollection nonGenericCollection = collection as ICollection; - if (nonGenericCollection != null) { + if (nonGenericCollection != null) + { nonGenericCollection.CopyTo(array, index); return; } T[] items = array as T[]; - if (items != null) { + if (items != null) + { collection.CopyTo(items, index); } - else { + else + { // // Catch the obvious case assignment will fail. // We can found all possible problems by doing the check though. @@ -595,7 +709,8 @@ namespace System.Collections.ObjectModel // Type targetType = array.GetType().GetElementType(); Type sourceType = typeof(T); - if (!(targetType.IsAssignableFrom(sourceType) || sourceType.IsAssignableFrom(targetType))) { + if (!(targetType.IsAssignableFrom(sourceType) || sourceType.IsAssignableFrom(targetType))) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } @@ -604,16 +719,20 @@ namespace System.Collections.ObjectModel // widening of primitive types here. // object[] objects = array as object[]; - if (objects == null) { + if (objects == null) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } - try { - foreach (var item in collection) { + try + { + foreach (var item in collection) + { objects[index++] = item; } } - catch (ArrayTypeMismatchException) { + catch (ArrayTypeMismatchException) + { ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); } } diff --git a/src/mscorlib/src/System/Collections/StructuralComparisons.cs b/src/mscorlib/src/System/Collections/StructuralComparisons.cs deleted file mode 100644 index 685af59c4b..0000000000 --- a/src/mscorlib/src/System/Collections/StructuralComparisons.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// - -using System; - -namespace System.Collections { - public static class StructuralComparisons { - - private static volatile IComparer s_StructuralComparer; - private static volatile IEqualityComparer s_StructuralEqualityComparer; - - public static IComparer StructuralComparer { - get { - IComparer comparer = s_StructuralComparer; - if (comparer == null) { - comparer = new StructuralComparer(); - s_StructuralComparer = comparer; - } - return comparer; - } - } - - public static IEqualityComparer StructuralEqualityComparer { - get { - IEqualityComparer comparer = s_StructuralEqualityComparer; - if (comparer == null) { - comparer = new StructuralEqualityComparer(); - s_StructuralEqualityComparer = comparer; - } - return comparer; - } - } - } - - [Serializable] - internal class StructuralEqualityComparer : IEqualityComparer { - public new bool Equals(Object x, Object y) { - if (x != null) { - - IStructuralEquatable seObj = x as IStructuralEquatable; - - if (seObj != null){ - return seObj.Equals(y, this); - } - - if (y != null) { - return x.Equals(y); - } else { - return false; - } - } - if (y != null) return false; - return true; - } - - public int GetHashCode(Object obj) { - if (obj == null) return 0; - - IStructuralEquatable seObj = obj as IStructuralEquatable; - - if (seObj != null) { - return seObj.GetHashCode(this); - } - - return obj.GetHashCode(); - } - } - - [Serializable] - internal class StructuralComparer : IComparer { - public int Compare(Object x, Object y) { - - if (x == null) return y == null ? 0 : -1; - if (y == null) return 1; - - IStructuralComparable scX = x as IStructuralComparable; - - if (scX != null) { - return scX.CompareTo(y, this); - } - - return Comparer.Default.Compare(x, y); - } - } - -} |