using System; using System.Collections; using System.Collections.Generic; using System.Threading; namespace Cobilas.Collections.Generic { /// Represents a long, strongly typed list of objects that can be accessed by index. /// Provides methods for searching, sorting, and manipulating lists. /// The type of elements in the list. [Serializable] public class LongList : ILongList, IReadOnlyLongList, ILongList, ICloneable { private long _size; private T[] longArray; [NonSerialized] private object _syncRoot; /// public long Count => _size; /// Gets or sets the total number of elements the internal data structure can hold without resizing. public long Capacity { get => ArrayManipulation.ArrayLongLength(longArray); set { if (value < _size) throw new ArgumentOutOfRangeException("The capacity cannot be smaller than the list size."); if (value != ArrayManipulation.ArrayLongLength(longArray)) { if (value > 0) { T[] newArray = new T[value]; if (_size > 0) ArrayManipulation.CopyTo(longArray, 0L, newArray, 0L, _size); longArray = newArray; } else longArray = Array.Empty(); } } } /// public bool IsReadOnly => false; bool ILongList.IsFixedSize => false; bool ILongCollection.IsSynchronized => false; object ILongCollection.SyncRoot { get { if (_syncRoot == null) Interlocked.CompareExchange(ref _syncRoot, new object(), null); return _syncRoot; } } /// public T this[long index] { get => longArray[index]; set => longArray[index] = value; } object ILongList.this[long index] { get => longArray[index]; set => longArray[index] = (T)value; } /// Creates a new instance of the object. public LongList() => longArray = Array.Empty(); /// Creates a new instance of the object. public LongList(long capacity) => longArray = new T[capacity]; /// Creates a new instance of the object. public LongList(IEnumerable collection) { foreach (T item in collection) Add(item); } /// Creates a new instance of the object. public LongList(params T[] collection) : this((IEnumerable)collection) {} /// Returns a read-only ReadOnlyLongCollection< T > wrapper for the current collection. public ReadOnlyLongCollection AsReadOnly() { T[] newArray = new T[_size]; CopyTo(newArray, 0L); return new ReadOnlyLongCollection(newArray); } /// Creates a shallow copy of a range of elements in the source . /// The zero-based index at which the range starts. /// The number of elements in the range. /// /// A shallow copy of a range of elements in the source . public LongList GetRange(long index, long count) { if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException("index", new ArgumentOutOfRangeException()); else if (count < 0 || count > Count) throw new ArgumentOutOfRangeException("count", new ArgumentOutOfRangeException()); LongList clone = new LongList(count); ArrayManipulation.CopyTo(longArray, index, clone.longArray, 0L, count); clone._size = count; return clone; } /// public void Add(T item) { if (_size == Capacity) Capacity = _size + 1; longArray[_size++] = item; } /// Adds the elements of the specified collection to the end of the . /// The collection whose elements should be added to the end of the . /// The collection itself cannot be null, but it can contain elements that are null, if type T is a /// reference type. public void AddRange(IEnumerable collection) { foreach (T item in collection) Add(item); } /// public void Clear() { ArrayManipulation.LongClearArraySafe(longArray); _size = 0; } /// public bool Contains(T item) => ArrayManipulation.Exists(item, longArray); /// /// The match parameter allows you to create custom comparison logic. public bool Contains(Predicate match) => ArrayManipulation.Exists(longArray, match); /// public void CopyTo(T[] array, long arrayIndex) => ArrayManipulation.CopyTo(longArray, arrayIndex, array, arrayIndex, Count); /// public IEnumerator GetEnumerator() { T[] newArray = new T[_size]; CopyTo(newArray, 0L); return new ArrayToIEnumerator(newArray); } /// public long IndexOf(T item) => ArrayManipulation.IndexOf(item, longArray); /// public void Insert(long index, T item) { ArrayManipulation.Insert(item, index, ref longArray); _size++; } /// Inserts the elements of a collection into the at the specified index. /// The zero-based index at which the new elements should be inserted. /// The collection whose elements should be inserted into the . /// The collection itself cannot be null, but it can contain elements that are null, /// if type T is a reference type. public void InsertRange(long index, IEnumerable collection) { foreach (T item in collection) Insert(index, item); } /// public bool Remove(T item) { long index = IndexOf(item); if (index != -1) RemoveAt(index); return false; } /// public void RemoveAt(long index) { long old_capacity = Capacity; ArrayManipulation.Remove(index, ref longArray); _size--; Capacity = old_capacity; } /// Removes all the elements that match the conditions defined by the specified predicate. /// The delegate that defines the conditions of the elements to remove. /// /// The number of elements removed from the . public long RemoveAll(Predicate match) { if (match == null) throw new ArgumentNullException("match", new ArgumentNullException()); long freeIndex = 0; while( freeIndex < _size && !match(longArray[freeIndex])) freeIndex++; if( freeIndex >= _size) return 0; long current = freeIndex + 1; while( current < _size) { while( current < _size && match(longArray[current])) current++; if ( current < _size) longArray[freeIndex++] = longArray[current++]; } ArrayManipulation.ClearArray(longArray, freeIndex, _size - freeIndex); long result = _size - freeIndex; _size = freeIndex; return result; } /// Removes a range of elements from the /// The zero-based starting index of the range of elements to remove. /// The number of elements to remove. public void RemoveRamge(long index, long count) { long old_capacity = Capacity; ArrayManipulation.Remove(index, count, ref longArray); _size -= count; Capacity = old_capacity; } /// public object Clone() => new LongList(longArray); /// Copies the elements of the to a new array. /// public T[] ToArray() { T[] newArray = new T[_size]; CopyTo(newArray, 0L); return newArray; } /// public void Reverse(long index, long length) => ArrayManipulation.Reverse(longArray, index, length); /// public void Reverse() => Reverse(0L, Count); /// public T Find(Predicate match) => ArrayManipulation.Find(longArray, match); /// public T FindLast(Predicate match) => ArrayManipulation.FindLast(longArray, match); /// public T[] FindAll(Predicate match) => ArrayManipulation.FindAll(longArray, match); /// public long FindIndex(Predicate match) => ArrayManipulation.LongFindIndex(longArray, match); /// public long FindIndex(long startIndex, Predicate match) => ArrayManipulation.FindIndex(longArray, startIndex, match); /// public long FindIndex(long startIndex, long count, Predicate match) => ArrayManipulation.FindIndex(longArray, startIndex, count, match); /// public long FindLastIndex(Predicate match) => ArrayManipulation.LongFindLastIndex(longArray, match); /// public long FindLastIndex(long startIndex, Predicate match) => ArrayManipulation.FindLastIndex(longArray, startIndex, match); /// public long FindLastIndex(long startIndex, long count, Predicate match) => ArrayManipulation.FindLastIndex(longArray, startIndex, count, match); /// public TOutput[] ConvertAll(Converter converter) => ArrayManipulation.LongConvertAll(longArray, converter); /// Performs the specified action on each element of the . /// The delegate to perform on each element of the . /// /// public void ForEach(Action action) { if (action == null) throw new ArgumentNullException($"Action<{typeof(T)}> action", new ArgumentNullException()); long _version = longArray.GetHashCode(); foreach (T item in longArray) { if (_version != longArray.GetHashCode()) throw new InvalidOperationException("The list cannot be changed while executing the ForEach function."); action(item); } } long ILongList.Add(object value) { Add((T)value); return _size - 1; } bool ILongList.Contains(object value) => ArrayManipulation.Exists((T)value, longArray); void ILongCollection.CopyTo(Array array, long index) => ArrayManipulation.CopyTo(longArray, index, array, index, Count); IEnumerator IEnumerable.GetEnumerator() { T[] newArray = new T[_size]; CopyTo(newArray, 0L); return new ArrayToIEnumerator(newArray); } long ILongList.IndexOf(object value) => IndexOf((T)value); void ILongList.Insert(long index, object value) => Insert(index, (T)value); void ILongList.Remove(object value) => Remove((T)value); } }