committed by
GitHub
18 changed files with 3278 additions and 31 deletions
@ -0,0 +1,40 @@ |
|||
// This source file is adapted from the Collections.Pooled.
|
|||
// (https://github.com/jtmueller/Collections.Pooled/tree/master/Collections.Pooled/)
|
|||
|
|||
namespace Avalonia.Collections.Pooled |
|||
{ |
|||
/// <summary>
|
|||
/// This enum allows control over how data is treated when internal
|
|||
/// arrays are returned to the ArrayPool. Be careful to understand
|
|||
/// what each option does before using anything other than the default
|
|||
/// of Auto.
|
|||
/// </summary>
|
|||
public enum ClearMode |
|||
{ |
|||
/// <summary>
|
|||
/// <para><code>Auto</code> has different behavior depending on the host project's target framework.</para>
|
|||
/// <para>.NET Core 2.1: Reference types and value types that contain reference types are cleared
|
|||
/// when the internal arrays are returned to the pool. Value types that do not contain reference
|
|||
/// types are not cleared when returned to the pool.</para>
|
|||
/// <para>.NET Standard 2.0: All user types are cleared before returning to the pool, in case they
|
|||
/// contain reference types.
|
|||
/// For .NET Standard, Auto and Always have the same behavior.</para>
|
|||
/// </summary>
|
|||
Auto = 0, |
|||
/// <summary>
|
|||
/// The <para><code>Always</code> setting has the effect of always clearing user types before returning to the pool.
|
|||
/// This is the default behavior on .NET Standard.</para><para>You might want to turn this on in a .NET Core project
|
|||
/// if you were concerned about sensitive data stored in value types leaking to other pars of your application.</para>
|
|||
/// </summary>
|
|||
Always = 1, |
|||
/// <summary>
|
|||
/// <para><code>Never</code> will cause pooled collections to never clear user types before returning them to the pool.</para>
|
|||
/// <para>You might want to use this setting in a .NET Standard project when you know that a particular collection stores
|
|||
/// only value types and you want the performance benefit of not taking time to reset array items to their default value.</para>
|
|||
/// <para>Be careful with this setting: if used for a collection that contains reference types, or value types that contain
|
|||
/// reference types, this setting could cause memory issues by making the garbage collector unable to clean up instances
|
|||
/// that are still being referenced by arrays sitting in the ArrayPool.</para>
|
|||
/// </summary>
|
|||
Never = 2 |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
// 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; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
|
|||
namespace Avalonia.Collections.Pooled |
|||
{ |
|||
internal sealed class ICollectionDebugView<T> |
|||
{ |
|||
private readonly ICollection<T> _collection; |
|||
|
|||
public ICollectionDebugView(ICollection<T> collection) |
|||
{ |
|||
_collection = collection ?? throw new ArgumentNullException(nameof(collection)); |
|||
} |
|||
|
|||
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] |
|||
public T[] Items |
|||
{ |
|||
get |
|||
{ |
|||
T[] items = new T[_collection.Count]; |
|||
_collection.CopyTo(items, 0); |
|||
return items; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
// This source file is adapted from the Collections.Pooled.
|
|||
// (https://github.com/jtmueller/Collections.Pooled/tree/master/Collections.Pooled/)
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Avalonia.Collections.Pooled |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a read-only collection of pooled elements that can be accessed by index
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of elements in the read-only pooled list.</typeparam>
|
|||
|
|||
public interface IReadOnlyPooledList<T> : IReadOnlyList<T> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets a <see cref="System.ReadOnlySpan{T}"/> for the items currently in the collection.
|
|||
/// </summary>
|
|||
ReadOnlySpan<T> Span { get; } |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -0,0 +1,699 @@ |
|||
// 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: An array implementation of a generic stack. |
|||
** |
|||
** |
|||
=============================================================================*/ |
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.Serialization; |
|||
using System.Threading; |
|||
|
|||
namespace Avalonia.Collections.Pooled |
|||
{ |
|||
/// <summary>
|
|||
/// A simple stack of objects. Internally it is implemented as an array,
|
|||
/// so Push can be O(n). Pop is O(1).
|
|||
/// </summary>
|
|||
[DebuggerTypeProxy(typeof(StackDebugView<>))] |
|||
[DebuggerDisplay("Count = {Count}")] |
|||
[Serializable] |
|||
public class PooledStack<T> : IEnumerable<T>, ICollection, IReadOnlyCollection<T>, IDisposable, IDeserializationCallback |
|||
{ |
|||
[NonSerialized] |
|||
private ArrayPool<T> _pool; |
|||
[NonSerialized] |
|||
private object _syncRoot; |
|||
|
|||
private T[] _array; // Storage for stack elements. Do not rename (binary serialization)
|
|||
private int _size; // Number of items in the stack. Do not rename (binary serialization)
|
|||
private int _version; // Used to keep enumerator in sync w/ collection. Do not rename (binary serialization)
|
|||
private readonly bool _clearOnFree; |
|||
|
|||
private const int DefaultCapacity = 4; |
|||
|
|||
#region Constructors
|
|||
|
|||
/// <summary>
|
|||
/// Create a stack with the default initial capacity.
|
|||
/// </summary>
|
|||
public PooledStack() : this(ClearMode.Auto, ArrayPool<T>.Shared) { } |
|||
|
|||
/// <summary>
|
|||
/// Create a stack with the default initial capacity.
|
|||
/// </summary>
|
|||
public PooledStack(ClearMode clearMode) : this(clearMode, ArrayPool<T>.Shared) { } |
|||
|
|||
/// <summary>
|
|||
/// Create a stack with the default initial capacity.
|
|||
/// </summary>
|
|||
public PooledStack(ArrayPool<T> customPool) : this(ClearMode.Auto, customPool) { } |
|||
|
|||
/// <summary>
|
|||
/// Create a stack with the default initial capacity and a custom ArrayPool.
|
|||
/// </summary>
|
|||
public PooledStack(ClearMode clearMode, ArrayPool<T> customPool) |
|||
{ |
|||
_pool = customPool ?? ArrayPool<T>.Shared; |
|||
_array = Array.Empty<T>(); |
|||
_clearOnFree = ShouldClear(clearMode); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a stack with a specific initial capacity. The initial capacity
|
|||
/// must be a non-negative number.
|
|||
/// </summary>
|
|||
public PooledStack(int capacity) : this(capacity, ClearMode.Auto, ArrayPool<T>.Shared) { } |
|||
|
|||
/// <summary>
|
|||
/// Create a stack with a specific initial capacity. The initial capacity
|
|||
/// must be a non-negative number.
|
|||
/// </summary>
|
|||
public PooledStack(int capacity, ClearMode clearMode) : this(capacity, clearMode, ArrayPool<T>.Shared) { } |
|||
|
|||
/// <summary>
|
|||
/// Create a stack with a specific initial capacity. The initial capacity
|
|||
/// must be a non-negative number.
|
|||
/// </summary>
|
|||
public PooledStack(int capacity, ArrayPool<T> customPool) : this(capacity, ClearMode.Auto, customPool) { } |
|||
|
|||
/// <summary>
|
|||
/// Create a stack with a specific initial capacity. The initial capacity
|
|||
/// must be a non-negative number.
|
|||
/// </summary>
|
|||
public PooledStack(int capacity, ClearMode clearMode, ArrayPool<T> customPool) |
|||
{ |
|||
if (capacity < 0) |
|||
{ |
|||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, |
|||
ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); |
|||
} |
|||
_pool = customPool ?? ArrayPool<T>.Shared; |
|||
_array = _pool.Rent(capacity); |
|||
_clearOnFree = ShouldClear(clearMode); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Fills a Stack with the contents of a particular collection. The items are
|
|||
/// pushed onto the stack in the same order they are read by the enumerator.
|
|||
/// </summary>
|
|||
public PooledStack(IEnumerable<T> enumerable) : this(enumerable, ClearMode.Auto, ArrayPool<T>.Shared) { } |
|||
|
|||
/// <summary>
|
|||
/// Fills a Stack with the contents of a particular collection. The items are
|
|||
/// pushed onto the stack in the same order they are read by the enumerator.
|
|||
/// </summary>
|
|||
public PooledStack(IEnumerable<T> enumerable, ClearMode clearMode) : this(enumerable, clearMode, ArrayPool<T>.Shared) { } |
|||
|
|||
/// <summary>
|
|||
/// Fills a Stack with the contents of a particular collection. The items are
|
|||
/// pushed onto the stack in the same order they are read by the enumerator.
|
|||
/// </summary>
|
|||
public PooledStack(IEnumerable<T> enumerable, ArrayPool<T> customPool) : this(enumerable, ClearMode.Auto, customPool) { } |
|||
|
|||
/// <summary>
|
|||
/// Fills a Stack with the contents of a particular collection. The items are
|
|||
/// pushed onto the stack in the same order they are read by the enumerator.
|
|||
/// </summary>
|
|||
public PooledStack(IEnumerable<T> enumerable, ClearMode clearMode, ArrayPool<T> customPool) |
|||
{ |
|||
_pool = customPool ?? ArrayPool<T>.Shared; |
|||
_clearOnFree = ShouldClear(clearMode); |
|||
|
|||
switch (enumerable) |
|||
{ |
|||
case null: |
|||
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.enumerable); |
|||
break; |
|||
|
|||
case ICollection<T> collection: |
|||
if (collection.Count == 0) |
|||
{ |
|||
_array = Array.Empty<T>(); |
|||
} |
|||
else |
|||
{ |
|||
_array = _pool.Rent(collection.Count); |
|||
collection.CopyTo(_array, 0); |
|||
_size = collection.Count; |
|||
} |
|||
break; |
|||
|
|||
default: |
|||
using (var list = new PooledList<T>(enumerable)) |
|||
{ |
|||
_array = _pool.Rent(list.Count); |
|||
list.Span.CopyTo(_array); |
|||
_size = list.Count; |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Fills a Stack with the contents of a particular collection. The items are
|
|||
/// pushed onto the stack in the same order they are read by the enumerator.
|
|||
/// </summary>
|
|||
public PooledStack(T[] array) : this(array.AsSpan(), ClearMode.Auto, ArrayPool<T>.Shared) { } |
|||
|
|||
/// <summary>
|
|||
/// Fills a Stack with the contents of a particular collection. The items are
|
|||
/// pushed onto the stack in the same order they are read by the enumerator.
|
|||
/// </summary>
|
|||
public PooledStack(T[] array, ClearMode clearMode) : this(array.AsSpan(), clearMode, ArrayPool<T>.Shared) { } |
|||
|
|||
/// <summary>
|
|||
/// Fills a Stack with the contents of a particular collection. The items are
|
|||
/// pushed onto the stack in the same order they are read by the enumerator.
|
|||
/// </summary>
|
|||
public PooledStack(T[] array, ArrayPool<T> customPool) : this(array.AsSpan(), ClearMode.Auto, customPool) { } |
|||
|
|||
/// <summary>
|
|||
/// Fills a Stack with the contents of a particular collection. The items are
|
|||
/// pushed onto the stack in the same order they are read by the enumerator.
|
|||
/// </summary>
|
|||
public PooledStack(T[] array, ClearMode clearMode, ArrayPool<T> customPool) : this(array.AsSpan(), clearMode, customPool) { } |
|||
|
|||
/// <summary>
|
|||
/// Fills a Stack with the contents of a particular collection. The items are
|
|||
/// pushed onto the stack in the same order they are read by the enumerator.
|
|||
/// </summary>
|
|||
public PooledStack(ReadOnlySpan<T> span) : this(span, ClearMode.Auto, ArrayPool<T>.Shared) { } |
|||
|
|||
/// <summary>
|
|||
/// Fills a Stack with the contents of a particular collection. The items are
|
|||
/// pushed onto the stack in the same order they are read by the enumerator.
|
|||
/// </summary>
|
|||
public PooledStack(ReadOnlySpan<T> span, ClearMode clearMode) : this(span, clearMode, ArrayPool<T>.Shared) { } |
|||
|
|||
/// <summary>
|
|||
/// Fills a Stack with the contents of a particular collection. The items are
|
|||
/// pushed onto the stack in the same order they are read by the enumerator.
|
|||
/// </summary>
|
|||
public PooledStack(ReadOnlySpan<T> span, ArrayPool<T> customPool) : this(span, ClearMode.Auto, customPool) { } |
|||
|
|||
/// <summary>
|
|||
/// Fills a Stack with the contents of a particular collection. The items are
|
|||
/// pushed onto the stack in the same order they are read by the enumerator.
|
|||
/// </summary>
|
|||
public PooledStack(ReadOnlySpan<T> span, ClearMode clearMode, ArrayPool<T> customPool) |
|||
{ |
|||
_pool = customPool ?? ArrayPool<T>.Shared; |
|||
_clearOnFree = ShouldClear(clearMode); |
|||
_array = _pool.Rent(span.Length); |
|||
span.CopyTo(_array); |
|||
_size = span.Length; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
/// <summary>
|
|||
/// The number of items in the stack.
|
|||
/// </summary>
|
|||
public int Count => _size; |
|||
|
|||
/// <summary>
|
|||
/// Returns the ClearMode behavior for the collection, denoting whether values are
|
|||
/// cleared from internal arrays before returning them to the pool.
|
|||
/// </summary>
|
|||
public ClearMode ClearMode => _clearOnFree ? ClearMode.Always : ClearMode.Never; |
|||
|
|||
bool ICollection.IsSynchronized => false; |
|||
|
|||
object ICollection.SyncRoot |
|||
{ |
|||
get |
|||
{ |
|||
if (_syncRoot == null) |
|||
{ |
|||
Interlocked.CompareExchange<object>(ref _syncRoot, new object(), null); |
|||
} |
|||
return _syncRoot; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes all Objects from the Stack.
|
|||
/// </summary>
|
|||
public void Clear() |
|||
{ |
|||
if (_clearOnFree) |
|||
{ |
|||
Array.Clear(_array, 0, _size); // clear the elements so that the gc can reclaim the references.
|
|||
} |
|||
_size = 0; |
|||
_version++; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares items using the default equality comparer
|
|||
/// </summary>
|
|||
public bool Contains(T item) |
|||
{ |
|||
// PERF: Internally Array.LastIndexOf calls
|
|||
// EqualityComparer<T>.Default.LastIndexOf, which
|
|||
// is specialized for different types. This
|
|||
// boosts performance since instead of making a
|
|||
// virtual method call each iteration of the loop,
|
|||
// via EqualityComparer<T>.Default.Equals, we
|
|||
// only make one virtual call to EqualityComparer.LastIndexOf.
|
|||
|
|||
return _size != 0 && Array.LastIndexOf(_array, item, _size - 1) != -1; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This method removes all items which match the predicate.
|
|||
/// The complexity is O(n).
|
|||
/// </summary>
|
|||
public int RemoveWhere(Func<T, bool> match) |
|||
{ |
|||
if (match == null) |
|||
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); |
|||
|
|||
int freeIndex = 0; // the first free slot in items array
|
|||
|
|||
// Find the first item which needs to be removed.
|
|||
while (freeIndex < _size && !match(_array[freeIndex])) |
|||
freeIndex++; |
|||
if (freeIndex >= _size) |
|||
return 0; |
|||
|
|||
int current = freeIndex + 1; |
|||
while (current < _size) |
|||
{ |
|||
// Find the first item which needs to be kept.
|
|||
while (current < _size && match(_array[current])) |
|||
current++; |
|||
|
|||
if (current < _size) |
|||
{ |
|||
// copy item to the free slot.
|
|||
_array[freeIndex++] = _array[current++]; |
|||
} |
|||
} |
|||
|
|||
if (_clearOnFree) |
|||
{ |
|||
// Clear the removed elements so that the gc can reclaim the references.
|
|||
Array.Clear(_array, freeIndex, _size - freeIndex); |
|||
} |
|||
|
|||
int result = _size - freeIndex; |
|||
_size = freeIndex; |
|||
_version++; |
|||
return result; |
|||
} |
|||
|
|||
// Copies the stack into an array.
|
|||
public void CopyTo(T[] array, int arrayIndex) |
|||
{ |
|||
if (array == null) |
|||
{ |
|||
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); |
|||
} |
|||
|
|||
if (arrayIndex < 0 || arrayIndex > array.Length) |
|||
{ |
|||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.arrayIndex); |
|||
} |
|||
|
|||
if (array.Length - arrayIndex < _size) |
|||
{ |
|||
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); |
|||
} |
|||
|
|||
Debug.Assert(array != _array); |
|||
int srcIndex = 0; |
|||
int dstIndex = arrayIndex + _size; |
|||
while (srcIndex < _size) |
|||
{ |
|||
array[--dstIndex] = _array[srcIndex++]; |
|||
} |
|||
} |
|||
|
|||
public void CopyTo(Span<T> span) |
|||
{ |
|||
if (span.Length < _size) |
|||
{ |
|||
ThrowHelper.ThrowArgumentException_DestinationTooShort(); |
|||
} |
|||
|
|||
int srcIndex = 0; |
|||
int dstIndex = _size; |
|||
while (srcIndex < _size) |
|||
{ |
|||
span[--dstIndex] = _array[srcIndex++]; |
|||
} |
|||
} |
|||
|
|||
void ICollection.CopyTo(Array array, int arrayIndex) |
|||
{ |
|||
if (array == null) |
|||
{ |
|||
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); |
|||
} |
|||
|
|||
if (array.Rank != 1) |
|||
{ |
|||
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); |
|||
} |
|||
|
|||
if (array.GetLowerBound(0) != 0) |
|||
{ |
|||
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound, ExceptionArgument.array); |
|||
} |
|||
|
|||
if (arrayIndex < 0 || arrayIndex > array.Length) |
|||
{ |
|||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.arrayIndex); |
|||
} |
|||
|
|||
if (array.Length - arrayIndex < _size) |
|||
{ |
|||
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen); |
|||
} |
|||
|
|||
try |
|||
{ |
|||
Array.Copy(_array, 0, array, arrayIndex, _size); |
|||
Array.Reverse(array, arrayIndex, _size); |
|||
} |
|||
catch (ArrayTypeMismatchException) |
|||
{ |
|||
ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns an IEnumerator for this PooledStack.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
public Enumerator GetEnumerator() |
|||
=> new Enumerator(this); |
|||
|
|||
/// <internalonly/>
|
|||
IEnumerator<T> IEnumerable<T>.GetEnumerator() |
|||
=> new Enumerator(this); |
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
=> new Enumerator(this); |
|||
|
|||
public void TrimExcess() |
|||
{ |
|||
if (_size == 0) |
|||
{ |
|||
ReturnArray(replaceWith: Array.Empty<T>()); |
|||
_version++; |
|||
return; |
|||
} |
|||
|
|||
int threshold = (int)(_array.Length * 0.9); |
|||
if (_size < threshold) |
|||
{ |
|||
var newArray = _pool.Rent(_size); |
|||
if (newArray.Length < _array.Length) |
|||
{ |
|||
Array.Copy(_array, newArray, _size); |
|||
ReturnArray(replaceWith: newArray); |
|||
_version++; |
|||
} |
|||
else |
|||
{ |
|||
// The array from the pool wasn't any smaller than the one we already had,
|
|||
// (we can only control minimum size) so return it and do nothing.
|
|||
// If we create an exact-sized array not from the pool, we'll
|
|||
// get an exception when returning it to the pool.
|
|||
_pool.Return(newArray); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the top object on the stack without removing it. If the stack
|
|||
/// is empty, Peek throws an InvalidOperationException.
|
|||
/// </summary>
|
|||
public T Peek() |
|||
{ |
|||
int size = _size - 1; |
|||
T[] array = _array; |
|||
|
|||
if ((uint)size >= (uint)array.Length) |
|||
{ |
|||
ThrowForEmptyStack(); |
|||
} |
|||
|
|||
return array[size]; |
|||
} |
|||
|
|||
public bool TryPeek(out T result) |
|||
{ |
|||
int size = _size - 1; |
|||
T[] array = _array; |
|||
|
|||
if ((uint)size >= (uint)array.Length) |
|||
{ |
|||
result = default; |
|||
return false; |
|||
} |
|||
result = array[size]; |
|||
return true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Pops an item from the top of the stack. If the stack is empty, Pop
|
|||
/// throws an InvalidOperationException.
|
|||
/// </summary>
|
|||
public T Pop() |
|||
{ |
|||
int size = _size - 1; |
|||
T[] array = _array; |
|||
|
|||
// if (_size == 0) is equivalent to if (size == -1), and this case
|
|||
// is covered with (uint)size, thus allowing bounds check elimination
|
|||
// https://github.com/dotnet/coreclr/pull/9773
|
|||
if ((uint)size >= (uint)array.Length) |
|||
{ |
|||
ThrowForEmptyStack(); |
|||
} |
|||
|
|||
_version++; |
|||
_size = size; |
|||
T item = array[size]; |
|||
if (_clearOnFree) |
|||
{ |
|||
array[size] = default; // Free memory quicker.
|
|||
} |
|||
return item; |
|||
} |
|||
|
|||
public bool TryPop(out T result) |
|||
{ |
|||
int size = _size - 1; |
|||
T[] array = _array; |
|||
|
|||
if ((uint)size >= (uint)array.Length) |
|||
{ |
|||
result = default; |
|||
return false; |
|||
} |
|||
|
|||
_version++; |
|||
_size = size; |
|||
result = array[size]; |
|||
if (_clearOnFree) |
|||
{ |
|||
array[size] = default; // Free memory quicker.
|
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Pushes an item to the top of the stack.
|
|||
/// </summary>
|
|||
public void Push(T item) |
|||
{ |
|||
int size = _size; |
|||
T[] array = _array; |
|||
|
|||
if ((uint)size < (uint)array.Length) |
|||
{ |
|||
array[size] = item; |
|||
_version++; |
|||
_size = size + 1; |
|||
} |
|||
else |
|||
{ |
|||
PushWithResize(item); |
|||
} |
|||
} |
|||
|
|||
// Non-inline from Stack.Push to improve its code quality as uncommon path
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
private void PushWithResize(T item) |
|||
{ |
|||
var newArray = _pool.Rent((_array.Length == 0) ? DefaultCapacity : 2 * _array.Length); |
|||
Array.Copy(_array, newArray, _size); |
|||
ReturnArray(replaceWith: newArray); |
|||
_array[_size] = item; |
|||
_version++; |
|||
_size++; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Copies the Stack to an array, in the same order Pop would return the items.
|
|||
/// </summary>
|
|||
public T[] ToArray() |
|||
{ |
|||
if (_size == 0) |
|||
return Array.Empty<T>(); |
|||
|
|||
T[] objArray = new T[_size]; |
|||
int i = 0; |
|||
while (i < _size) |
|||
{ |
|||
objArray[i] = _array[_size - i - 1]; |
|||
i++; |
|||
} |
|||
return objArray; |
|||
} |
|||
|
|||
private void ThrowForEmptyStack() |
|||
{ |
|||
Debug.Assert(_size == 0); |
|||
throw new InvalidOperationException("Stack was empty."); |
|||
} |
|||
|
|||
private void ReturnArray(T[] replaceWith = null) |
|||
{ |
|||
if (_array?.Length > 0) |
|||
{ |
|||
try |
|||
{ |
|||
_pool.Return(_array, clearArray: _clearOnFree); |
|||
} |
|||
catch (ArgumentException) |
|||
{ |
|||
// oh well, the array pool didn't like our array
|
|||
} |
|||
} |
|||
|
|||
if (!(replaceWith is null)) |
|||
{ |
|||
_array = replaceWith; |
|||
} |
|||
} |
|||
|
|||
private static bool ShouldClear(ClearMode mode) |
|||
{ |
|||
#if NETCOREAPP2_1
|
|||
return mode == ClearMode.Always |
|||
|| (mode == ClearMode.Auto && RuntimeHelpers.IsReferenceOrContainsReferences<T>()); |
|||
#else
|
|||
return mode != ClearMode.Never; |
|||
#endif
|
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
ReturnArray(replaceWith: Array.Empty<T>()); |
|||
_size = 0; |
|||
_version++; |
|||
} |
|||
|
|||
void IDeserializationCallback.OnDeserialization(object sender) |
|||
{ |
|||
// We can't serialize array pools, so deserialized PooledStacks will
|
|||
// have to use the shared pool, even if they were using a custom pool
|
|||
// before serialization.
|
|||
_pool = ArrayPool<T>.Shared; |
|||
} |
|||
|
|||
[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "not an expected scenario")] |
|||
public struct Enumerator : IEnumerator<T>, IEnumerator |
|||
{ |
|||
private readonly PooledStack<T> _stack; |
|||
private readonly int _version; |
|||
private int _index; |
|||
private T _currentElement; |
|||
|
|||
internal Enumerator(PooledStack<T> stack) |
|||
{ |
|||
_stack = stack; |
|||
_version = stack._version; |
|||
_index = -2; |
|||
_currentElement = default; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
_index = -1; |
|||
} |
|||
|
|||
public bool MoveNext() |
|||
{ |
|||
bool retval; |
|||
if (_version != _stack._version) |
|||
throw new InvalidOperationException("Collection was modified during enumeration."); |
|||
if (_index == -2) |
|||
{ // First call to enumerator.
|
|||
_index = _stack._size - 1; |
|||
retval = (_index >= 0); |
|||
if (retval) |
|||
_currentElement = _stack._array[_index]; |
|||
return retval; |
|||
} |
|||
if (_index == -1) |
|||
{ // End of enumeration.
|
|||
return false; |
|||
} |
|||
|
|||
retval = (--_index >= 0); |
|||
if (retval) |
|||
_currentElement = _stack._array[_index]; |
|||
else |
|||
_currentElement = default; |
|||
return retval; |
|||
} |
|||
|
|||
public T Current |
|||
{ |
|||
get |
|||
{ |
|||
if (_index < 0) |
|||
ThrowEnumerationNotStartedOrEnded(); |
|||
return _currentElement; |
|||
} |
|||
} |
|||
|
|||
private void ThrowEnumerationNotStartedOrEnded() |
|||
{ |
|||
Debug.Assert(_index == -1 || _index == -2); |
|||
throw new InvalidOperationException(_index == -2 ? "Enumeration was not started." : "Enumeration has ended."); |
|||
} |
|||
|
|||
object IEnumerator.Current |
|||
{ |
|||
get { return Current; } |
|||
} |
|||
|
|||
void IEnumerator.Reset() |
|||
{ |
|||
if (_version != _stack._version) |
|||
throw new InvalidOperationException("Collection was modified during enumeration."); |
|||
_index = -2; |
|||
_currentElement = default; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
// 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; |
|||
using System.Diagnostics; |
|||
|
|||
namespace Avalonia.Collections.Pooled |
|||
{ |
|||
internal sealed class StackDebugView<T> |
|||
{ |
|||
private readonly PooledStack<T> _stack; |
|||
|
|||
public StackDebugView(PooledStack<T> stack) |
|||
{ |
|||
_stack = stack ?? throw new ArgumentNullException(nameof(stack)); |
|||
} |
|||
|
|||
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] |
|||
public T[] Items |
|||
{ |
|||
get |
|||
{ |
|||
return _stack.ToArray(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,691 @@ |
|||
// 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.
|
|||
|
|||
|
|||
// This file defines an internal class used to throw exceptions in BCL code.
|
|||
// The main purpose is to reduce code size.
|
|||
//
|
|||
// The old way to throw an exception generates quite a lot IL code and assembly code.
|
|||
// Following is an example:
|
|||
// C# source
|
|||
// throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key);
|
|||
// IL code:
|
|||
// IL_0003: ldstr "key"
|
|||
// IL_0008: ldstr "ArgumentNull_Key"
|
|||
// IL_000d: call string System.Environment::GetResourceString(string)
|
|||
// IL_0012: newobj instance void System.ArgumentNullException::.ctor(string,string)
|
|||
// IL_0017: throw
|
|||
// which is 21bytes in IL.
|
|||
//
|
|||
// So we want to get rid of the ldstr and call to Environment.GetResource in IL.
|
|||
// In order to do that, I created two enums: ExceptionResource, ExceptionArgument to represent the
|
|||
// argument name and resource name in a small integer. The source code will be changed to
|
|||
// ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key, ExceptionResource.ArgumentNull_Key);
|
|||
//
|
|||
// The IL code will be 7 bytes.
|
|||
// IL_0008: ldc.i4.4
|
|||
// IL_0009: ldc.i4.4
|
|||
// IL_000a: call void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument)
|
|||
// IL_000f: ldarg.0
|
|||
//
|
|||
// This will also reduce the Jitted code size a lot.
|
|||
//
|
|||
// It is very important we do this for generic classes because we can easily generate the same code
|
|||
// multiple times for different instantiation.
|
|||
//
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.Serialization; |
|||
|
|||
namespace Avalonia.Collections.Pooled |
|||
{ |
|||
internal static class ThrowHelper |
|||
{ |
|||
internal static void ThrowArrayTypeMismatchException() |
|||
{ |
|||
throw new ArrayTypeMismatchException(); |
|||
} |
|||
|
|||
internal static void ThrowIndexOutOfRangeException() |
|||
{ |
|||
throw new IndexOutOfRangeException(); |
|||
} |
|||
|
|||
internal static void ThrowArgumentOutOfRangeException() |
|||
{ |
|||
throw new ArgumentOutOfRangeException(); |
|||
} |
|||
|
|||
internal static void ThrowArgumentException_DestinationTooShort() |
|||
{ |
|||
throw new ArgumentException("Destination too short."); |
|||
} |
|||
|
|||
internal static void ThrowArgumentException_OverlapAlignmentMismatch() |
|||
{ |
|||
throw new ArgumentException("Overlap alignment mismatch."); |
|||
} |
|||
|
|||
internal static void ThrowArgumentOutOfRange_IndexException() |
|||
{ |
|||
throw GetArgumentOutOfRangeException(ExceptionArgument.index, |
|||
ExceptionResource.ArgumentOutOfRange_Index); |
|||
} |
|||
|
|||
internal static void ThrowIndexArgumentOutOfRange_NeedNonNegNumException() |
|||
{ |
|||
throw GetArgumentOutOfRangeException(ExceptionArgument.index, |
|||
ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); |
|||
} |
|||
|
|||
internal static void ThrowValueArgumentOutOfRange_NeedNonNegNumException() |
|||
{ |
|||
throw GetArgumentOutOfRangeException(ExceptionArgument.value, |
|||
ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); |
|||
} |
|||
|
|||
internal static void ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum() |
|||
{ |
|||
throw GetArgumentOutOfRangeException(ExceptionArgument.length, |
|||
ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); |
|||
} |
|||
|
|||
internal static void ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index() |
|||
{ |
|||
throw GetArgumentOutOfRangeException(ExceptionArgument.startIndex, |
|||
ExceptionResource.ArgumentOutOfRange_Index); |
|||
} |
|||
|
|||
internal static void ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count() |
|||
{ |
|||
throw GetArgumentOutOfRangeException(ExceptionArgument.count, |
|||
ExceptionResource.ArgumentOutOfRange_Count); |
|||
} |
|||
|
|||
internal static void ThrowWrongKeyTypeArgumentException<T>(T key, Type targetType) |
|||
{ |
|||
// Generic key to move the boxing to the right hand side of throw
|
|||
throw GetWrongKeyTypeArgumentException((object)key, targetType); |
|||
} |
|||
|
|||
internal static void ThrowWrongValueTypeArgumentException<T>(T value, Type targetType) |
|||
{ |
|||
// Generic key to move the boxing to the right hand side of throw
|
|||
throw GetWrongValueTypeArgumentException((object)value, targetType); |
|||
} |
|||
|
|||
private static ArgumentException GetAddingDuplicateWithKeyArgumentException(object key) |
|||
{ |
|||
return new ArgumentException($"Error adding duplicate with key: {key}."); |
|||
} |
|||
|
|||
internal static void ThrowAddingDuplicateWithKeyArgumentException<T>(T key) |
|||
{ |
|||
// Generic key to move the boxing to the right hand side of throw
|
|||
throw GetAddingDuplicateWithKeyArgumentException((object)key); |
|||
} |
|||
|
|||
internal static void ThrowKeyNotFoundException<T>(T key) |
|||
{ |
|||
// Generic key to move the boxing to the right hand side of throw
|
|||
throw GetKeyNotFoundException((object)key); |
|||
} |
|||
|
|||
internal static void ThrowArgumentException(ExceptionResource resource) |
|||
{ |
|||
throw GetArgumentException(resource); |
|||
} |
|||
|
|||
internal static void ThrowArgumentException(ExceptionResource resource, ExceptionArgument argument) |
|||
{ |
|||
throw GetArgumentException(resource, argument); |
|||
} |
|||
|
|||
private static ArgumentNullException GetArgumentNullException(ExceptionArgument argument) |
|||
{ |
|||
return new ArgumentNullException(GetArgumentName(argument)); |
|||
} |
|||
|
|||
internal static void ThrowArgumentNullException(ExceptionArgument argument) |
|||
{ |
|||
throw GetArgumentNullException(argument); |
|||
} |
|||
|
|||
internal static void ThrowArgumentNullException(ExceptionResource resource) |
|||
{ |
|||
throw new ArgumentNullException(GetResourceString(resource)); |
|||
} |
|||
|
|||
internal static void ThrowArgumentNullException(ExceptionArgument argument, ExceptionResource resource) |
|||
{ |
|||
throw new ArgumentNullException(GetArgumentName(argument), GetResourceString(resource)); |
|||
} |
|||
|
|||
internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(GetArgumentName(argument)); |
|||
} |
|||
|
|||
internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) |
|||
{ |
|||
throw GetArgumentOutOfRangeException(argument, resource); |
|||
} |
|||
|
|||
internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, int paramNumber, ExceptionResource resource) |
|||
{ |
|||
throw GetArgumentOutOfRangeException(argument, paramNumber, resource); |
|||
} |
|||
|
|||
internal static void ThrowInvalidOperationException(ExceptionResource resource) |
|||
{ |
|||
throw GetInvalidOperationException(resource); |
|||
} |
|||
|
|||
internal static void ThrowInvalidOperationException(ExceptionResource resource, Exception e) |
|||
{ |
|||
throw new InvalidOperationException(GetResourceString(resource), e); |
|||
} |
|||
|
|||
internal static void ThrowSerializationException(ExceptionResource resource) |
|||
{ |
|||
throw new SerializationException(GetResourceString(resource)); |
|||
} |
|||
|
|||
internal static void ThrowSecurityException(ExceptionResource resource) |
|||
{ |
|||
throw new System.Security.SecurityException(GetResourceString(resource)); |
|||
} |
|||
|
|||
internal static void ThrowRankException(ExceptionResource resource) |
|||
{ |
|||
throw new RankException(GetResourceString(resource)); |
|||
} |
|||
|
|||
internal static void ThrowNotSupportedException(ExceptionResource resource) |
|||
{ |
|||
throw new NotSupportedException(GetResourceString(resource)); |
|||
} |
|||
|
|||
internal static void ThrowUnauthorizedAccessException(ExceptionResource resource) |
|||
{ |
|||
throw new UnauthorizedAccessException(GetResourceString(resource)); |
|||
} |
|||
|
|||
internal static void ThrowObjectDisposedException(string objectName, ExceptionResource resource) |
|||
{ |
|||
throw new ObjectDisposedException(objectName, GetResourceString(resource)); |
|||
} |
|||
|
|||
internal static void ThrowObjectDisposedException(ExceptionResource resource) |
|||
{ |
|||
throw new ObjectDisposedException(null, GetResourceString(resource)); |
|||
} |
|||
|
|||
internal static void ThrowNotSupportedException() |
|||
{ |
|||
throw new NotSupportedException(); |
|||
} |
|||
|
|||
internal static void ThrowAggregateException(List<Exception> exceptions) |
|||
{ |
|||
throw new AggregateException(exceptions); |
|||
} |
|||
|
|||
internal static void ThrowOutOfMemoryException() |
|||
{ |
|||
throw new OutOfMemoryException(); |
|||
} |
|||
|
|||
internal static void ThrowArgumentException_Argument_InvalidArrayType() |
|||
{ |
|||
throw new ArgumentException("Invalid array type."); |
|||
} |
|||
|
|||
internal static void ThrowInvalidOperationException_InvalidOperation_EnumNotStarted() |
|||
{ |
|||
throw new InvalidOperationException("Enumeration has not started."); |
|||
} |
|||
|
|||
internal static void ThrowInvalidOperationException_InvalidOperation_EnumEnded() |
|||
{ |
|||
throw new InvalidOperationException("Enumeration has ended."); |
|||
} |
|||
|
|||
internal static void ThrowInvalidOperationException_EnumCurrent(int index) |
|||
{ |
|||
throw GetInvalidOperationException_EnumCurrent(index); |
|||
} |
|||
|
|||
internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion() |
|||
{ |
|||
throw new InvalidOperationException("Collection was modified during enumeration."); |
|||
} |
|||
|
|||
internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen() |
|||
{ |
|||
throw new InvalidOperationException("Invalid enumerator state: enumeration cannot proceed."); |
|||
} |
|||
|
|||
internal static void ThrowInvalidOperationException_InvalidOperation_NoValue() |
|||
{ |
|||
throw new InvalidOperationException("No value provided."); |
|||
} |
|||
|
|||
internal static void ThrowInvalidOperationException_ConcurrentOperationsNotSupported() |
|||
{ |
|||
throw new InvalidOperationException("Concurrent operations are not supported."); |
|||
} |
|||
|
|||
internal static void ThrowInvalidOperationException_HandleIsNotInitialized() |
|||
{ |
|||
throw new InvalidOperationException("Handle is not initialized."); |
|||
} |
|||
|
|||
internal static void ThrowFormatException_BadFormatSpecifier() |
|||
{ |
|||
throw new FormatException("Bad format specifier."); |
|||
} |
|||
|
|||
private static ArgumentException GetArgumentException(ExceptionResource resource) |
|||
{ |
|||
return new ArgumentException(GetResourceString(resource)); |
|||
} |
|||
|
|||
private static InvalidOperationException GetInvalidOperationException(ExceptionResource resource) |
|||
{ |
|||
return new InvalidOperationException(GetResourceString(resource)); |
|||
} |
|||
|
|||
private static ArgumentException GetWrongKeyTypeArgumentException(object key, Type targetType) |
|||
{ |
|||
return new ArgumentException($"Wrong key type. Expected {targetType}, got: '{key}'.", nameof(key)); |
|||
} |
|||
|
|||
private static ArgumentException GetWrongValueTypeArgumentException(object value, Type targetType) |
|||
{ |
|||
return new ArgumentException($"Wrong value type. Expected {targetType}, got: '{value}'.", nameof(value)); |
|||
} |
|||
|
|||
private static KeyNotFoundException GetKeyNotFoundException(object key) |
|||
{ |
|||
return new KeyNotFoundException($"Key not found: {key}"); |
|||
} |
|||
|
|||
private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) |
|||
{ |
|||
return new ArgumentOutOfRangeException(GetArgumentName(argument), GetResourceString(resource)); |
|||
} |
|||
|
|||
private static ArgumentException GetArgumentException(ExceptionResource resource, ExceptionArgument argument) |
|||
{ |
|||
return new ArgumentException(GetResourceString(resource), GetArgumentName(argument)); |
|||
} |
|||
|
|||
private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(ExceptionArgument argument, int paramNumber, ExceptionResource resource) |
|||
{ |
|||
return new ArgumentOutOfRangeException(GetArgumentName(argument) + "[" + paramNumber.ToString() + "]", GetResourceString(resource)); |
|||
} |
|||
|
|||
private static InvalidOperationException GetInvalidOperationException_EnumCurrent(int index) |
|||
{ |
|||
return new InvalidOperationException( |
|||
index < 0 ? |
|||
"Enumeration has not started" : |
|||
"Enumeration has ended"); |
|||
} |
|||
|
|||
// Allow nulls for reference types and Nullable<U>, but not for value types.
|
|||
// Aggressively inline so the jit evaluates the if in place and either drops the call altogether
|
|||
// Or just leaves null test and call to the Non-returning ThrowHelper.ThrowArgumentNullException
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal static void IfNullAndNullsAreIllegalThenThrow<T>(object value, ExceptionArgument argName) |
|||
{ |
|||
// Note that default(T) is not equal to null for value types except when T is Nullable<U>.
|
|||
if (!(default(T) == null) && value == null) |
|||
ThrowHelper.ThrowArgumentNullException(argName); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal static void ThrowForUnsupportedVectorBaseType<T>() where T : struct |
|||
{ |
|||
if (typeof(T) != typeof(byte) && typeof(T) != typeof(sbyte) && |
|||
typeof(T) != typeof(short) && typeof(T) != typeof(ushort) && |
|||
typeof(T) != typeof(int) && typeof(T) != typeof(uint) && |
|||
typeof(T) != typeof(long) && typeof(T) != typeof(ulong) && |
|||
typeof(T) != typeof(float) && typeof(T) != typeof(double)) |
|||
{ |
|||
ThrowNotSupportedException(ExceptionResource.Arg_TypeNotSupported); |
|||
} |
|||
} |
|||
|
|||
#if false // Reflection-based implementation does not work for CoreRT/ProjectN
|
|||
// This function will convert an ExceptionArgument enum value to the argument name string.
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
private static string GetArgumentName(ExceptionArgument argument) |
|||
{ |
|||
Debug.Assert(Enum.IsDefined(typeof(ExceptionArgument), argument), |
|||
"The enum value is not defined, please check the ExceptionArgument Enum."); |
|||
|
|||
return argument.ToString(); |
|||
} |
|||
#endif
|
|||
|
|||
private static string GetArgumentName(ExceptionArgument argument) |
|||
{ |
|||
switch (argument) |
|||
{ |
|||
case ExceptionArgument.obj: |
|||
return "obj"; |
|||
case ExceptionArgument.dictionary: |
|||
return "dictionary"; |
|||
case ExceptionArgument.array: |
|||
return "array"; |
|||
case ExceptionArgument.info: |
|||
return "info"; |
|||
case ExceptionArgument.key: |
|||
return "key"; |
|||
case ExceptionArgument.text: |
|||
return "text"; |
|||
case ExceptionArgument.values: |
|||
return "values"; |
|||
case ExceptionArgument.value: |
|||
return "value"; |
|||
case ExceptionArgument.startIndex: |
|||
return "startIndex"; |
|||
case ExceptionArgument.task: |
|||
return "task"; |
|||
case ExceptionArgument.ch: |
|||
return "ch"; |
|||
case ExceptionArgument.s: |
|||
return "s"; |
|||
case ExceptionArgument.input: |
|||
return "input"; |
|||
case ExceptionArgument.list: |
|||
return "list"; |
|||
case ExceptionArgument.index: |
|||
return "index"; |
|||
case ExceptionArgument.capacity: |
|||
return "capacity"; |
|||
case ExceptionArgument.collection: |
|||
return "collection"; |
|||
case ExceptionArgument.item: |
|||
return "item"; |
|||
case ExceptionArgument.converter: |
|||
return "converter"; |
|||
case ExceptionArgument.match: |
|||
return "match"; |
|||
case ExceptionArgument.count: |
|||
return "count"; |
|||
case ExceptionArgument.action: |
|||
return "action"; |
|||
case ExceptionArgument.comparison: |
|||
return "comparison"; |
|||
case ExceptionArgument.exceptions: |
|||
return "exceptions"; |
|||
case ExceptionArgument.exception: |
|||
return "exception"; |
|||
case ExceptionArgument.enumerable: |
|||
return "enumerable"; |
|||
case ExceptionArgument.start: |
|||
return "start"; |
|||
case ExceptionArgument.format: |
|||
return "format"; |
|||
case ExceptionArgument.culture: |
|||
return "culture"; |
|||
case ExceptionArgument.comparer: |
|||
return "comparer"; |
|||
case ExceptionArgument.comparable: |
|||
return "comparable"; |
|||
case ExceptionArgument.source: |
|||
return "source"; |
|||
case ExceptionArgument.state: |
|||
return "state"; |
|||
case ExceptionArgument.length: |
|||
return "length"; |
|||
case ExceptionArgument.comparisonType: |
|||
return "comparisonType"; |
|||
case ExceptionArgument.manager: |
|||
return "manager"; |
|||
case ExceptionArgument.sourceBytesToCopy: |
|||
return "sourceBytesToCopy"; |
|||
case ExceptionArgument.callBack: |
|||
return "callBack"; |
|||
case ExceptionArgument.creationOptions: |
|||
return "creationOptions"; |
|||
case ExceptionArgument.function: |
|||
return "function"; |
|||
case ExceptionArgument.delay: |
|||
return "delay"; |
|||
case ExceptionArgument.millisecondsDelay: |
|||
return "millisecondsDelay"; |
|||
case ExceptionArgument.millisecondsTimeout: |
|||
return "millisecondsTimeout"; |
|||
case ExceptionArgument.timeout: |
|||
return "timeout"; |
|||
case ExceptionArgument.type: |
|||
return "type"; |
|||
case ExceptionArgument.sourceIndex: |
|||
return "sourceIndex"; |
|||
case ExceptionArgument.sourceArray: |
|||
return "sourceArray"; |
|||
case ExceptionArgument.destinationIndex: |
|||
return "destinationIndex"; |
|||
case ExceptionArgument.destinationArray: |
|||
return "destinationArray"; |
|||
case ExceptionArgument.other: |
|||
return "other"; |
|||
case ExceptionArgument.newSize: |
|||
return "newSize"; |
|||
case ExceptionArgument.lowerBounds: |
|||
return "lowerBounds"; |
|||
case ExceptionArgument.lengths: |
|||
return "lengths"; |
|||
case ExceptionArgument.len: |
|||
return "len"; |
|||
case ExceptionArgument.keys: |
|||
return "keys"; |
|||
case ExceptionArgument.indices: |
|||
return "indices"; |
|||
case ExceptionArgument.endIndex: |
|||
return "endIndex"; |
|||
case ExceptionArgument.elementType: |
|||
return "elementType"; |
|||
case ExceptionArgument.arrayIndex: |
|||
return "arrayIndex"; |
|||
default: |
|||
Debug.Fail("The enum value is not defined, please check the ExceptionArgument Enum."); |
|||
return argument.ToString(); |
|||
} |
|||
} |
|||
|
|||
#if false // Reflection-based implementation does not work for CoreRT/ProjectN
|
|||
// This function will convert an ExceptionResource enum value to the resource string.
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
private static string GetResourceString(ExceptionResource resource) |
|||
{ |
|||
Debug.Assert(Enum.IsDefined(typeof(ExceptionResource), resource), |
|||
"The enum value is not defined, please check the ExceptionResource Enum."); |
|||
|
|||
return SR.GetResourceString(resource.ToString()); |
|||
} |
|||
#endif
|
|||
|
|||
private static string GetResourceString(ExceptionResource resource) |
|||
{ |
|||
switch (resource) |
|||
{ |
|||
case ExceptionResource.ArgumentOutOfRange_Index: |
|||
return "Argument 'index' was out of the range of valid values."; |
|||
case ExceptionResource.ArgumentOutOfRange_Count: |
|||
return "Argument 'count' was out of the range of valid values."; |
|||
case ExceptionResource.Arg_ArrayPlusOffTooSmall: |
|||
return "Array plus offset too small."; |
|||
case ExceptionResource.NotSupported_ReadOnlyCollection: |
|||
return "This operation is not supported on a read-only collection."; |
|||
case ExceptionResource.Arg_RankMultiDimNotSupported: |
|||
return "Multi-dimensional arrays are not supported."; |
|||
case ExceptionResource.Arg_NonZeroLowerBound: |
|||
return "Arrays with a non-zero lower bound are not supported."; |
|||
case ExceptionResource.ArgumentOutOfRange_ListInsert: |
|||
return "Insertion index was out of the range of valid values."; |
|||
case ExceptionResource.ArgumentOutOfRange_NeedNonNegNum: |
|||
return "The number must be non-negative."; |
|||
case ExceptionResource.ArgumentOutOfRange_SmallCapacity: |
|||
return "The capacity cannot be set below the current Count."; |
|||
case ExceptionResource.Argument_InvalidOffLen: |
|||
return "Invalid offset length."; |
|||
case ExceptionResource.ArgumentOutOfRange_BiggerThanCollection: |
|||
return "The given value was larger than the size of the collection."; |
|||
case ExceptionResource.Serialization_MissingKeys: |
|||
return "Serialization error: missing keys."; |
|||
case ExceptionResource.Serialization_NullKey: |
|||
return "Serialization error: null key."; |
|||
case ExceptionResource.NotSupported_KeyCollectionSet: |
|||
return "The KeyCollection does not support modification."; |
|||
case ExceptionResource.NotSupported_ValueCollectionSet: |
|||
return "The ValueCollection does not support modification."; |
|||
case ExceptionResource.InvalidOperation_NullArray: |
|||
return "Null arrays are not supported."; |
|||
case ExceptionResource.InvalidOperation_HSCapacityOverflow: |
|||
return "Set hash capacity overflow. Cannot increase size."; |
|||
case ExceptionResource.NotSupported_StringComparison: |
|||
return "String comparison not supported."; |
|||
case ExceptionResource.ConcurrentCollection_SyncRoot_NotSupported: |
|||
return "SyncRoot not supported."; |
|||
case ExceptionResource.ArgumentException_OtherNotArrayOfCorrectLength: |
|||
return "The other array is not of the correct length."; |
|||
case ExceptionResource.ArgumentOutOfRange_EndIndexStartIndex: |
|||
return "The end index does not come after the start index."; |
|||
case ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported: |
|||
return "Huge arrays are not supported."; |
|||
case ExceptionResource.Argument_AddingDuplicate: |
|||
return "Duplicate item added."; |
|||
case ExceptionResource.Argument_InvalidArgumentForComparison: |
|||
return "Invalid argument for comparison."; |
|||
case ExceptionResource.Arg_LowerBoundsMustMatch: |
|||
return "Array lower bounds must match."; |
|||
case ExceptionResource.Arg_MustBeType: |
|||
return "Argument must be of type: "; |
|||
case ExceptionResource.InvalidOperation_IComparerFailed: |
|||
return "IComparer failed."; |
|||
case ExceptionResource.NotSupported_FixedSizeCollection: |
|||
return "This operation is not suppored on a fixed-size collection."; |
|||
case ExceptionResource.Rank_MultiDimNotSupported: |
|||
return "Multi-dimensional arrays are not supported."; |
|||
case ExceptionResource.Arg_TypeNotSupported: |
|||
return "Type not supported."; |
|||
default: |
|||
Debug.Assert(false, |
|||
"The enum value is not defined, please check the ExceptionResource Enum."); |
|||
return resource.ToString(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
//
|
|||
// The convention for this enum is using the argument name as the enum name
|
|||
//
|
|||
internal enum ExceptionArgument |
|||
{ |
|||
obj, |
|||
dictionary, |
|||
array, |
|||
info, |
|||
key, |
|||
text, |
|||
values, |
|||
value, |
|||
startIndex, |
|||
task, |
|||
ch, |
|||
s, |
|||
input, |
|||
list, |
|||
index, |
|||
capacity, |
|||
collection, |
|||
item, |
|||
converter, |
|||
match, |
|||
count, |
|||
action, |
|||
comparison, |
|||
exceptions, |
|||
exception, |
|||
enumerable, |
|||
start, |
|||
format, |
|||
culture, |
|||
comparer, |
|||
comparable, |
|||
source, |
|||
state, |
|||
length, |
|||
comparisonType, |
|||
manager, |
|||
sourceBytesToCopy, |
|||
callBack, |
|||
creationOptions, |
|||
function, |
|||
delay, |
|||
millisecondsDelay, |
|||
millisecondsTimeout, |
|||
timeout, |
|||
type, |
|||
sourceIndex, |
|||
sourceArray, |
|||
destinationIndex, |
|||
destinationArray, |
|||
other, |
|||
newSize, |
|||
lowerBounds, |
|||
lengths, |
|||
len, |
|||
keys, |
|||
indices, |
|||
endIndex, |
|||
elementType, |
|||
arrayIndex |
|||
} |
|||
|
|||
//
|
|||
// The convention for this enum is using the resource name as the enum name
|
|||
//
|
|||
internal enum ExceptionResource |
|||
{ |
|||
ArgumentOutOfRange_Index, |
|||
ArgumentOutOfRange_Count, |
|||
Arg_ArrayPlusOffTooSmall, |
|||
NotSupported_ReadOnlyCollection, |
|||
Arg_RankMultiDimNotSupported, |
|||
Arg_NonZeroLowerBound, |
|||
ArgumentOutOfRange_ListInsert, |
|||
ArgumentOutOfRange_NeedNonNegNum, |
|||
ArgumentOutOfRange_SmallCapacity, |
|||
Argument_InvalidOffLen, |
|||
ArgumentOutOfRange_BiggerThanCollection, |
|||
Serialization_MissingKeys, |
|||
Serialization_NullKey, |
|||
NotSupported_KeyCollectionSet, |
|||
NotSupported_ValueCollectionSet, |
|||
InvalidOperation_NullArray, |
|||
InvalidOperation_HSCapacityOverflow, |
|||
NotSupported_StringComparison, |
|||
ConcurrentCollection_SyncRoot_NotSupported, |
|||
ArgumentException_OtherNotArrayOfCorrectLength, |
|||
ArgumentOutOfRange_EndIndexStartIndex, |
|||
ArgumentOutOfRange_HugeArrayNotSupported, |
|||
Argument_AddingDuplicate, |
|||
Argument_InvalidArgumentForComparison, |
|||
Arg_LowerBoundsMustMatch, |
|||
Arg_MustBeType, |
|||
InvalidOperation_IComparerFailed, |
|||
NotSupported_FixedSizeCollection, |
|||
Rank_MultiDimNotSupported, |
|||
Arg_TypeNotSupported, |
|||
} |
|||
} |
|||
Loading…
Reference in new issue