//****************************** // Written by Peter Golde // Copyright (c) 2004-2005, Wintellect // // Use and restribution of this code is subject to the license agreement // contained in the file "License.txt" accompanying this file. //****************************** using System; using System.Collections; using System.Collections.Generic; namespace Wintellect.PowerCollections { /// /// ListBase is an abstract class that can be used as a base class for a read-write collection that needs /// to implement the generic IList<T> and non-generic IList collections. The derived class needs /// to override the following methods: Count, Clear, Insert, RemoveAt, and the indexer. The implementation /// of all the other methods in IList<T> and IList are handled by ListBase. /// /// [Serializable] public abstract class ListBase : CollectionBase, IList, IList { /// /// Creates a new ListBase. /// protected ListBase() { } /// /// The property must be overridden by the derived class to return the number of /// items in the list. /// /// The number of items in the list. public abstract override int Count { get;} /// /// This method must be overridden by the derived class to empty the list /// of all items. /// public abstract override void Clear(); /// /// The indexer must be overridden by the derived class to get and set /// values of the list at a particular index. /// /// The index in the list to get or set an item at. The /// first item in the list has index 0, and the last has index Count-1. /// The item at the given index. /// is /// less than zero or greater than or equal to Count. public abstract T this[int index] { get; set; } /// /// This method must be overridden by the derived class to insert a new /// item at the given index. /// /// The index in the list to insert the item at. After the /// insertion, the inserted item is located at this index. The /// first item in the list has index 0. /// The item to insert at the given index. /// is /// less than zero or greater than Count. public abstract void Insert(int index, T item); /// /// This method must be overridden by the derived class to remove the /// item at the given index. /// /// The index in the list to remove the item at. The /// first item in the list has index 0. /// is /// less than zero or greater than or equal to Count. public abstract void RemoveAt(int index); /// /// Enumerates all of the items in the list, in order. The item at index 0 /// is enumerated first, then the item at index 1, and so on. /// /// The enumerator does not check for changes made /// to the structure of the list. Thus, changes to the list during /// enumeration may cause incorrect enumeration or out of range /// exceptions. Consider overriding this method and adding checks /// for structural changes. /// An IEnumerator<T> that enumerates all the /// items in the list. public override IEnumerator GetEnumerator() { int count = Count; for (int i = 0; i < count; ++i) { yield return this[i]; } } /// /// Determines if the list contains any item that compares equal to . /// The implementation simply checks whether IndexOf(item) returns a non-negative value. /// /// Equality in the list is determined by the default sense of /// equality for T. If T implements IComparable<T>, the /// Equals method of that interface is used to determine equality. Otherwise, /// Object.Equals is used to determine equality. /// The item to search for. /// True if the list contains an item that compares equal to . public override bool Contains(T item) { return (IndexOf(item) >= 0); } /// /// Adds an item to the end of the list. This method is equivalent to calling: /// Insert(Count, item) /// /// The item to add to the list. public override void Add(T item) { Insert(Count, item); } /// /// Searches the list for the first item that compares equal to . /// If one is found, it is removed. Otherwise, the list is unchanged. /// /// Equality in the list is determined by the default sense of /// equality for T. If T implements IComparable<T>, the /// Equals method of that interface is used to determine equality. Otherwise, /// Object.Equals is used to determine equality. /// The item to remove from the list. /// True if an item was found and removed that compared equal to /// . False if no such item was in the list. public override bool Remove(T item) { int index = IndexOf(item); if (index >= 0) { RemoveAt(index); return true; } else { return false; } } /// /// Copies all the items in the list, in order, to , /// starting at index 0. /// /// The array to copy to. This array must have a size /// that is greater than or equal to Count. public virtual void CopyTo(T[] array) { this.CopyTo(array, 0); } /// /// Copies all the items in the list, in order, to , /// starting at . /// /// The array to copy to. This array must have a size /// that is greater than or equal to Count + arrayIndex. /// The starting index in /// to copy to. public override void CopyTo(T[] array, int arrayIndex) { base.CopyTo(array, arrayIndex); } /// /// Copies a range of elements from the list to , /// starting at . /// /// The starting index in the source list of the range to copy. /// The array to copy to. This array must have a size /// that is greater than or equal to Count + arrayIndex. /// The starting index in /// to copy to. /// The number of items to copy. public virtual void CopyTo(int index, T[] array, int arrayIndex, int count) { Range(index, count).CopyTo(array, arrayIndex); } /// /// Provides a read-only view of this list. The returned IList<T> provides /// a view of the list that prevents modifications to the list. Use the method to provide /// access to the list without allowing changes. Since the returned object is just a view, /// changes to the list will be reflected in the view. /// /// An IList<T> that provides read-only access to the list. public virtual new IList AsReadOnly() { return Algorithms.ReadOnly(this); } /// /// Finds the first item in the list that satisfies the condition /// defined by . If no item matches the condition, than /// the default value for T (null or all-zero) is returned. /// /// If the default value for T (null or all-zero) matches the condition defined by , /// and the list might contain the default value, then it is impossible to distinguish the different between finding /// the default value and not finding any item. To distinguish these cases, use . /// A delegate that defined the condition to check for. /// The first item that satisfies the condition . If no item satisfies that /// condition, the default value for T is returned. /// public virtual T Find(Predicate predicate) { return Algorithms.FindFirstWhere(this, predicate); } /// /// Finds the first item in the list that satisfies the condition /// defined by . /// /// A delegate that defines the condition to check for. /// If true is returned, this parameter receives the first item in the list /// that satifies the condition defined by . /// True if an item that satisfies the condition was found. False /// if no item in the list satisfies that condition. public virtual bool TryFind(Predicate predicate, out T foundItem) { return Algorithms.TryFindFirstWhere(this, predicate, out foundItem); } /// /// Finds the last item in the list that satisfies the condition /// defined by . If no item matches the condition, than /// the default value for T (null or all-zero) is returned. /// /// If the default value for T (null or all-zero) matches the condition defined by , /// and the list might contain the default value, then it is impossible to distinguish the different between finding /// the default value and not finding any item. To distinguish these cases, use . /// A delegate that defined the condition to check for. /// The last item that satisfies the condition . If no item satisfies that /// condition, the default value for T is returned. /// public virtual T FindLast(Predicate predicate) { return Algorithms.FindLastWhere(this, predicate); } /// /// Finds the last item in the list that satisfies the condition /// defined by . /// /// A delegate that defines the condition to check for. /// If true is returned, this parameter receives the last item in the list /// that satifies the condition defined by . /// True if an item that satisfies the condition was found. False /// if no item in the list satisfies that condition. public virtual bool TryFindLast(Predicate predicate, out T foundItem) { return Algorithms.TryFindLastWhere(this, predicate, out foundItem); } /// /// Finds the index of the first item in the list that satisfies the condition /// defined by . If no item matches the condition, -1 is returned. /// /// A delegate that defined the condition to check for. /// The index of the first item that satisfies the condition . If no item satisfies that /// condition, -1 is returned. public virtual int FindIndex(Predicate predicate) { return Algorithms.FindFirstIndexWhere(this, predicate); } /// /// Finds the index of the first item, in the range of items extending from to the end, that satisfies the condition /// defined by . If no item matches the condition, -1 is returned. /// /// A delegate that defined the condition to check for. /// The starting index of the range to check. /// The index of the first item in the given range that satisfies the condition . If no item satisfies that /// condition, -1 is returned. public virtual int FindIndex(int index, Predicate predicate) { int foundIndex = Algorithms.FindFirstIndexWhere(Range(index, Count - index), predicate); if (foundIndex < 0) return -1; else return foundIndex + index; } /// /// Finds the index of the first item, in the range of items starting from , that satisfies the condition /// defined by . If no item matches the condition, -1 is returned. /// /// A delegate that defined the condition to check for. /// The starting index of the range to check. /// The number of items in range to check. /// The index of the first item in the given range that satisfies the condition . If no item satisfies that /// condition, -1 is returned. public virtual int FindIndex(int index, int count, Predicate predicate) { int foundIndex = Algorithms.FindFirstIndexWhere(Range(index, count), predicate); if (foundIndex < 0) return -1; else return foundIndex + index; } /// /// Finds the index of the last item in the list that satisfies the condition /// defined by . If no item matches the condition, -1 is returned. /// /// A delegate that defined the condition to check for. /// The index of the last item that satisfies the condition . If no item satisfies that /// condition, -1 is returned. public virtual int FindLastIndex(Predicate predicate) { return Algorithms.FindLastIndexWhere(this, predicate); } /// /// Finds the index of the last item, in the range of items extending from the beginning /// of the list to , that satisfies the condition /// defined by . If no item matches the condition, -1 is returned. /// /// A delegate that defined the condition to check for. /// The ending index of the range to check. /// The index of the last item in the given range that satisfies the condition . If no item satisfies that /// condition, -1 is returned. public virtual int FindLastIndex(int index, Predicate predicate) { return Algorithms.FindLastIndexWhere(Range(0, index + 1), predicate); } /// /// Finds the index of the last item, in the range of items ending at , that satisfies the condition /// defined by . If no item matches the condition, -1 is returned. /// /// A delegate that defined the condition to check for. /// The ending index of the range to check. /// The number of items in range to check. /// The index of the last item in the given range that satisfies the condition . If no item satisfies that /// condition, -1 is returned. public virtual int FindLastIndex(int index, int count, Predicate predicate) { int foundIndex = Algorithms.FindLastIndexWhere(Range(index - count + 1, count), predicate); if (foundIndex >= 0) return foundIndex + index - count + 1; else return -1; } /// /// Finds the index of the first item in the list that is equal to . /// /// The default implementation of equality for type T is used in the search. This is the /// equality defined by IComparable<T> or object.Equals. /// The item to search fror. /// The index of the first item in the list that that is equal to . If no item is equal /// to , -1 is returned. public virtual int IndexOf(T item) { return Algorithms.FirstIndexOf(this, item, EqualityComparer.Default); } /// /// Finds the index of the first item, in the range of items extending from to the end, /// that is equal to . /// /// The default implementation of equality for type T is used in the search. This is the /// equality defined by IComparable<T> or object.Equals. /// The item to search fror. /// The starting index of the range to check. /// The index of the first item in the given range that that is equal to . If no item is equal /// to , -1 is returned. public virtual int IndexOf(T item, int index) { int foundIndex = Algorithms.FirstIndexOf(Range(index, Count - index), item, EqualityComparer.Default); if (foundIndex >= 0) return foundIndex + index; else return -1; } /// /// Finds the index of the first item, in the range of items starting from , /// that is equal to . /// /// The default implementation of equality for type T is used in the search. This is the /// equality defined by IComparable<T> or object.Equals. /// The item to search fror. /// The starting index of the range to check. /// The number of items in range to check. /// The index of the first item in the given range that that is equal to . If no item is equal /// to , -1 is returned. public virtual int IndexOf(T item, int index, int count) { int foundIndex = Algorithms.FirstIndexOf(Range(index, count), item, EqualityComparer.Default); if (foundIndex >= 0) return foundIndex + index; else return -1; } /// /// Finds the index of the last item in the list that is equal to . /// /// The default implementation of equality for type T is used in the search. This is the /// equality defined by IComparable<T> or object.Equals. /// The item to search fror. /// The index of the last item in the list that that is equal to . If no item is equal /// to , -1 is returned. public virtual int LastIndexOf(T item) { return Algorithms.LastIndexOf(this, item, EqualityComparer.Default); } /// /// Finds the index of the last item, in the range of items extending from the beginning /// of the list to , that is equal to . /// /// The default implementation of equality for type T is used in the search. This is the /// equality defined by IComparable<T> or object.Equals. /// The item to search fror. /// The ending index of the range to check. /// The index of the last item in the given range that that is equal to . If no item is equal /// to , -1 is returned. public virtual int LastIndexOf(T item, int index) { int foundIndex = Algorithms.LastIndexOf(Range(0, index + 1), item, EqualityComparer.Default); return foundIndex; } /// /// Finds the index of the last item, in the range of items ending at , /// that is equal to . /// /// The default implementation of equality for type T is used in the search. This is the /// equality defined by IComparable<T> or object.Equals. /// The item to search for. /// The ending index of the range to check. /// The number of items in range to check. /// The index of the last item in the given range that that is equal to . If no item is equal /// to , -1 is returned. public virtual int LastIndexOf(T item, int index, int count) { int foundIndex = Algorithms.LastIndexOf(Range(index - count + 1, count), item, EqualityComparer.Default); if (foundIndex >= 0) return foundIndex + index - count + 1; else return -1; } /// /// Returns a view onto a sub-range of this list. Items are not copied; the /// returned IList<T> is simply a different view onto the same underlying items. Changes to this list /// are reflected in the view, and vice versa. Insertions and deletions in the view change the size of the /// view, but insertions and deletions in the underlying list do not. /// /// /// This method can be used to apply an algorithm to a portion of a list. For example: /// Algorithms.ReverseInPlace(deque.Range(3, 6)) /// will reverse the 6 items beginning at index 3. /// The starting index of the view. /// The number of items in the view. /// A list that is a view onto the given sub-part of this list. /// or is negative. /// + is greater than the /// size of the list. public virtual IList Range(int start, int count) { return Algorithms.Range(this, start, count); } /// /// Convert the given parameter to T. Throw an ArgumentException /// if it isn't. /// /// parameter name /// parameter value private T ConvertToItemType(string name, object value) { try { return (T)value; } catch (InvalidCastException) { throw new ArgumentException(string.Format(Strings.WrongType, value, typeof(T)), name); } } /// /// Adds an item to the end of the list. This method is equivalent to calling: /// Insert(Count, item) /// /// The item to add to the list. /// cannot be converted to T. int IList.Add(object value) { int count = Count; Insert(count, ConvertToItemType("value", value)); return count; } /// /// Removes all the items from the list, resulting in an empty list. /// void IList.Clear() { Clear(); } /// /// Determines if the list contains any item that compares equal to . /// /// Equality in the list is determined by the default sense of /// equality for T. If T implements IComparable<T>, the /// Equals method of that interface is used to determine equality. Otherwise, /// Object.Equals is used to determine equality. /// The item to search for. bool IList.Contains(object value) { if (value is T || value == null) return Contains((T)value); else return false; } /// /// Find the first occurrence of an item equal to /// in the list, and returns the index of that item. /// /// Equality in the list is determined by the default sense of /// equality for T. If T implements IComparable<T>, the /// Equals method of that interface is used to determine equality. Otherwise, /// Object.Equals is used to determine equality. /// The item to search for. /// The index of , or -1 if no item in the /// list compares equal to . int IList.IndexOf(object value) { if (value is T || value == null) return IndexOf((T)value); else return -1; } /// /// Insert a new /// item at the given index. /// /// The index in the list to insert the item at. After the /// insertion, the inserted item is located at this index. The /// first item in the list has index 0. /// The item to insert at the given index. /// is /// less than zero or greater than Count. /// cannot be converted to T. void IList.Insert(int index, object value) { Insert(index, ConvertToItemType("value", value)); } /// /// Returns whether the list is a fixed size. This implementation always returns false. /// /// Alway false, indicating that the list is not fixed size. bool IList.IsFixedSize { get { return false; } } /// /// Returns whether the list is read only. This implementation returns the value /// from ICollection<T>.IsReadOnly, which is by default, false. /// /// By default, false, indicating that the list is not read only. bool IList.IsReadOnly { get { return ((ICollection)this).IsReadOnly; } } /// /// Searches the list for the first item that compares equal to . /// If one is found, it is removed. Otherwise, the list is unchanged. /// /// Equality in the list is determined by the default sense of /// equality for T. If T implements IComparable<T>, the /// Equals method of that interface is used to determine equality. Otherwise, /// Object.Equals is used to determine equality. /// The item to remove from the list. /// cannot be converted to T. void IList.Remove(object value) { if (value is T || value == null) Remove((T)value); } /// /// Removes the /// item at the given index. /// /// The index in the list to remove the item at. The /// first item in the list has index 0. /// is /// less than zero or greater than or equal to Count. void IList.RemoveAt(int index) { RemoveAt(index); } /// /// Gets or sets the /// value at a particular index in the list. /// /// The index in the list to get or set an item at. The /// first item in the list has index 0, and the last has index Count-1. /// The item at the given index. /// is /// less than zero or greater than or equal to Count. /// cannot be converted to T. object IList.this[int index] { get { return this[index]; } set { this[index] = ConvertToItemType("value", value); } } } }