| File: System\Net\Http\Headers\ObjectCollection.cs | Web Access |
| Project: src\runtime\src\libraries\System.Net.Http\src\System.Net.Http.csproj (System.Net.Http) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace System.Net.Http.Headers { internal sealed class UnvalidatedObjectCollection<T> : ObjectCollection<T> where T : class { public override void Validate(T item) { ArgumentNullException.ThrowIfNull(item); } } /// <summary>An <see cref="ICollection{T}"/> list that prohibits null elements and that is optimized for a small number of elements.</summary> [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ObjectCollection<>.DebugView))] internal abstract class ObjectCollection<T> : ICollection<T> where T : class { private const int DefaultSize = 4; /// <summary>null, a T, or a T[].</summary> internal object? _items; /// <summary>Number of elements stored in the collection.</summary> internal int _size; public ObjectCollection() { } public int Count => _size; public bool IsReadOnly => false; public abstract void Validate(T item); public void Add(T item) { Validate(item); Debug.Assert(item != null); if (_items is null) { // The collection is empty. Just store the new item directly. _items = item; _size = 1; } else if (_items is T existingItem) { // The collection has a single item stored directly. Upgrade to // an array, and store both the existing and new items. Debug.Assert(_size == 1); T[] items = new T[DefaultSize]; items[0] = existingItem; items[1] = item; _items = items; _size = 2; } else { T[] array = (T[])_items; int size = _size; if ((uint)size < (uint)array.Length) { // There's room in the existing array. Add the item. array[size] = item; } else { // We need to grow the array. Do so, and store the new item. Debug.Assert(_size > 0); Debug.Assert(_size == array.Length); var newItems = new T[array.Length * 2]; Array.Copy(array, newItems, size); _items = newItems; newItems[size] = item; } _size = size + 1; } } public void Clear() { _items = null; _size = 0; } public bool Contains(T item) => _size <= 0 ? false : _items is T o ? o.Equals(item) : _items is T[] items && Array.IndexOf(items, item, 0, _size) >= 0; public void CopyTo(T[] array, int arrayIndex) { if (_items is T[] items) { Array.Copy(items, 0, array, arrayIndex, _size); } else { Debug.Assert(_size == 0 || _size == 1); if (array is null || _size > array.Length - arrayIndex) { // Use Array.CopyTo to throw the right exceptions. new T[] { (T)_items! }.CopyTo(array!, arrayIndex); } else if (_size == 1) { array[arrayIndex] = (T)_items!; } } } public bool Remove(T item) { if (_items is T o) { if (o.Equals(item)) { _items = null; _size = 0; return true; } } else if (_items is T[] items) { int index = Array.IndexOf(items, item, 0, _size); if (index >= 0) { _size--; if (index < _size) { Array.Copy(items, index + 1, items, index, _size - index); } items[_size] = null!; return true; } } return false; } public Enumerator GetEnumerator() => new Enumerator(this); IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public struct Enumerator : IEnumerator<T> { private readonly ObjectCollection<T> _list; private int _index; private T _current; internal Enumerator(ObjectCollection<T> list) { _list = list; _index = 0; _current = default!; } public void Dispose() { } public bool MoveNext() { ObjectCollection<T> list = _list; if ((uint)_index < (uint)list._size) { _current = list._items is T[] items ? items[_index] : (T)list._items!; _index++; return true; } _index = _list._size + 1; _current = default!; return false; } public T Current => _current!; object? IEnumerator.Current => _current; void IEnumerator.Reset() { _index = 0; _current = default!; } } internal sealed class DebugView { private readonly ObjectCollection<T> _collection; public DebugView(ObjectCollection<T> collection) { ArgumentNullException.ThrowIfNull(collection); _collection = collection; } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Items { get { T[] items = new T[_collection.Count]; _collection.CopyTo(items, 0); return items; } } } } }