/*
Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using System.Diagnostics;
using SCG = System.Collections.Generic;
namespace C5
{
///
/// A collection class implementing a sorted dynamic array data structure.
///
[Serializable]
public class SortedArray : ArrayBase, IIndexedSorted
{
#region Features
///
/// A debugging artifact. To be removed.
///
[Flags]
public enum Feature : short
{
///
/// A debugging artifact. To be removed.
///
Standard = 0
}
static Feature features = Feature.Standard;
///
/// A debugging artifact. To be removed.
///
///
public static Feature Features { get { return features; } }
#endregion
#region Events
///
///
///
///
public override EventTypeEnum ListenableEvents { get { return EventTypeEnum.Basic; } }
#endregion
#region Fields
SCG.IComparer comparer;
#endregion
#region Util
///
///
///
/// The item to search for
/// The least index, mid, for which array[mid] >= item
/// True if item found
private bool binarySearch(T item, out int mid)
{
int bot = 0, top = size;
mid = top / 2;
while (top > bot)
{
int c;
if ((c = comparer.Compare(array[mid], item)) == 0)
return true;
if (c > 0)
{ top = mid; }
else
{ bot = mid + 1; }
mid = (bot + top) / 2;
}
return false;
}
private int indexOf(T item)
{
int ind;
if (binarySearch(item, out ind))
return ind;
return ~ind;
}
#endregion
#region Constructors
///
/// Create a dynamic sorted array with a natural comparer
/// (and item equalityComparer, assumed compatible)
///
/// If T
is not comparable.
///
public SortedArray() : this(8) { }
///
/// Create a dynamic sorted array with a natural comparer
/// (and item equalityComparer, assumed compatible)
/// and prescribed initial capacity.
///
/// If T
is not comparable.
///
/// The capacity
public SortedArray(int capacity)
: this(capacity, Comparer.Default, EqualityComparer.Default) { }
///
/// Create a dynamic sorted array with an external comparer.
/// The itemequalityComparer will be compatible
/// since the
/// default equalityComparer for T ()
/// is unlikely to be compatible with the external comparer. This makes the
/// array inadequate for use as item in a collection of unsequenced or sequenced sets or bags
/// ( and )
///
///
/// The comparer
public SortedArray(SCG.IComparer comparer)
: this(8, comparer) { }
///
/// Create a dynamic sorted array with an external comparer
/// and prescribed initial capacity.
/// The itemequalityComparer will be a compatible
/// since the
/// default equalityComparer for T ()
/// is unlikely to be compatible with the external comparer. This makes the
/// sorted array inadequate for use as item in a collection of unsequenced or sequenced sets or bags
/// ( and )
///
///
/// The capacity
/// The comparer
public SortedArray(int capacity, SCG.IComparer comparer)
: this(capacity, comparer, new ComparerZeroHashCodeEqualityComparer(comparer)) { }
///
/// Create a dynamic sorted array with an external comparer, an external item equalityComparer
/// and prescribed initial capacity. This is the constructor to use if the collection
/// will be used as item in a hash table based collection.
///
/// The capacity
/// The item comparer
/// The item equalityComparer (assumed compatible)
public SortedArray(int capacity, SCG.IComparer comparer, SCG.IEqualityComparer equalityComparer)
: base(capacity, equalityComparer)
{
if (comparer == null)
throw new NullReferenceException("Comparer cannot be null");
this.comparer = comparer;
}
#endregion
#region IIndexedSorted Members
///
/// Determine the number of items at or above a supplied threshold.
///
/// The lower bound (inclusive)
/// The number of matcing items.
[Tested]
public int CountFrom(T bot)
{
int lo;
binarySearch(bot, out lo);
return size - lo;
}
///
/// Determine the number of items between two supplied thresholds.
///
/// The lower bound (inclusive)
/// The upper bound (exclusive)
/// The number of matcing items.
[Tested]
public int CountFromTo(T bot, T top)
{
int lo, hi;
binarySearch(bot, out lo);
binarySearch(top, out hi);
return hi > lo ? hi - lo : 0;
}
///
/// Determine the number of items below a supplied threshold.
///
/// The upper bound (exclusive)
/// The number of matcing items.
[Tested]
public int CountTo(T top)
{
int hi;
binarySearch(top, out hi);
return hi;
}
///
/// Query this sorted collection for items greater than or equal to a supplied value.
///
/// The lower bound (inclusive).
/// The result directed collection.
[Tested]
public IDirectedCollectionValue RangeFrom(T bot)
{
int lo;
binarySearch(bot, out lo);
return new Range(this, lo, size - lo, true);
}
///
/// Query this sorted collection for items between two supplied values.
///
/// The lower bound (inclusive).
/// The upper bound (exclusive).
/// The result directed collection.
[Tested]
public IDirectedCollectionValue RangeFromTo(T bot, T top)
{
int lo, hi;
binarySearch(bot, out lo);
binarySearch(top, out hi);
int sz = hi - lo;
return new Range(this, lo, sz, true);
}
///
/// Query this sorted collection for items less than a supplied value.
///
/// The upper bound (exclusive).
/// The result directed collection.
[Tested]
public IDirectedCollectionValue RangeTo(T top)
{
int hi;
binarySearch(top, out hi);
return new Range(this, 0, hi, true);
}
///
/// Create a new indexed sorted collection consisting of the items of this
/// indexed sorted collection satisfying a certain predicate.
///
/// The filter delegate defining the predicate.
/// The new indexed sorted collection.
[Tested]
public IIndexedSorted FindAll(Fun f)
{
SortedArray res = new SortedArray(comparer);
int j = 0, rescap = res.array.Length;
for (int i = 0; i < size; i++)
{
T a = array[i];
if (f(a))
{
if (j == rescap) res.expand(rescap = 2 * rescap, j);
res.array[j++] = a;
}
}
res.size = j;
return res;
}
///
/// Create a new indexed sorted collection consisting of the results of
/// mapping all items of this list.
/// if the map is not increasing over
/// the items of this collection (with respect to the two given comparison
/// relations).
///
/// The delegate definging the map.
/// The comparion relation to use for the result.
/// The new sorted collection.
[Tested]
public IIndexedSorted Map(Fun m, SCG.IComparer c)
{
SortedArray res = new SortedArray(size, c);
if (size > 0)
{
V oldv = res.array[0] = m(array[0]), newv;
for (int i = 1; i < size; i++)
{
if (c.Compare(oldv, newv = res.array[i] = m(array[i])) >= 0)
throw new ArgumentException("mapper not monotonic");
oldv = newv;
}
}
res.size = size;
return res;
}
#endregion
#region ISorted Members
///
/// Find the strict predecessor of item in the sorted array,
/// that is, the greatest item in the collection smaller than the item.
///
/// The item to find the predecessor for.
/// The predecessor, if any; otherwise the default value for T.
/// True if item has a predecessor; otherwise false.
public bool TryPredecessor(T item, out T res)
{
int lo;
binarySearch(item, out lo);
if (lo == 0)
{
res = default(T);
return false;
}
else
{
res = array[lo - 1];
return true;
}
}
///
/// Find the strict successor of item in the sorted array,
/// that is, the least item in the collection greater than the supplied value.
///
/// The item to find the successor for.
/// The successor, if any; otherwise the default value for T.
/// True if item has a successor; otherwise false.
public bool TrySuccessor(T item, out T res)
{
int hi;
if (binarySearch(item, out hi))
hi++;
if (hi >= size)
{
res = default(T);
return false;
} else {
res = array[hi];
return true;
}
}
///
/// Find the weak predecessor of item in the sorted array,
/// that is, the greatest item in the collection smaller than or equal to the item.
///
/// The item to find the weak predecessor for.
/// The weak predecessor, if any; otherwise the default value for T.
/// True if item has a weak predecessor; otherwise false.
public bool TryWeakPredecessor(T item, out T res)
{
int lo;
if (!binarySearch(item, out lo))
lo--;
if (lo < 0)
{
res = default(T);
return false;
}
else
{
res = array[lo];
return true;
}
}
///
/// Find the weak successor of item in the sorted array,
/// that is, the least item in the collection greater than or equal to the supplied value.
///
/// The item to find the weak successor for.
/// The weak successor, if any; otherwise the default value for T.
/// True if item has a weak successor; otherwise false.
public bool TryWeakSuccessor(T item, out T res)
{
int hi;
binarySearch(item, out hi);
if (hi >= size)
{
res = default(T);
return false;
}
else
{
res = array[hi];
return true;
}
}
///
/// Find the strict predecessor in the sorted collection of a particular value,
/// i.e. the largest item in the collection less than the supplied value.
///
/// if no such element exists (the
/// supplied value is less than or equal to the minimum of this collection.)
/// The item to find the predecessor for.
/// The predecessor.
[Tested]
public T Predecessor(T item)
{
int lo;
binarySearch(item, out lo);
if (lo == 0)
throw new NoSuchItemException();
return array[lo - 1];
}
///
/// Find the strict successor in the sorted collection of a particular value,
/// i.e. the least item in the collection greater than the supplied value.
///
/// if no such element exists (the
/// supplied value is greater than or equal to the maximum of this collection.)
/// The item to find the successor for.
/// The successor.
[Tested]
public T Successor(T item)
{
int hi;
if (binarySearch(item, out hi)) hi++;
if (hi >= size)
throw new NoSuchItemException();
return array[hi];
}
///
/// Find the weak predecessor in the sorted collection of a particular value,
/// i.e. the largest item in the collection less than or equal to the supplied value.
/// if no such element exists (the
/// supplied value is less than the minimum of this collection.)
///
/// The item to find the weak predecessor for.
/// The weak predecessor.
[Tested]
public T WeakPredecessor(T item)
{
int lo;
if (!binarySearch(item, out lo)) lo--;
if (lo < 0)
throw new NoSuchItemException();
return array[lo];
}
///
/// Find the weak successor in the sorted collection of a particular value,
/// i.e. the least item in the collection greater than or equal to the supplied value.
///
/// if no such element exists (the
/// supplied value is greater than the maximum of this collection.)
/// The item to find the weak successor for.
/// The weak successor.
[Tested]
public T WeakSuccessor(T item)
{
int hi;
binarySearch(item, out hi);
if (hi >= size)
throw new NoSuchItemException();
return array[hi];
}
///
/// Perform a search in the sorted collection for the ranges in which a
/// non-increasing (i.e. weakly decrerasing) function from the item type to
/// int
is
/// negative, zero respectively positive. If the supplied cut function is
/// not non-increasing, the result of this call is undefined.
///
/// The cut function T
to int
, given
/// as an IComparable<T>
object, where the cut function is
/// the c.CompareTo(T that)
method.
/// Returns the largest item in the collection, where the
/// cut function is positive (if any).
/// True if the cut function is positive somewhere
/// on this collection.
/// Returns the least item in the collection, where the
/// cut function is negative (if any).
/// True if the cut function is negative somewhere
/// on this collection.
///
[Tested]
public bool Cut(IComparable c, out T low, out bool lowIsValid, out T high, out bool highIsValid)
{
int lbest = -1, rbest = size;
low = default(T);
lowIsValid = false;
high = default(T);
highIsValid = false;
int bot = 0, top = size, mid, comp = -1, sol;
mid = top / 2;
while (top > bot)
{
if ((comp = c.CompareTo(array[mid])) == 0)
break;
if (comp < 0)
{ rbest = top = mid; }
else
{ lbest = mid; bot = mid + 1; }
mid = (bot + top) / 2;
}
if (comp != 0)
{
if (lbest >= 0) { lowIsValid = true; low = array[lbest]; }
if (rbest < size) { highIsValid = true; high = array[rbest]; }
return false;
}
sol = mid;
bot = sol - 1;
//Invariant: c.Compare(array[x]) < 0 when rbest <= x < size
// c.Compare(array[x]) >= 0 when x < bot)
//(Assuming c.Compare monotonic)
while (rbest > bot)
{
mid = (bot + rbest) / 2;
if (c.CompareTo(array[mid]) < 0)
{ rbest = mid; }
else
{ bot = mid + 1; }
}
if (rbest < size) { highIsValid = true; high = array[rbest]; }
top = sol + 1;
//Invariant: c.Compare(array[x]) > 0 when 0 <= x <= lbest
// c.Compare(array[x]) <= 0 when x>top)
//(Assuming c.Compare monotonic)
while (top > lbest)
{
mid = (lbest + top + 1) / 2;
if (c.CompareTo(array[mid]) > 0)
{ lbest = mid; }
else
{ top = mid - 1; }
}
if (lbest >= 0) { lowIsValid = true; low = array[lbest]; }
return true;
}
IDirectedEnumerable ISorted.RangeFrom(T bot)
{ return RangeFrom(bot); }
IDirectedEnumerable ISorted.RangeFromTo(T bot, T top)
{ return RangeFromTo(bot, top); }
IDirectedEnumerable ISorted.RangeTo(T top)
{ return RangeTo(top); }
///
/// Create a directed collection with the same items as this collection.
///
/// The result directed collection.
[Tested]
public IDirectedCollectionValue RangeAll()
{ return new Range(this, 0, size, true); }
///
/// Add all the items from another collection with an enumeration order that
/// is increasing in the items.
/// if the enumerated items turns out
/// not to be in increasing order.
///
/// The collection to add.
///
[Tested]
public void AddSorted(SCG.IEnumerable items) where U : T
{
//Unless items have <=1 elements we would expect it to be
//too expensive to do repeated inserts, thus:
updatecheck();
int j = 0, i = 0, c = -1, itemcount = EnumerableBase.countItems(items), numAdded = 0;
SortedArray res = new SortedArray(size + itemcount, comparer);
T lastitem = default(T);
T[] addedItems = new T[itemcount];
foreach (T item in items)
{
while (i < size && (c = comparer.Compare(array[i], item)) <= 0)
{
lastitem = res.array[j++] = array[i++];
if (c == 0)
goto next;
}
if (j > 0 && comparer.Compare(lastitem, item) >= 0)
throw new ArgumentException("Argument not sorted");
addedItems[numAdded++] = lastitem = res.array[j++] = item;
next:
c = -1;
}
while (i < size) res.array[j++] = array[i++];
size = j;
array = res.array;
raiseForAddAll(addedItems, numAdded);
}
///
/// Remove all items of this collection above or at a supplied threshold.
///
/// The lower threshold (inclusive).
[Tested]
public void RemoveRangeFrom(T low)
{
int lowind;
binarySearch(low, out lowind);
if (lowind == size)
return;
T[] removed = new T[size - lowind];
Array.Copy(array, lowind, removed, 0, removed.Length);
Array.Reverse(removed);
Array.Clear(array, lowind, size - lowind);
size = lowind;
raiseForRemoveRange(removed);
}
///
/// Remove all items of this collection between two supplied thresholds.
///
/// The lower threshold (inclusive).
/// The upper threshold (exclusive).
[Tested]
public void RemoveRangeFromTo(T low, T hi)
{
int lowind, highind;
binarySearch(low, out lowind);
binarySearch(hi, out highind);
if (highind <= lowind)
return;
T[] removed = new T[highind - lowind];
Array.Copy(array, lowind, removed, 0, removed.Length);
Array.Reverse(removed);
Array.Copy(array, highind, array, lowind, size - highind);
Array.Clear(array, size - highind + lowind, highind - lowind);
size -= highind - lowind;
raiseForRemoveRange(removed);
}
///
/// Remove all items of this collection below a supplied threshold.
///
/// The upper threshold (exclusive).
[Tested]
public void RemoveRangeTo(T hi)
{
int highind;
binarySearch(hi, out highind);
if (highind == 0)
return;
T[] removed = new T[highind];
Array.Copy(array, 0, removed, 0, removed.Length);
Array.Copy(array, highind, array, 0, size - highind);
Array.Clear(array, size - highind, highind);
size = size - highind;
raiseForRemoveRange(removed);
}
private void raiseForRemoveRange(T[] removed)
{
foreach(T item in removed)
raiseItemsRemoved(item, 1);
if(removed.Length > 0)
raiseCollectionChanged();
}
#endregion
#region ICollection Members
///
/// The value is symbolic indicating the type of asymptotic complexity
/// in terms of the size of this collection (worst-case).
///
/// Speed.Log
[Tested]
public Speed ContainsSpeed { [Tested]get { return Speed.Log; } }
///
/// Remove all items from this collection, resetting internal array size.
///
[Tested]
override public void Clear()
{
int oldCount = size;
base.Clear();
if(oldCount > 0)
{
raiseCollectionCleared(true, oldCount);
raiseCollectionChanged();
}
}
///
/// Check if this collection contains (an item equivalent according to the
/// itemequalityComparer) to a particular value.
///
/// The value to check for.
/// True if the items is in this collection.
[Tested]
public bool Contains(T item)
{
int ind;
return binarySearch(item, out ind);
}
///
/// Check if this collection contains an item equivalent according to the
/// itemequalityComparer to a particular value. If so, return in the ref argument (a
/// binary copy of) the actual value found.
///
/// The value to look for.
/// True if the items is in this collection.
[Tested]
public bool Find(ref T item)
{
int ind;
if (binarySearch(item, out ind))
{
item = array[ind];
return true;
}
return false;
}
//This should probably just be bool Add(ref T item); !!!
///
/// Check if this collection contains an item equivalent according to the
/// itemequalityComparer to a particular value. If so, return in the ref argument (a
/// binary copy of) the actual value found. Else, add the item to the collection.
///
/// The value to look for.
/// True if the item was added (hence not found).
[Tested]
public bool FindOrAdd(ref T item)
{
updatecheck();
int ind;
if (binarySearch(item, out ind))
{
item = array[ind];
return true;
}
if (size == array.Length) expand();
Array.Copy(array, ind, array, ind + 1, size - ind);
array[ind] = item;
size++;
raiseForAdd(item);
return false;
}
///
/// Check if this collection contains an item equivalent according to the
/// itemequalityComparer to a particular value. If so, update the item in the collection
/// to with a binary copy of the supplied value. If the collection has bag semantics,
/// it is implementation dependent if this updates all equivalent copies in
/// the collection or just one.
///
/// Value to update.
/// True if the item was found and hence updated.
[Tested]
public bool Update(T item)
{ T olditem; return Update(item, out olditem); }
///
///
///
///
///
///
public bool Update(T item, out T olditem)
{
updatecheck();
int ind;
if (binarySearch(item, out ind))
{
olditem = array[ind];
array[ind] = item;
raiseForUpdate(item, olditem);
return true;
}
olditem = default(T);
return false;
}
///
/// Check if this collection contains an item equivalent according to the
/// itemequalityComparer to a particular value. If so, update the item in the collection
/// to with a binary copy of the supplied value; else add the value to the collection.
///
/// Value to add or update.
/// True if the item was found and updated (hence not added).
[Tested]
public bool UpdateOrAdd(T item)
{ T olditem; return UpdateOrAdd(item, out olditem); }
///
///
///
///
///
///
public bool UpdateOrAdd(T item, out T olditem)
{
updatecheck();
int ind;
if (binarySearch(item, out ind))
{
olditem = array[ind];
array[ind] = item;
raiseForUpdate(item, olditem);
return true;
}
if (size == array.Length) expand();
Array.Copy(array, ind, array, ind + 1, size - ind);
array[ind] = item;
size++;
olditem = default(T);
raiseForAdd(item);
return false;
}
///
/// Remove a particular item from this collection. If the collection has bag
/// semantics only one copy equivalent to the supplied item is removed.
///
/// The value to remove.
/// True if the item was found (and removed).
[Tested]
public bool Remove(T item)
{
int ind;
updatecheck();
if (binarySearch(item, out ind))
{
T removeditem = array[ind];
Array.Copy(array, ind + 1, array, ind, size - ind - 1);
array[--size] = default(T);
raiseForRemove(removeditem);
return true;
}
return false;
}
///
/// Remove a particular item from this collection if found. If the collection
/// has bag semantics only one copy equivalent to the supplied item is removed,
/// which one is implementation dependent.
/// If an item was removed, report a binary copy of the actual item removed in
/// the argument.
///
/// The value to remove.
/// The removed value.
/// True if the item was found (and removed).
[Tested]
public bool Remove(T item, out T removeditem)
{
int ind;
updatecheck();
if (binarySearch(item, out ind))
{
removeditem = array[ind];
Array.Copy(array, ind + 1, array, ind, size - ind - 1);
array[--size] = default(T);
raiseForRemove(removeditem);
return true;
}
removeditem = default(T);
return false;
}
///
/// Remove all items in another collection from this one.
///
///
/// The items to remove.
[Tested]
public void RemoveAll(SCG.IEnumerable items) where U : T
{
//This is O(m*logn) with n bits extra storage
//(Not better to collect the m items and sort them)
updatecheck();
RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(this);
bool mustFire = raiseHandler.MustFire;
int[] toremove = new int[(size >> 5) + 1];
int ind, j = 0;
foreach (T item in items)
if (binarySearch(item, out ind))
toremove[ind >> 5] |= 1 << (ind & 31);
for (int i = 0; i < size; i++)
if ((toremove[i >> 5] & (1 << (i & 31))) == 0)
array[j++] = array[i];
else if (mustFire)
raiseHandler.Remove(array[i]);
Array.Clear(array, j, size - j);
size = j;
if (mustFire)
raiseHandler.Raise();
}
///
/// Remove all items not in some other collection from this one.
///
///
/// The items to retain.
[Tested]
public void RetainAll(SCG.IEnumerable items) where U : T
{
//This is O(m*logn) with n bits extra storage
//(Not better to collect the m items and sort them)
updatecheck();
RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(this);
bool mustFire = raiseHandler.MustFire;
int[] toretain = new int[(size >> 5) + 1];
int ind, j = 0;
foreach (T item in items)
if (binarySearch(item, out ind))
toretain[ind >> 5] |= 1 << (ind & 31);
for (int i = 0; i < size; i++)
if ((toretain[i >> 5] & (1 << (i & 31))) != 0)
array[j++] = array[i];
else if (mustFire)
raiseHandler.Remove(array[i]);
Array.Clear(array, j, size - j);
size = j;
if (mustFire)
raiseHandler.Raise();
}
///
/// Check if this collection contains all the values in another collection.
/// Multiplicities are not taken into account.
///
/// The
///
/// True if all values in items
is in this collection.
[Tested]
public bool ContainsAll(SCG.IEnumerable items) where U : T
{
int tmp;
foreach (T item in items)
if (!binarySearch(item, out tmp))
return false;
return true;
}
///
/// Count the number of items of the collection equal to a particular value.
/// Returns 0 if and only if the value is not in the collection.
///
/// The value to count.
/// The number of copies found (0 or 1).
[Tested]
public int ContainsCount(T item)
{
int tmp;
return binarySearch(item, out tmp) ? 1 : 0;
}
///
///
///
///
public virtual ICollectionValue UniqueItems() { return this; }
///
///
///
///
public virtual ICollectionValue> ItemMultiplicities()
{
return new MultiplicityOne(this);
}
///
/// Remove all (0 or 1) items equivalent to a given value.
///
/// The value to remove.
[Tested]
public void RemoveAllCopies(T item) { Remove(item); }
///
/// Check the integrity of the internal data structures of this collection.
/// Only avaliable in DEBUG builds???
///
/// True if check does not fail.
[Tested]
public override bool Check()
{
bool retval = true;
if (size > array.Length)
{
Console.WriteLine("Bad size ({0}) > array.Length ({1})", size, array.Length);
return false;
}
for (int i = 0; i < size; i++)
{
if ((object)(array[i]) == null)
{
Console.WriteLine("Bad element: null at index {0}", i);
return false;
}
if (i > 0 && comparer.Compare(array[i], array[i - 1]) <= 0)
{
Console.WriteLine("Inversion at index {0}", i);
retval = false;
}
}
return retval;
}
#endregion
#region IExtensible Members
///
///
///
/// False since this collection has set semantics
[Tested]
public bool AllowsDuplicates { [Tested]get { return false; } }
///
/// By convention this is true for any collection with set semantics.
///
/// True if only one representative of a group of equal items
/// is kept in the collection together with the total count.
public virtual bool DuplicatesByCounting { get { return true; } }
///
/// Add an item to this collection if possible. If this collection has set
/// semantics, the item will be added if not already in the collection. If
/// bag semantics, the item will always be added.
///
/// The item to add.
/// True if item was added.
[Tested]
public bool Add(T item)
{
updatecheck();
int ind;
if (binarySearch(item, out ind)) return false;
insert(ind, item);
raiseForAdd(item);
return true;
}
///
/// Add an item to this collection if possible.
///
/// The item to add.
[Tested]
void SCG.ICollection.Add(T item)
{
Add(item);
}
///
/// Add the elements from another collection with a more specialized item type
/// to this collection. Since this
/// collection has set semantics, only items not already in the collection
/// will be added.
///
/// The type of items to add
/// The items to add
[Tested]
public void AddAll(SCG.IEnumerable items) where U : T
{
int toadd = EnumerableBase.countItems(items), newsize = array.Length;
while (newsize < size + toadd) { newsize *= 2; }
T[] newarr = new T[newsize];
toadd = 0;
foreach (T item in items) newarr[size + toadd++] = item;
Sorting.IntroSort(newarr, size, toadd, comparer);
int j = 0, i = 0, numAdded = 0;
T lastitem = default(T);
T[] addedItems = new T[toadd];
//The following eliminates duplicates (including duplicates in input)
//while merging the old and new collection
for (int k = size, klimit = size + toadd; k < klimit; k++)
{
while (i < size && comparer.Compare(array[i], newarr[k]) <= 0)
lastitem = newarr[j++] = array[i++];
if (j == 0 || comparer.Compare(lastitem, newarr[k]) < 0)
addedItems[numAdded++] = lastitem = newarr[j++] = newarr[k];
}
while (i < size) newarr[j++] = array[i++];
Array.Clear(newarr, j, size + toadd - j);
size = j;
array = newarr;
raiseForAddAll(addedItems, numAdded);
}
private void raiseForAddAll(T[] addedItems, int numAdded)
{
if ((ActiveEvents & EventTypeEnum.Added) != 0)
for(int i = 0 ;i < numAdded; i += 1)
raiseItemsAdded(addedItems[i], 1);
if (numAdded > 0)
raiseCollectionChanged();
}
#endregion
#region IPriorityQueue Members
///
/// Find the current least item of this priority queue.
///
/// The least item.
[Tested]
public T FindMin()
{
if (size == 0)
throw new NoSuchItemException();
return array[0];
}
///
/// Remove the least item from this priority queue.
///
/// The removed item.
[Tested]
public T DeleteMin()
{
updatecheck();
if (size == 0)
throw new NoSuchItemException();
T retval = array[0];
size--;
Array.Copy(array, 1, array, 0, size);
array[size] = default(T);
raiseForRemove(retval);
return retval;
}
///
/// Find the current largest item of this priority queue.
///
/// The largest item.
[Tested]
public T FindMax()
{
if (size == 0)
throw new NoSuchItemException();
return array[size - 1];
}
///
/// Remove the largest item from this priority queue.
///
/// The removed item.
[Tested]
public T DeleteMax()
{
updatecheck();
if (size == 0)
throw new NoSuchItemException();
T retval = array[size - 1];
size--;
array[size] = default(T);
raiseForRemove(retval);
return retval;
}
///
/// The comparer object supplied at creation time for this collection
///
/// The comparer
public SCG.IComparer Comparer { get { return comparer; } }
#endregion
#region IIndexed Members
///
/// if i is negative or
/// >= the size of the collection.
///
/// The i'th item of this list.
/// the index to lookup
[Tested]
public T this[int i]
{
[Tested]
get
{
if (i < 0 || i >= size)
throw new IndexOutOfRangeException();
return array[i];
}
}
///
///
///
///
public virtual Speed IndexingSpeed { get { return Speed.Constant; } }
///
/// Searches for an item in the list going forwrds from the start.
///
/// Item to search for.
/// Index of item from start.
[Tested]
public int IndexOf(T item) { return indexOf(item); }
///
/// Searches for an item in the list going backwords from the end.
///
/// Item to search for.
/// Index of of item from the end.
[Tested]
public int LastIndexOf(T item) { return indexOf(item); }
///
/// Remove the item at a specific position of the list.
/// if i is negative or
/// >= the size of the collection.
///
/// The index of the item to remove.
/// The removed item.
[Tested]
public T RemoveAt(int i)
{
if (i < 0 || i >= size)
throw new IndexOutOfRangeException("Index out of range for sequenced collectionvalue");
updatecheck();
T retval = array[i];
size--;
Array.Copy(array, i + 1, array, i, size - i);
array[size] = default(T);
raiseForRemoveAt(i, retval);
return retval;
}
///
/// Remove all items in an index interval.
/// ???.
///
/// The index of the first item to remove.
/// The number of items to remove.
[Tested]
public void RemoveInterval(int start, int count)
{
updatecheck();
checkRange(start, count);
Array.Copy(array, start + count, array, start, size - start - count);
size -= count;
Array.Clear(array, size, count);
raiseForRemoveInterval(start, count);
}
private void raiseForRemoveInterval(int start, int count)
{
if (ActiveEvents != 0 && count > 0)
{
raiseCollectionCleared(size == 0, count);
raiseCollectionChanged();
}
}
#endregion
#region IDirectedEnumerable Members
///
/// Create a collection containing the same items as this collection, but
/// whose enumerator will enumerate the items backwards. The new collection
/// will become invalid if the original is modified. Method typicaly used as in
/// foreach (T x in coll.Backwards()) {...}
///
/// The backwards collection.
[Tested]
IDirectedEnumerable IDirectedEnumerable.Backwards()
{ return Backwards(); }
#endregion
#region ICloneable Members
///
/// Make a shallow copy of this SortedArray.
///
///
public virtual object Clone()
{
SortedArray clone = new SortedArray(size, comparer, itemequalityComparer);
clone.AddSorted(this);
return clone;
}
#endregion
}
}