//******************************
// 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);
}
}
}
}