#nullable enable using System; using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; using System.Runtime.CompilerServices; namespace imm; /// /// An immutable list implementation that tracks history, metadata, and time. /// public record class List : Timed>, IImmutableList { static public List Empty { get; } = new(); public ImmutableList Values { get; init; } = ImmutableList.Empty; public List() { } // Required for 'with' expressions to work with the base class hierarchy protected List(Timed> original) : base(original) { } // Helper to apply changes using the Process method private List Change( Func, ImmutableList> listChange, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "listChange" )] string reason = "" ) { var newValues = listChange(Values); return ReferenceEquals(Values, newValues) ? this : Process(l => l with { Values = newValues }, reason, dbgMethod, dbgPath, dbgLine, reason); } // --- IImmutableList implementation using the Change helper --- public T this[int index] => Values[index]; public int Count => Values.Count; public List Add(T value, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1) => Change(v => v.Add(value), dbgMethod, dbgPath, dbgLine); public List AddRange(IEnumerable items, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1) => Change(v => v.AddRange(items), dbgMethod, dbgPath, dbgLine); public List Clear([CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1) => Change(v => v.Clear(), dbgMethod, dbgPath, dbgLine); #region IImmutableList Implementati, dbgMethod, dbgPath, dbgLineon public List Insert( int index, T element, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Insert( index, element ) , dbgMethod, dbgPath, dbgLine); public List InsertRange( int index, IEnumerable items, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.InsertRange( index, items ) , dbgMethod, dbgPath, dbgLine); public List Remove( T value, IEqualityComparer? equalityComparer, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Remove( value, equalityComparer ) , dbgMethod, dbgPath, dbgLine); public List Remove( T value, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Remove( value, EqualityComparer.Default , dbgMethod, dbgPath, dbgLine); public List RemoveAll( Predicate match, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveAll( match ) , dbgMethod, dbgPath, dbgLine); public List RemoveAt( int index, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveAt( index ) , dbgMethod, dbgPath, dbgLine); public List RemoveRange( int index, int count, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveRange( index, count ) , dbgMethod, dbgPath, dbgLine); public List RemoveRange( IEnumerable items, IEqualityComparer? equalityComparer, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveRange( items, equalityComparer ) , dbgMethod, dbgPath, dbgLine); public List Replace( T oldValue, T newValue, IEqualityComparer? equalityComparer, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Replace( oldValue, newValue, equalityComparer ) , dbgMethod, dbgPath, dbgLine); public List SetItem( int index, T value, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.SetItem( index, value ) , dbgMethod, dbgPath, dbgLine); public int IndexOf( T item, int index, int count, IEqualityComparer? equalityComparer ) => Values.IndexOf( item, index, count, equalityComparer ?? EqualityComparer.Default ); public int LastIndexOf( T item, int index, int count, IEqualityComparer? equalityComparer) => Values.LastIndexOf( item, index, count, equalityComparer ?? EqualityComparer.Default ); public int IndexOf( T item, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => IndexOf( item, 0, Count, EqualityComparer.Default); IImmutableList IImmutableList.Clear() => Clear(); IImmutableList IImmutableList.Add( T value ) => Add( value ); IImmutableList IImmutableList.AddRange( IEnumerable items ) => AddRange( items ); IImmutableList IImmutableList.Insert( int index, T element ) => Insert( index, element ); IImmutableList IImmutableList.InsertRange( int index, IEnumerable items ) => InsertRange( index, items ); IImmutableList IImmutableList.Remove( T value, IEqualityComparer? equalityComparer ) => Remove( value, equalityComparer ); IImmutableList IImmutableList.RemoveAll( Predicate match ) => RemoveAll( match ); IImmutableList IImmutableList.RemoveAt( int index ) => RemoveAt( index ); IImmutableList IImmutableList.RemoveRange( IEnumerable items, IEqualityComparer? equalityComparer ) => RemoveRange( items, equalityComparer ); IImmutableList IImmutableList.RemoveRange( int index, int count ) => RemoveRange( index, count ); IImmutableList IImmutableList.Replace( T oldValue, T newValue, IEqualityComparer? equalityComparer ) => Replace( oldValue, newValue, equalityComparer ); IImmutableList IImmutableList.SetItem( int index, T value ) => SetItem( index, value ); #endregion // --- Standard Interfaces --- public IEnumerator GetEnumerator() => Values.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)Values).GetEnumerator(); }