.RangeTester rangeTester, bool entireTree, bool reversed)
{
this.mySet = mySet;
this.rangeTester = rangeTester;
this.entireTree = entireTree;
this.reversed = reversed;
}
public override int Count
{
get
{
if (entireTree)
return mySet.Count;
else {
// Note: we can't cache the result of this call because the underlying
// set can change, which would make the cached value incorrect.
return mySet.tree.CountRange(rangeTester);
}
}
}
public override T this[int index]
{
get
{
if (entireTree) {
if (reversed)
return mySet[mySet.Count - 1 - index];
else
return mySet[index];
}
else {
T dummy;
int firstIndex = mySet.tree.FirstItemInRange(rangeTester, out dummy);
int lastIndex = mySet.tree.LastItemInRange(rangeTester, out dummy);
if (firstIndex < 0 || lastIndex < 0 || index < 0 || index >= (lastIndex - firstIndex + 1))
throw new ArgumentOutOfRangeException("index");
if (reversed)
return mySet[lastIndex - index];
else
return mySet[firstIndex + index];
}
}
}
public override int IndexOf(T item)
{
if (entireTree) {
if (reversed)
return mySet.Count - 1 - mySet.IndexOf(item);
else
return mySet.IndexOf(item);
}
else {
T dummy;
if (rangeTester(item) != 0)
return -1;
if (reversed) {
int indexInSet = mySet.tree.FindIndex(item, false);
if (indexInSet < 0)
return -1;
int indexOfEnd = mySet.tree.LastItemInRange(rangeTester, out dummy);
return indexOfEnd - indexInSet;
}
else {
int indexInSet = mySet.tree.FindIndex(item, true);
if (indexInSet < 0)
return -1;
int indexOfStart = mySet.tree.FirstItemInRange(rangeTester, out dummy);
return indexInSet - indexOfStart;
}
}
}
}
#endregion Read-only list view
#region Sub-views
///
/// Returns a View collection that can be used for enumerating the items in the set in
/// reversed order.
///
///
///Typically, this method is used in conjunction with a foreach statement. For example:
///
/// foreach(T item in set.Reversed()) {
/// // process item
/// }
///
/// If an item is added to or deleted from the set while the View is being enumerated, then
/// the enumeration will end with an InvalidOperationException.
///Calling Reverse does not copy the data in the tree, and the operation takes constant time.
///
/// An OrderedSet.View of items in reverse order.
public View Reversed() // A reversed view that can be enumerated
{
return new View(this, tree.EntireRangeTester, true, true);
}
///
/// Returns a View collection that can be used for enumerating a range of the items in the set..
/// Only items that are greater than and
/// less than are included. The items are enumerated in sorted order.
/// Items equal to the end points of the range can be included or excluded depending on the
/// and parameters.
///
///
///If is greater than , the returned collection is empty.
///Typically, this method is used in conjunction with a foreach statement. For example:
///
/// foreach(T item in set.Range(from, true, to, false)) {
/// // process item
/// }
///
/// If an item is added to or deleted from the set while the View is being enumerated, then
/// the enumeration will end with an InvalidOperationException.
///Calling Range does not copy the data in the tree, and the operation takes constant time.
///
/// The lower bound of the range.
/// If true, the lower bound is inclusive--items equal to the lower bound will
/// be included in the range. If false, the lower bound is exclusive--items equal to the lower bound will not
/// be included in the range.
/// The upper bound of the range.
/// If true, the upper bound is inclusive--items equal to the upper bound will
/// be included in the range. If false, the upper bound is exclusive--items equal to the upper bound will not
/// be included in the range.
/// An OrderedSet.View of items in the given range.
public View Range(T from, bool fromInclusive, T to, bool toInclusive) // A partial view that can be enumerated
{
return new View(this, tree.DoubleBoundedRangeTester(from, fromInclusive, to, toInclusive), false, false);
}
///
/// Returns a View collection that can be used for enumerating a range of the items in the set..
/// Only items that are greater than (and optionally, equal to) are included.
/// The items are enumerated in sorted order. Items equal to can be included
/// or excluded depending on the parameter.
///
///
///Typically, this method is used in conjunction with a foreach statement. For example:
///
/// foreach(T item in set.RangeFrom(from, true)) {
/// // process item
/// }
///
/// If an item is added to or deleted from the set while the View is being enumerated, then
/// the enumeration will end with an InvalidOperationException.
///Calling RangeFrom does not copy the data in the tree, and the operation takes constant time.
///
/// The lower bound of the range.
/// If true, the lower bound is inclusive--items equal to the lower bound will
/// be included in the range. If false, the lower bound is exclusive--items equal to the lower bound will not
/// be included in the range.
/// An OrderedSet.View of items in the given range.
public View RangeFrom(T from, bool fromInclusive) // A partial view that can be enumerated
{
return new View(this, tree.LowerBoundedRangeTester(from, fromInclusive), false, false);
}
///
/// Returns a View collection that can be used for enumerating a range of the items in the set..
/// Only items that are less than (and optionally, equal to) are included.
/// The items are enumerated in sorted order. Items equal to can be included
/// or excluded depending on the parameter.
///
///
///Typically, this method is used in conjunction with a foreach statement. For example:
///
/// foreach(T item in set.RangeTo(to, false)) {
/// // process item
/// }
///
/// If an item is added to or deleted from the set while the View is being enumerated, then
/// the enumeration will end with an InvalidOperationException.
///Calling RangeTo does not copy the data in the tree, and the operation takes constant time.
///
/// The upper bound of the range.
/// If true, the upper bound is inclusive--items equal to the upper bound will
/// be included in the range. If false, the upper bound is exclusive--items equal to the upper bound will not
/// be included in the range.
/// An OrderedSet.View of items in the given range.
public View RangeTo(T to, bool toInclusive) // A partial view that can be enumerated
{
return new View(this, tree.UpperBoundedRangeTester(to, toInclusive), false, false);
}
#endregion
#region View nested class
///
/// The OrderedSet<T>.View class is used to look at a subset of the Items
/// inside an ordered set. It is returned from the Range, RangeTo, RangeFrom, and Reversed methods.
///
///
/// Views are dynamic. If the underlying set changes, the view changes in sync. If a change is made
/// to the view, the underlying set changes accordingly.
///Typically, this class is used in conjunction with a foreach statement to enumerate the items
/// in a subset of the OrderedSet. For example:
///
/// foreach(T item in set.Range(from, to)) {
/// // process item
/// }
///
///
[Serializable]
public class View : CollectionBase, ICollection
{
private OrderedSet mySet;
private RedBlackTree.RangeTester rangeTester; // range tester for the range being used.
private bool entireTree; // is the view the whole tree?
private bool reversed; // is the view reversed?
///
/// Initialize the view.
///
/// OrderedSet being viewed
/// Range tester that defines the range being used.
/// If true, then rangeTester defines the entire tree. Used to optimize some operations.
/// Is the view enuemerated in reverse order?
internal View(OrderedSet mySet, RedBlackTree.RangeTester rangeTester, bool entireTree, bool reversed)
{
this.mySet = mySet;
this.rangeTester = rangeTester;
this.entireTree = entireTree;
this.reversed = reversed;
}
///
/// Determine if the given item lies within the bounds of this view.
///
/// Item to test.
/// True if the item is within the bounds of this view.
private bool ItemInView(T item)
{
return rangeTester(item) == 0;
}
///
/// Enumerate all the items in this view.
///
/// An IEnumerator<T> with the items in this view.
public sealed override IEnumerator GetEnumerator()
{
if (reversed)
return mySet.tree.EnumerateRangeReversed(rangeTester).GetEnumerator();
else
return mySet.tree.EnumerateRange(rangeTester).GetEnumerator();
}
///
/// Number of items in this view.
///
/// Number of items that lie within the bounds the view.
public sealed override int Count
{
get {
if (entireTree)
return mySet.Count;
else {
// Note: we can't cache the result of this call because the underlying
// set can change, which would make the cached value incorrect.
return mySet.tree.CountRange(rangeTester);
}
}
}
///
/// Removes all the items within this view from the underlying set.
///
/// The following removes all the items that start with "A" from an OrderedSet.
///
/// set.Range("A", "B").Clear();
///
///
public sealed override void Clear()
{
if (entireTree) {
mySet.Clear(); // much faster than DeleteRange
}
else {
mySet.tree.DeleteRange(rangeTester);
}
}
///
/// Adds a new item to the set underlying this View. If the set already contains an item equal to
/// , that item is replaces with . If
/// is outside the range of this view, an InvalidOperationException
/// is thrown.
///
///
/// Equality between items is determined by the comparison instance or delegate used
/// to create the set.
/// Adding an item takes time O(log N), where N is the number of items in the set.
/// The item to add.
/// True if the set already contained an item equal to (which was replaced), false
/// otherwise.
public new bool Add(T item)
{
if (!ItemInView(item))
throw new ArgumentException(Strings.OutOfViewRange, "item");
else
return mySet.Add(item);
}
///
/// Adds a new item to the set underlying this View. If the set already contains an item equal to
/// , that item is replaces with . If
/// is outside the range of this view, an InvalidOperationException
/// is thrown.
///
///
/// Equality between items is determined by the comparison instance or delegate used
/// to create the set.
/// Adding an item takes time O(log N), where N is the number of items in the set.
/// The item to add.
void ICollection.Add(T item)
{
Add(item);
}
///
/// Searches the underlying set for an item equal to , and if found,
/// removes it from the set. If not found, the set is unchanged. If the item is outside
/// the range of this view, the set is unchanged.
///
///
/// Equality between items is determined by the comparison instance or delegate used
/// to create the set.
/// Removing an item from the set takes time O(log N), where N is the number of items in the set.
/// The item to remove.
/// True if was found and removed. False if was not in the set, or
/// was outside the range of this view.
public sealed override bool Remove(T item)
{
if (!ItemInView(item))
return false;
else
return mySet.Remove(item);
}
///
/// Determines if this view of the set contains an item equal to . The set
/// is not changed. If
///
/// Searching the set for an item takes time O(log N), where N is the number of items in the set.
/// The item to search for.
/// True if the set contains , and is within
/// the range of this view. False otherwise.
public sealed override bool Contains(T item)
{
if (!ItemInView(item))
return false;
else
return mySet.Contains(item);
}
///
/// Get the index of the given item in the view. The smallest item in the view has index 0,
/// the next smallest item has index 1, and the largest item has index Count-1.
///
/// Finding the index takes time O(log N), which N is the number of items in
/// the set.
/// The item to get the index of.
/// The index of the item in the view, or -1 if the item is not present
/// in the view.
public int IndexOf(T item)
{
if (entireTree) {
if (reversed) {
int indexInSet = mySet.tree.FindIndex(item, false);
if (indexInSet < 0)
return -1;
return mySet.Count - 1 - indexInSet;
}
else {
return mySet.tree.FindIndex(item, true);
}
}
else {
T dummy;
if (!ItemInView(item))
return -1;
if (reversed) {
int indexInSet = mySet.tree.FindIndex(item, false);
if (indexInSet < 0)
return -1;
int indexOfEnd = mySet.tree.LastItemInRange(rangeTester, out dummy);
return indexOfEnd - indexInSet;
}
else {
int indexInSet = mySet.tree.FindIndex(item, true);
if (indexInSet < 0)
return -1;
int indexOfStart = mySet.tree.FirstItemInRange(rangeTester, out dummy);
return indexInSet - indexOfStart;
}
}
}
///
/// Get the item by its index in the sorted order. The smallest item in the view has index 0,
/// the next smallest item has index 1, and the largest item has index Count-1.
///
/// The indexer takes time O(log N), which N is the number of items in
/// the set.
/// The index to get the item by.
/// The item at the given index.
/// is
/// less than zero or greater than or equal to Count.
public T this[int index]
{
get
{
if (entireTree) {
if (reversed) {
return mySet[mySet.Count - 1 - index];
}
else {
return mySet[index];
}
}
else {
T dummy;
int firstIndex = mySet.tree.FirstItemInRange(rangeTester, out dummy);
int lastIndex = mySet.tree.LastItemInRange(rangeTester, out dummy);
if (firstIndex < 0 || lastIndex < 0 || index < 0 || index >= (lastIndex - firstIndex + 1))
throw new ArgumentOutOfRangeException("index");
if (reversed)
return mySet[lastIndex - index];
else
return mySet[firstIndex + index];
}
}
}
///
/// Get a read-only list view of the items in this view. The
/// items in the list are in sorted order, with the smallest item
/// at index 0. This view does not copy any data, and reflects any
/// changes to the underlying OrderedSet.
///
/// A read-only IList<T> view onto this view.
public IList AsList()
{
return new ListView(mySet, rangeTester, entireTree, reversed);
}
///
/// Creates a new View that has the same items as this view, in the reversed order.
///
/// A new View that has the reversed order of this view, with the same upper
/// and lower bounds.
public View Reversed()
{
return new View(mySet, rangeTester, entireTree, !reversed);
}
///
/// Returns the first item in this view: the item
/// that would appear first if the view was enumerated.
///
/// GetFirst() takes time O(log N), where N is the number of items in the set.
/// The first item in the view.
/// The view has no items in it.
public T GetFirst()
{
T item;
int found;
if (reversed)
found = mySet.tree.LastItemInRange(rangeTester, out item);
else
found = mySet.tree.FirstItemInRange(rangeTester, out item);
if (found < 0)
throw new InvalidOperationException(Strings.CollectionIsEmpty);
return item;
}
///
/// Returns the last item in the view: the item
/// that would appear last if the view was enumerated.
///
/// GetLast() takes time O(log N), where N is the number of items in the set.
/// The last item in the view.
/// The view has no items in it.
public T GetLast()
{
T item;
int found;
if (reversed)
found = mySet.tree.FirstItemInRange(rangeTester, out item);
else
found = mySet.tree.LastItemInRange(rangeTester, out item);
if (found < 0)
throw new InvalidOperationException(Strings.CollectionIsEmpty);
return item;
}
}
#endregion
}
}