123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
- using System;
- using System.Collections;
- using System.Collections.Generic;
- namespace Animancer
- {
- /// <summary>
- /// An <see cref="IEnumerator{T}"/> for any <see cref="IList{T}"/> doesn't bother checking if the target has been
- /// modified. This gives it good performance but also makes it slightly less safe to use.
- /// </summary>
- /// <remarks>
- /// This struct also implements <see cref="IEnumerable{T}"/> so it can be used in <c>foreach</c> statements and
- /// <see cref="IList{T}"/> to allow the target collection to be modified without breaking the enumerator (though
- /// doing so is still somewhat dangerous so use with care).
- /// </remarks>
- /// <example><code>
- /// var numbers = new int[] { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, };
- /// var count = 4;
- /// foreach (var number in new FastEnumerator<int>(numbers, count))
- /// {
- /// Debug.Log(number);
- /// }
- ///
- /// // Log Output:
- /// // 9
- /// // 8
- /// // 7
- /// // 6
- /// </code></example>
- public struct FastEnumerator<T> : IList<T>, IEnumerator<T>
- {
- /************************************************************************************************************************/
- /// <summary>The target <see cref="IList{T}"/>.</summary>
- private readonly IList<T> List;
- /************************************************************************************************************************/
- private int _Count;
- /// <summary>[<see cref="ICollection{T}"/>]
- /// The number of items in the <see cref="List"/> (which can be less than the
- /// <see cref="ICollection{T}.Count"/> of the <see cref="List"/>).
- /// </summary>
- public int Count
- {
- get => _Count;
- set
- {
- AssertCount(value);
- _Count = value;
- }
- }
- /************************************************************************************************************************/
- private int _Index;
- /// <summary>The position of the <see cref="Current"/> item in the <see cref="List"/>.</summary>
- public int Index
- {
- get => _Index;
- set
- {
- AssertIndex(value);
- _Index = value;
- }
- }
- /************************************************************************************************************************/
- /// <summary>The item at the current <see cref="Index"/> in the <see cref="List"/>.</summary>
- public T Current
- {
- get
- {
- AssertCount(_Count);
- AssertIndex(_Index);
- return List[_Index];
- }
- set
- {
- AssertCount(_Count);
- AssertIndex(_Index);
- List[_Index] = value;
- }
- }
- /// <summary>The item at the current <see cref="Index"/> in the <see cref="List"/>.</summary>
- object IEnumerator.Current => Current;
- /************************************************************************************************************************/
- /// <summary>Creates a new <see cref="FastEnumerator{T}"/>.</summary>
- /// <exception cref="NullReferenceException">
- /// The `list` is null. Use the <c>default</c> <see cref="FastEnumerator{T}"/> instead.
- /// </exception>
- public FastEnumerator(IList<T> list)
- : this(list, list.Count)
- { }
- /// <summary>Creates a new <see cref="FastEnumerator{T}"/>.</summary>
- /// <exception cref="NullReferenceException">
- /// The `list` is null. Use the <c>default</c> <see cref="FastEnumerator{T}"/> instead.
- /// </exception>
- public FastEnumerator(IList<T> list, int count)
- {
- List = list;
- _Count = count;
- _Index = -1;
- AssertCount(count);
- }
- /************************************************************************************************************************/
- /// <summary>Moves to the next item in the <see cref="List"/> and returns true if there is one.</summary>
- /// <remarks>At the end of the <see cref="List"/> the <see cref="Index"/> is set to <see cref="int.MinValue"/>.</remarks>
- public bool MoveNext()
- {
- _Index++;
- if ((uint)_Index < (uint)_Count)
- {
- return true;
- }
- else
- {
- _Index = int.MinValue;
- return false;
- }
- }
- /************************************************************************************************************************/
- /// <summary>Moves to the previous item in the <see cref="List"/> and returns true if there is one.</summary>
- /// <remarks>At the end of the <see cref="List"/> the <see cref="Index"/> is set to <c>-1</c>.</remarks>
- public bool MovePrevious()
- {
- if (_Index > 0)
- {
- _Index--;
- return true;
- }
- else
- {
- _Index = -1;
- return false;
- }
- }
- /************************************************************************************************************************/
- /// <summary>[<see cref="IEnumerator"/>] Reverts this enumerator to the start of the <see cref="List"/>.</summary>
- public void Reset()
- {
- _Index = -1;
- }
- /************************************************************************************************************************/
- /// <inheritdoc/>
- void IDisposable.Dispose() { }
- /************************************************************************************************************************/
- // IEnumerator.
- /************************************************************************************************************************/
- /// <summary>Returns <c>this</c>.</summary>
- public FastEnumerator<T> GetEnumerator() => this;
- /// <inheritdoc/>
- IEnumerator<T> IEnumerable<T>.GetEnumerator() => this;
- /// <inheritdoc/>
- IEnumerator IEnumerable.GetEnumerator() => this;
- /************************************************************************************************************************/
- // IList.
- /************************************************************************************************************************/
- /// <summary>[<see cref="IList{T}"/>] Returns the first index of the `item` in the <see cref="List"/>.</summary>
- public int IndexOf(T item) => List.IndexOf(item);
- /// <summary>[<see cref="IList{T}"/>] The item at the specified `index` in the <see cref="List"/>.</summary>
- public T this[int index]
- {
- get
- {
- AssertIndex(index);
- return List[index];
- }
- set
- {
- AssertIndex(index);
- List[index] = value;
- }
- }
- /// <summary>[<see cref="IList{T}"/>] Inserts the `item` at the specified `index` in the <see cref="List"/>.</summary>
- public void Insert(int index, T item)
- {
- AssertIndex(index);
- List.Insert(index, item);
- if (_Index >= index)
- _Index++;
- _Count++;
- }
- /// <summary>[<see cref="IList{T}"/>] Removes the item at the specified `index` from the <see cref="List"/>.</summary>
- public void RemoveAt(int index)
- {
- AssertIndex(index);
- List.RemoveAt(index);
- if (_Index >= index)
- _Index--;
- _Count--;
- }
- /************************************************************************************************************************/
- // ICollection.
- /************************************************************************************************************************/
- /// <summary>[<see cref="ICollection{T}"/>] Is the <see cref="List"/> read-only?</summary>
- public bool IsReadOnly => List.IsReadOnly;
- /// <summary>[<see cref="ICollection{T}"/>] Does the <see cref="List"/> contain the `item`?</summary>
- public bool Contains(T item) => List.Contains(item);
- /// <summary>[<see cref="ICollection{T}"/>] Adds the `item` to the end of the <see cref="List"/>.</summary>
- public void Add(T item)
- {
- List.Add(item);
- _Count++;
- }
- /// <summary>[<see cref="ICollection{T}"/>] Removes the `item` from the <see cref="List"/> and returns true if successful.</summary>
- public bool Remove(T item)
- {
- var index = List.IndexOf(item);
- if (index >= 0)
- {
- RemoveAt(index);
- return true;
- }
- else return false;
- }
- /// <summary>[<see cref="ICollection{T}"/>] Removes everything from the <see cref="List"/>.</summary>
- public void Clear()
- {
- List.Clear();
- _Index = -1;
- _Count = 0;
- }
- /// <summary>[<see cref="ICollection{T}"/>] Copies the contents of the <see cref="List"/> into the `array`.</summary>
- public void CopyTo(T[] array, int arrayIndex)
- {
- for (int i = 0; i < _Count; i++)
- array[arrayIndex + i] = List[i];
- }
- /************************************************************************************************************************/
- /// <summary>[Assert-Only] Throws an exception unless 0 <= `index` < <see cref="Count"/>.</summary>
- /// <exception cref="ArgumentOutOfRangeException"/>
- [System.Diagnostics.Conditional(Strings.Assertions)]
- private void AssertIndex(int index)
- {
- #if UNITY_ASSERTIONS
- if ((uint)index > (uint)_Count)
- throw new ArgumentOutOfRangeException(nameof(index),
- $"{nameof(FastEnumerator<T>)}.{nameof(Index)}" +
- $" must be within 0 <= {nameof(Index)} ({index}) < {nameof(Count)} ({_Count}).");
- #endif
- }
- /************************************************************************************************************************/
- /// <summary>[Assert-Only] Throws an exception unless 0 < `count` <= <see cref="ICollection{T}.Count"/>.</summary>
- /// <exception cref="ArgumentOutOfRangeException"/>
- [System.Diagnostics.Conditional(Strings.Assertions)]
- private void AssertCount(int count)
- {
- #if UNITY_ASSERTIONS
- if (List == null)
- {
- if (count != 0)
- throw new ArgumentOutOfRangeException(nameof(count),
- $"Must be within 0 since the {nameof(List)} is null.");
- }
- else
- {
- if ((uint)count > (uint)List.Count)
- throw new ArgumentOutOfRangeException(nameof(count),
- $"Must be within 0 <= {nameof(count)} ({count}) < {nameof(List)}.{nameof(List.Count)} ({List.Count}).");
- }
- #endif
- }
- /************************************************************************************************************************/
- }
- }
|