From 91dd5a9940a17ecd42e1f9da8df3ad97709bc83a Mon Sep 17 00:00:00 2001 From: rameel Date: Tue, 29 Apr 2025 01:42:15 +0500 Subject: [PATCH] Use standard List`1 instead of custom ArrayList`1 --- .../Collections/ArrayListDebugView.cs | 14 - .../Collections/ArrayList`1.cs | 382 ------------------ src/Ramstack.Parsing/Parser.Choice.cs | 2 +- src/Ramstack.Parsing/Parser.Repeat.cs | 32 +- src/Ramstack.Parsing/Parser.Separated.cs | 8 +- src/Ramstack.Parsing/Parser.Set.cs | 2 +- src/Ramstack.Parsing/Parser.Until.cs | 10 +- src/Ramstack.Parsing/Ramstack.Parsing.csproj | 2 +- src/Ramstack.Parsing/Utilities/ListFactory.cs | 68 ++++ .../Collections/ArrayListTests.cs | 345 ---------------- .../Scenarios/SimpleCalcTests.cs | 4 +- 11 files changed, 98 insertions(+), 771 deletions(-) delete mode 100644 src/Ramstack.Parsing/Collections/ArrayListDebugView.cs delete mode 100644 src/Ramstack.Parsing/Collections/ArrayList`1.cs create mode 100644 src/Ramstack.Parsing/Utilities/ListFactory.cs delete mode 100644 tests/Ramstack.Parsing.Tests/Collections/ArrayListTests.cs diff --git a/src/Ramstack.Parsing/Collections/ArrayListDebugView.cs b/src/Ramstack.Parsing/Collections/ArrayListDebugView.cs deleted file mode 100644 index 0046762..0000000 --- a/src/Ramstack.Parsing/Collections/ArrayListDebugView.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ramstack.Parsing.Collections; - -/// -/// Represents a debugger view for the structure. -/// -/// The type of items in the . -internal sealed class ArrayListDebugView(ArrayList list) -{ - /// - /// Gets the array of items contained in the . - /// - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public T[] Items => list.ToArray(); -} diff --git a/src/Ramstack.Parsing/Collections/ArrayList`1.cs b/src/Ramstack.Parsing/Collections/ArrayList`1.cs deleted file mode 100644 index 19db9bc..0000000 --- a/src/Ramstack.Parsing/Collections/ArrayList`1.cs +++ /dev/null @@ -1,382 +0,0 @@ -using System.Collections; - -namespace Ramstack.Parsing.Collections; - -/// -/// Represents a strongly typed list of objects that can be accessed by index. -/// -/// The type of elements in the list. -[DebuggerDisplay("Count = {Count}")] -[DebuggerTypeProxy(typeof(ArrayListDebugView<>))] -public sealed class ArrayList : IList, IReadOnlyList -{ - private T[] _array; - private int _count; - - /// - /// Gets the number of items contained in the . - /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public int Count => _count; - - /// - /// Gets an item at the specified index. - /// - /// The zero-based index of the item to get. - public ref T this[int index] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - var array = _array; - var count = _count; - - if ((uint)index >= (uint)count) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - return ref Unsafe.Add( - ref MemoryMarshal.GetArrayDataReference(array), - (nint)(uint)index); - } - } - - /// - /// Initializes a new instance of the . - /// - public ArrayList() - { - _count = 0; - _array = []; - } - - /// - /// Initializes a new instance of the with the specified buffer capacity. - /// - /// The initial capacity of the buffer. - public ArrayList(int capacity) - { - _count = 0; - _array = new T[capacity]; - } - - /// - /// Initializes a new instance of the class that contains elements copied - /// from the specified span and has sufficient capacity to accommodate the number of elements copied. - /// - /// The collection whose elements are copied to the new list. - public ArrayList(ReadOnlySpan collection) - { - _count = collection.Length; - _array = collection.ToArray(); - } - - /// - public int IndexOf(T item) => - Array.IndexOf(_array, item, 0, _count); - - /// - public bool Contains(T item) => - IndexOf(item) >= 0; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(T item) - { - var array = _array; - var count = _count; - - if ((uint)count < (uint)array.Length) - { - array[count] = item; - _count = count + 1; - } - else - { - AddSlow(item); - } - } - - /// - /// Adds the items of the specified span to the end of the list. - /// - /// The readonly span of items to add. - public void AddRange(ReadOnlySpan collection) - { - var array = _array; - var count = _count; - - if (array.Length - count < collection.Length) - array = Grow(checked(count + collection.Length)); - - _count = count + collection.Length; - _ = array.Length; - collection.TryCopyTo(array.AsSpan(count)); - } - - /// - public void Insert(int index, T item) - { - var count = _count; - var array = _array; - - Argument.ThrowIfGreaterThan((uint)index, (uint)count); - - if (count == array.Length) - array = Grow(index); - - Array.Copy( - sourceArray: array, - sourceIndex: index, - destinationArray: array, - destinationIndex: index + 1, - length: count - index); - - _count = count + 1; - - if ((uint)index < (uint)array.Length) - array[index] = item; - } - - /// - public bool Remove(T item) - { - var index = IndexOf(item); - if (index >= 0) - { - RemoveAt(index); - return true; - } - - return false; - } - - /// - public void RemoveAt(int index) - { - Argument.ThrowIfGreaterThanOrEqual((uint)index, (uint)_count); - - if (index < --_count) - Array.Copy( - sourceArray: _array, - sourceIndex: index + 1, - destinationArray: _array, - destinationIndex: index, - length: _count - index); - - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - _array[_count] = default!; - } - - /// - /// Removes all elements from the . - /// - public void Clear() - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - { - _count = ClearImpl(_array, _count); - - [MethodImpl(MethodImplOptions.NoInlining)] - static int ClearImpl(T[] array, int count) - { - if ((uint)count <= (uint)array.Length) - array.AsSpan(0, count).Clear(); - - return 0; - } - } - else - { - _count = 0; - } - } - - /// - /// Copies the contents of this list into a destination . - /// - /// The destination object. - public void CopyTo(Span destination) => - AsSpan().CopyTo(destination); - - /// - /// Attempts to copy the current list to a destination - /// and returns a value that indicates whether the copy operation succeeded. - /// - /// The destination object. - /// - /// if copy operations succeeded; otherwise, . - /// - public bool TryCopyTo(Span destination) => - AsSpan().TryCopyTo(destination); - - /// - /// Returns an enumerator that iterates through the . - /// - /// - /// A for the . - /// - public Enumerator GetEnumerator() => - new Enumerator(this); - - /// - /// Returns a representing the written data of the current instance. - /// - /// - /// A that represents the data within the current instance. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() - { - var array = _array; - var count = _count; - _ = array.Length; - - return MemoryMarshal.CreateSpan( - ref MemoryMarshal.GetArrayDataReference(array), - count); - } - - /// - /// Copies the elements of the to a new array. - /// - /// - /// An array containing copies of the elements of the . - /// - public T[] ToArray() => - AsSpan().ToArray(); - - #region Explicit interface implementations - - /// - T IList.this[int index] - { - get => this[index]; - set => this[index] = value; - } - - /// - T IReadOnlyList.this[int index] => this[index]; - - /// - bool ICollection.IsReadOnly => false; - - /// - void ICollection.CopyTo(T[] array, int arrayIndex) => - AsSpan().CopyTo(array.AsSpan(arrayIndex)); - - /// - IEnumerator IEnumerable.GetEnumerator() => - GetEnumerator(); - - /// - IEnumerator IEnumerable.GetEnumerator() => - GetEnumerator(); - - #endregion - - [MethodImpl(MethodImplOptions.NoInlining)] - private void AddSlow(T item) - { - var array = Grow(1); - var count = _count; - - if ((uint)count < (uint)array.Length) - array[count] = item; - - _count = count + 1; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private T[] Grow(int extra) - { - var array = _array; - - // ReSharper disable once RedundantOverflowCheckingContext - var required = checked(array.Length + extra); - var capacity = array.Length != 0 ? array.Length * 2 : 4; - - if ((uint)capacity > (uint)Array.MaxLength) - capacity = Array.MaxLength; - - if (capacity < required) - capacity = required; - - var destination = new T[capacity]; - array.AsSpan().TryCopyTo(destination); - - _array = destination; - return destination; - } - - #region Inner type: Enumerator - - /// - /// Enumerates the items of a . - /// - public struct Enumerator : IEnumerator - { - private readonly T[] _array; - private readonly int _count; - private int _index; - - /// - /// Gets the item at the current position of the enumerator. - /// - public readonly ref readonly T Current - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - if ((uint)_index >= (uint)_count) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - Debug.Assert((uint)_index < (uint)_array.Length); - - return ref Unsafe.Add( - ref MemoryMarshal.GetArrayDataReference(_array), - (nint)(uint)_index); - } - } - - /// - /// Initializes a new instance of the structure. - /// - /// The list to initialize from. - internal Enumerator(ArrayList list) - { - _index = -1; - _count = list._count; - _array = list._array; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => - (uint)++_index < (uint)_count; - - /// - public void Reset() => - _index = -1; - - /// - T IEnumerator.Current - { - get - { - if ((uint)_index >= (uint)_count) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - return _array[_index]; - } - } - - /// - object? IEnumerator.Current => Current; - - /// - public void Dispose() => - _index = -1; - } - - #endregion -} diff --git a/src/Ramstack.Parsing/Parser.Choice.cs b/src/Ramstack.Parsing/Parser.Choice.cs index 4992eeb..bb4e4b2 100644 --- a/src/Ramstack.Parsing/Parser.Choice.cs +++ b/src/Ramstack.Parsing/Parser.Choice.cs @@ -16,7 +16,7 @@ public static Parser Choice(params Parser[] parsers) { Argument.ThrowIfNullOrEmpty(parsers); - var list = new ArrayList>(); + var list = new List>(); while (true) { diff --git a/src/Ramstack.Parsing/Parser.Repeat.cs b/src/Ramstack.Parsing/Parser.Repeat.cs index 3bd8e41..eda211c 100644 --- a/src/Ramstack.Parsing/Parser.Repeat.cs +++ b/src/Ramstack.Parsing/Parser.Repeat.cs @@ -15,7 +15,7 @@ partial class Parser /// /// A parser that applies the specified parser zero or more times. /// - public static Parser> ZeroOrMore(this Parser parser) => + public static Parser> ZeroOrMore(this Parser parser) => Repeat(parser, 0, int.MaxValue); /// @@ -36,7 +36,7 @@ public static Parser ZeroOrMore(this Parser parser) => /// /// A parser that applies the specified parser at least once. /// - public static Parser> OneOrMore(this Parser parser) => + public static Parser> OneOrMore(this Parser parser) => Repeat(parser, 1, int.MaxValue); /// @@ -57,7 +57,7 @@ public static Parser OneOrMore(this Parser parser) => /// /// A parser that applies the specified parser zero or more times. /// - public static Parser> Many(this Parser parser) => + public static Parser> Many(this Parser parser) => Repeat(parser, 0, int.MaxValue); /// @@ -79,7 +79,7 @@ public static Parser Many(this Parser parser) => /// /// A parser that applies the specified parser at least a defined number of times. /// - public static Parser> AtLeast(this Parser parser, int count) => + public static Parser> AtLeast(this Parser parser, int count) => Repeat(parser, count, int.MaxValue); /// @@ -102,7 +102,7 @@ public static Parser AtLeast(this Parser parser, int count) => /// /// A parser that applies the specified parser a defined number of times. /// - public static Parser> Repeat(this Parser parser, int count) => + public static Parser> Repeat(this Parser parser, int count) => Repeat(parser, count, count); /// @@ -126,14 +126,14 @@ public static Parser Repeat(this Parser parser, int count) => /// /// A parser that applies the specified parser a defined number of times. /// - public static Parser> Repeat(this Parser parser, int min, int max) + public static Parser> Repeat(this Parser parser, int min, int max) { Argument.ThrowIfNegative(min); Argument.ThrowIfNegativeOrZero(max); Argument.ThrowIfGreaterThan(min, max); return parser is ICharClassSupport s - ? (Parser>)(object)CreateRepeatParser(s.GetCharClass(), min, max) + ? (Parser>)(object)CreateRepeatParser(s.GetCharClass(), min, max) : new RepeatParser(parser, min, max); } @@ -157,7 +157,7 @@ public static Parser Repeat(this Parser parser, int min, int max) : new VoidRepeatParser(parser, min, max); } - private static Parser> CreateRepeatParser(CharClass @class, int min, int max) + private static Parser> CreateRepeatParser(CharClass @class, int min, int max) { if (@class.Ranges.Length == 0) @class = @class.EnrichRanges(); @@ -207,7 +207,7 @@ private static Parser> CreateRepeatParser(CharClass @class, int new BitVectorSearcher(ranges), @class.UnicodeCategories, min, max) { Name = errors }; - var list = new ArrayList<(int comparisons, int consumption, Parser> parser)>(); + var list = new List<(int comparisons, int consumption, Parser> parser)>(); if (true) { @@ -294,7 +294,7 @@ private static Parser> CreateRepeatParser(CharClass @class, int /// Represents a parser that applies the specified parser a defined number of times. /// /// The type of the value produced by the specified parser. - private sealed class RepeatParser : Parser> + private sealed class RepeatParser : Parser> { private readonly Parser _parser; private readonly int _min; @@ -310,9 +310,9 @@ public RepeatParser(Parser parser, int min, int max) => (_parser, _min, _max) = (parser, min, max); /// - public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out ArrayList? value) + public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out List? value) { - var list = new ArrayList(); + var list = new List(); var bookmark = context.BookmarkPosition(); var parser = _parser; @@ -423,7 +423,7 @@ public override bool TryParse(ref ParseContext context, out Unit value) #region Inner type: RepeatCharClassParser - private sealed class RepeatCharClassParser : Parser> where TSearcher : struct, ICharClassRangeSearcher + private sealed class RepeatCharClassParser : Parser> where TSearcher : struct, ICharClassRangeSearcher { private TSearcher _searcher; private readonly CharClassUnicodeCategory _categories; @@ -441,7 +441,7 @@ public RepeatCharClassParser(TSearcher searcher, CharClassUnicodeCategory catego } /// - public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out ArrayList? value) + public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out List? value) { value = null; @@ -484,7 +484,7 @@ ref Unsafe.Add(ref MemoryMarshal.GetReference(s), (nint)(uint)index), count = Math.Min(count, _max); context.Advance(count); - value = new ArrayList(context.MatchedSegment); + value = ListFactory.CreateList(context.MatchedSegment); } else { @@ -495,7 +495,7 @@ ref Unsafe.Add(ref MemoryMarshal.GetReference(s), (nint)(uint)index), } /// - protected internal override Parser> ToNamedParser(string? name) => + protected internal override Parser> ToNamedParser(string? name) => new RepeatCharClassParser(_searcher, _categories, _min, _max) { Name = name }; /// diff --git a/src/Ramstack.Parsing/Parser.Separated.cs b/src/Ramstack.Parsing/Parser.Separated.cs index a0be11b..bf5df24 100644 --- a/src/Ramstack.Parsing/Parser.Separated.cs +++ b/src/Ramstack.Parsing/Parser.Separated.cs @@ -15,7 +15,7 @@ partial class Parser /// /// /// A parser that repeatedly applies the main parser, interleaved with the specified separator. /// - public static Parser> Separated(this Parser parser, Parser separator, bool allowTrailing = false, int min = 0, int max = int.MaxValue) => + public static Parser> Separated(this Parser parser, Parser separator, bool allowTrailing = false, int min = 0, int max = int.MaxValue) => new SeparatedParser(parser, separator.Void(), allowTrailing, min, max); #region Inner type: SeparatedParser @@ -29,12 +29,12 @@ public static Parser> Separated(this Parser parse /// if trailing separator is allowed; otherwise, . /// The minimum number of repetitions. /// The maximum number of repetitions. - private sealed class SeparatedParser(Parser parser, Parser separator, bool allowTrailing, int min, int max) : Parser> + private sealed class SeparatedParser(Parser parser, Parser separator, bool allowTrailing, int min, int max) : Parser> { /// - public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out ArrayList? value) + public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out List? value) { - var list = new ArrayList(); + var list = new List(); var bookmark = context.BookmarkPosition(); var separatorBookmark = bookmark; diff --git a/src/Ramstack.Parsing/Parser.Set.cs b/src/Ramstack.Parsing/Parser.Set.cs index e72c21d..b1ac036 100644 --- a/src/Ramstack.Parsing/Parser.Set.cs +++ b/src/Ramstack.Parsing/Parser.Set.cs @@ -144,7 +144,7 @@ internal static Parser Set(CharClass @class) new BitVectorSearcher(ranges), categories) { Name = name }; - var list = new ArrayList<(int comparisons, int consumption, Parser parser)>(); + var list = new List<(int comparisons, int consumption, Parser parser)>(); if (true) { diff --git a/src/Ramstack.Parsing/Parser.Until.cs b/src/Ramstack.Parsing/Parser.Until.cs index df9ffe1..21ad72f 100644 --- a/src/Ramstack.Parsing/Parser.Until.cs +++ b/src/Ramstack.Parsing/Parser.Until.cs @@ -14,7 +14,7 @@ partial class Parser /// A parser that applies zero or more times, stopping when /// succeeds, and returns an array of the results produced by . /// - public static Parser> Until(this Parser parser, Parser terminator) => + public static Parser> Until(this Parser parser, Parser terminator) => new UntilParser(parser, terminator.Void()); /// @@ -28,7 +28,7 @@ public static Parser> Until(this Parser parser, /// A parser that applies zero or more times, stopping when /// succeeds, and returns an array of the results produced by . /// - public static Parser> Until(this Parser parser, Parser terminator) => + public static Parser> Until(this Parser parser, Parser terminator) => new UntilParser(parser, terminator); #region Inner type: UntilParser @@ -39,14 +39,14 @@ public static Parser> Until(this Parser parser, Parser /// /// The main parser to apply repeatedly. /// The parser that determines when to stop. - private sealed class UntilParser(Parser parser, Parser terminator) : Parser> + private sealed class UntilParser(Parser parser, Parser terminator) : Parser> { private readonly Parser _isTerminator = And(terminator); /// - public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out ArrayList? value) + public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out List? value) { - var list = new ArrayList(); + var list = new List(); var bookmark = context.BookmarkPosition(); while (true) diff --git a/src/Ramstack.Parsing/Ramstack.Parsing.csproj b/src/Ramstack.Parsing/Ramstack.Parsing.csproj index 61b19cd..4b1885a 100644 --- a/src/Ramstack.Parsing/Ramstack.Parsing.csproj +++ b/src/Ramstack.Parsing/Ramstack.Parsing.csproj @@ -1,7 +1,7 @@ - net6.0;net7.0;net8.0 + net6.0;net7.0;net8.0;net9.0 A blazing-fast, lightweight, and intuitive parser combinator library for .NET enable enable diff --git a/src/Ramstack.Parsing/Utilities/ListFactory.cs b/src/Ramstack.Parsing/Utilities/ListFactory.cs new file mode 100644 index 0000000..eb37654 --- /dev/null +++ b/src/Ramstack.Parsing/Utilities/ListFactory.cs @@ -0,0 +1,68 @@ +namespace Ramstack.Parsing.Utilities; + +/// +/// Represents the helper class responsible for creating instances +/// with optimized initialization based on the target framework version. +/// +/// The type of the elements in the list. +internal static class ListFactory +{ + /// + /// Creates a new initialized with the elements from the specified . + /// + /// The span of items to populate the list with. + /// + /// A new containing the specified elements. + /// + /// + /// This method leverages internal optimizations depending on the target framework version + /// to efficiently populate the list with the specified items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static List CreateList(ReadOnlySpan items) + { + #if NET9_0_OR_GREATER + var list = new List(); + GetCount(list) = items.Length; + GetArray(list) = items.ToArray(); + return list; + #elif NET8_0_OR_GREATER + var list = new List(items.Length); + if (items.Length != 0) + { + CollectionsMarshal.SetCount(list, items.Length); + items.TryCopyTo(CollectionsMarshal.AsSpan(list)); + } + return list; + #else + var list = new List(items.Length); + foreach (var item in items) + list.Add(item); + return list; + #endif + } + + #if NET9_0_OR_GREATER + /// + /// Returns a reference to the internal array buffer of the specified . + /// + /// The list whose internal buffer is to be accessed. + /// + /// A reference to the internal array used by the list. + /// + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_items")] + private static extern ref T[] GetArray(List list); + + /// + /// Returns a reference to the internal "_size" field of the specified + /// representing the number of elements in the list. + /// + /// The list whose internal "_size" field is to be accessed. + /// + /// A reference to the internal "_size" field representing the number of elements in the list. + /// + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_size")] + private static extern ref int GetCount(List list); + #endif +} + diff --git a/tests/Ramstack.Parsing.Tests/Collections/ArrayListTests.cs b/tests/Ramstack.Parsing.Tests/Collections/ArrayListTests.cs deleted file mode 100644 index d62ff85..0000000 --- a/tests/Ramstack.Parsing.Tests/Collections/ArrayListTests.cs +++ /dev/null @@ -1,345 +0,0 @@ -namespace Ramstack.Parsing.Collections; - -[TestFixture] -public class ArrayListTests -{ - [TestCase(0)] - [TestCase(1)] - [TestCase(2)] - [TestCase(3)] - [TestCase(9)] - public void Ctor_Capacity(int capacity) - { - var list = new ArrayList(capacity); - - foreach (var _ in list) - Assert.Fail(); - - foreach (var _ in list.AsSpan()) - Assert.Fail(); - - Assert.That(list.Count, Is.Zero); - Assert.That(list.ToArray(), Is.SameAs(Array.Empty())); - Assert.That(list.Clear, Throws.Nothing); - } - - [TestCase(-1)] - [TestCase(int.MinValue)] - [TestCase(int.MaxValue)] - public void Ctor_InvalidCapacity_ShouldThrow(int capacity) - { - Assert.That( - () => new ArrayList(capacity), - Throws.TypeOf().Or.TypeOf()); - } - - [Test] - public void Indexer_ReturnsReference() - { - var list = new ArrayList(); - for (var i = 1; i <= 5; i++) - list.Add(i); - - list[1] = 10; - - Assert.That(list[3], Is.EqualTo(4)); - - ref var value = ref list[3]; - value = 20; - - Assert.That(list[3], Is.EqualTo(20)); - Assert.That( - list.ToArray(), - Is.EquivalentTo([1, 10, 3, 20, 5])); - } - - [Test] - public void Indexer_ReturnsValue() - { - var list = new ArrayList(); - for (var i = 0; i < 5; i++) - list.Add(i); - - for (var i = 0; i < list.Count; i++) - Assert.That(list[i], Is.EqualTo(i)); - } - - [Test] - public void Indexer_InvalidIndex_ShouldThrow() - { - var list = new ArrayList(); - Assert.That( - () => list[0], - Throws.TypeOf()); - - for (var i = 0; i < 5; i++) - list.Add(i); - - Assert.That( - () => list[6], - Throws.TypeOf()); - } - - [Test] - public void Add_ValueAdded() - { - var list = new ArrayList { 10 }; - - Assert.That(list.Count, Is.EqualTo(1)); - Assert.That(list.ToArray(), Is.EquivalentTo([10])); - } - - [Test] - public void Add_MultipleValues_AllValuesAdded() - { - const int Count = 999; - - var list = new ArrayList(4); - for (var i = 0; i < Count; i++) - list.Add(i); - - Assert.That(list.Count, Is.EqualTo(Count)); - Assert.That(list.ToArray().Length, Is.EqualTo(Count)); - } - - [Test] - public void Insert_ValuesAdded() - { - var list = new ArrayList(); - for (var i = 0; i < 10; i++) - list.Insert(i, i); - - Assert.That(list.Count, Is.EqualTo(10)); - Assert.That(list.ToArray(), Is.EquivalentTo(Enumerable.Range(0, 10))); - } - - [Test] - public void Insert_FromStart_ValuesAdded() - { - var list = new ArrayList(4); - for (var i = 0; i < 10; i++) - list.Insert(0, i); - - Assert.That(list.Count, Is.EqualTo(10)); - Assert.That(list.ToArray(), Is.EquivalentTo(Enumerable.Range(0, 10).Reverse())); - } - - [Test] - public void Insert_OutOfRange_ShouldThrow() - { - var list = new ArrayList(); - for (var i = 0; i < 10; i++) - list.Insert(0, i); - - Assert.Throws(() => list.Insert(11, 0)); - Assert.That(list.Count, Is.EqualTo(10)); - } - - [Test] - public void RemoveAt_EmptyList_ShouldThrow() - { - // ReSharper disable once CollectionNeverUpdated.Local - var list = new ArrayList(); - - Assert.Throws(() => list.RemoveAt(0)); - Assert.Throws(() => list.RemoveAt(5)); - Assert.That(list.Count, Is.EqualTo(0)); - } - - [Test] - public void RemoveAt_OutOfRange_ShouldThrow() - { - var list = new ArrayList(); - for (var i = 0; i < 5; i++) - list.Add(i); - - Assert.Throws(() => list.RemoveAt(5)); - Assert.That(list.Count, Is.EqualTo(5)); - } - - [Test] - public void RemoveAt_FromStart_ValueRemoved() - { - const int Count = 100; - - var reference = new List(); - var list = new ArrayList(); - - for (var i = 0; i < Count; i++) - { - list.Add(i.ToString()); - reference.Add(i.ToString()); - } - - for (var i = 0; i < Count; i++) - { - list.RemoveAt(0); - reference.RemoveAt(0); - - Assert.That(list.Count, Is.EqualTo(reference.Count)); - Assert.That(list, Is.EquivalentTo(reference)); - Assert.That(list.ToArray(), Is.EquivalentTo(reference)); - } - - Assert.That(list.Count, Is.Zero); - Assert.That(list.Any(), Is.False); - } - - [Test] - public void RemoveAt_FromEnd_ValueRemoved() - { - const int Count = 100; - - var reference = new List(); - var list = new ArrayList(); - - for (var i = 0; i < Count; i++) - { - list.Add(i.ToString()); - reference.Add(i.ToString()); - } - - for (var i = Count - 1; i >= 0; i--) - { - list.RemoveAt(i); - reference.RemoveAt(i); - - Assert.That(list.Count, Is.EqualTo(reference.Count)); - Assert.That(list, Is.EquivalentTo(reference)); - Assert.That(list.ToArray(), Is.EquivalentTo(reference)); - } - - Assert.That(list.Count, Is.Zero); - Assert.That(list.Any(), Is.False); - } - - [Test] - public void RemoveAt_RemoveAll_AllValuesRemoved() - { - const int Count = 100; - - var list = new ArrayList(); - for (var i = 0; i < Count; i++) - list.Add(i); - - for (var i = 0; i < Count; i++) - list.RemoveAt(0); - - Assert.That(list.Count, Is.EqualTo(0)); - Assert.That(list, Is.EquivalentTo(Array.Empty())); - Assert.That(list.ToArray(), Is.EquivalentTo(Array.Empty())); - } - - [Test] - public void Clear_AllValuesRemoved() - { - var list = new ArrayList(); - for (var i = 0; i < 10; i++) - list.Add(i.ToString()); - - list.Clear(); - - Assert.That(list.Count, Is.Zero); - Assert.That(list, Is.EquivalentTo(Array.Empty())); - Assert.That(list.ToArray(), Is.EquivalentTo(Array.Empty())); - } - - [Test] - public void RemoveAt_RemoveReferenceValue_ArrayElementNullified() - { - var list = new ArrayList(); - for (var i = 0; i < 4; i++) - list.Add(i.ToString()); - - ref var r2 = ref list[2]; - ref var r3 = ref list[3]; - - Assert.That(list, Is.EquivalentTo(["0", "1", "2", "3"])); - - list.RemoveAt(3); - - Assert.That(list, Is.EquivalentTo(["0", "1", "2"])); - Assert.That(r3, Is.Null); - - list.RemoveAt(0); - Assert.That(list, Is.EquivalentTo(["1", "2"])); - Assert.That(r2, Is.Null); - } - - [Test] - public void Clear_ReferenceValues_ArrayElementNullified() - { - var list = new ArrayList(); - for (var i = 0; i < 4; i++) - list.Add(i.ToString()); - - ref var r0 = ref list[0]; - ref var r1 = ref list[1]; - ref var r2 = ref list[2]; - ref var r3 = ref list[3]; - - list.Clear(); - - Assert.That(list, Is.Empty); - Assert.That(r0, Is.Null); - Assert.That(r1, Is.Null); - Assert.That(r2, Is.Null); - Assert.That(r3, Is.Null); - } - - [TestCase(0)] - [TestCase(2)] - [TestCase(4)] - [TestCase(5)] - public void AsSpan_Empty(int capacity) - { - var list = new ArrayList(capacity); - - Assert.That(list.Count, Is.Zero); - Assert.That(list.AsSpan().Length, Is.Zero); - } - - [TestCase(0)] - [TestCase(1)] - [TestCase(4)] - [TestCase(7)] - [TestCase(9)] - public void ToArray(int count) - { - var list = new ArrayList(count); - for (var i = 0; i < count; i++) - list.Add(i); - - Assert.That(list.ToArray(), Is.EquivalentTo(Enumerable.Range(0, count))); - Assert.That(list.Count, Is.EqualTo(count)); - } - - [Test] - public void ToArray_Empty() - { - Assert.That(new ArrayList().ToArray(), Is.Empty); - } - - [TestCase(0)] - [TestCase(1)] - [TestCase(4)] - [TestCase(7)] - [TestCase(9)] - public void AsSpan(int count) - { - var list = new ArrayList(count); - for (var i = 0; i < count; i++) - list.Add(i); - - Assert.That( - list.AsSpan().ToArray(), - Is.EquivalentTo(Enumerable.Range(0, count))); - } - - [Test] - public void AsSpan_Empty() - { - var view = new ArrayList().AsSpan(); - Assert.That(view.Length, Is.Zero); - } -} diff --git a/tests/Ramstack.Parsing.Tests/Scenarios/SimpleCalcTests.cs b/tests/Ramstack.Parsing.Tests/Scenarios/SimpleCalcTests.cs index 6e42a73..69118c6 100644 --- a/tests/Ramstack.Parsing.Tests/Scenarios/SimpleCalcTests.cs +++ b/tests/Ramstack.Parsing.Tests/Scenarios/SimpleCalcTests.cs @@ -86,7 +86,7 @@ public void SimpleCalcTest(string text, double number, string error = "") var expression = sum.Between(S, Eof); - static double Multiply(double v, ArrayList<(char, Unit, double)> results) + static double Multiply(double v, List<(char, Unit, double)> results) { foreach (var (op, _, d) in results) v = op == '*' ? v * d : v / d; @@ -94,7 +94,7 @@ static double Multiply(double v, ArrayList<(char, Unit, double)> results) return v; } - static double Add(double v, ArrayList<(char, Unit, double)> results) + static double Add(double v, List<(char, Unit, double)> results) { foreach (var (op, _, d) in results) v = op == '+' ? v + d : v - d;