using System;
using System.Collections;
using System.Collections.Generic;
namespace SoftConsept.Collections
{
///
/// Collections that holds elements in the specified order. The complexity and efficiency
/// of the algorithm is comparable to the SortedList from .NET collections. In contrast
/// to the SortedList SortedCollection accepts redundant elements. If no comparer is
/// is specified the list will use the default comparer for given type.
///
/// consept
public class SortedCollection : IList
{
// Fields
private const int DEFAULT_CAPACITY = 4;
private static TValue[] emptyValues;
private readonly IComparer comparer;
private TValue[] values;
private int size;
// for enumeration
private int version;
static SortedCollection()
{
emptyValues = new TValue[0];
}
// Constructors
public SortedCollection()
{
this.values = emptyValues;
this.comparer = Comparer.Default;
}
public SortedCollection(IComparer comparer)
{
this.values = emptyValues;
this.comparer = comparer;
}
// Methods
private void CheckCapacity(int min)
{
// double the capacity
int num = this.values.Length == 0 ? DEFAULT_CAPACITY : this.values.Length * 2;
if (min > num)
{
num = min;
}
this.Capacity = num;
}
public virtual void Insert(int index, TValue value)
{
if (value == null)
{
throw new ArgumentException("Value can't be null.");
}
if (index < 0 || index > this.size)
{
throw new ArgumentOutOfRangeException();
}
if (this.size == this.values.Length)
{
this.CheckCapacity(this.size + 1);
}
if (index < this.size)
{
Array.Copy(this.values, index, this.values, index + 1, this.size - index);
}
this.values[index] = value;
this.size++;
this.version++;
}
public void Add(TValue value)
{
if (value == null)
{
throw new ArgumentException("Value can't be null");
}
// check where the element should be placed
int index = Array.BinarySearch(values, 0, this.size, value, this.comparer);
if (index < 0)
{
// xor
index = ~index;
}
Insert(index, value);
}
public virtual void Clear()
{
this.version++;
Array.Clear(this.values, 0, this.size);
this.size = 0;
}
public int IndexOf(TValue value)
{
if (value == null)
{
throw new ArgumentException("Value can't be null.");
}
int index = Array.BinarySearch(values, 0, this.size, value, this.comparer);
if (index >= 0)
{
return index;
}
return -1;
}
public bool Contains(TValue value)
{
return this.IndexOf(value) >= 0;
}
public void CopyTo(TValue[] array, int arrayIndex)
{
Array.Copy(this.values, 0, array, arrayIndex, this.size);
}
public int Count
{
get { return this.size; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(TValue value)
{
int index = this.IndexOf(value);
if (index < 0)
{
return false;
}
RemoveAt(index);
return true;
}
public IEnumerator GetEnumerator()
{
return new SortedCollectionEnumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new SortedCollectionEnumerator(this);
}
// Properties
public int Capacity
{
get { return this.values.Length; }
set
{
if (this.values.Length != value)
{
if (value < this.size)
{
throw new ArgumentException("Too small capacity.");
}
if (value > 0)
{
TValue[] tempValues = new TValue[value];
if (this.size > 0)
{
// copy only when size is greater than zero
Array.Copy(this.values, 0, tempValues, 0, this.size);
}
this.values = tempValues;
}
else
{
this.values = emptyValues;
}
}
}
}
public virtual void RemoveAt(int index)
{
if (index < 0 || index >= this.size)
{
throw new ArgumentOutOfRangeException();
}
this.size--;
this.version++;
Array.Copy(this.values, index + 1, this.values, index, this.size - index);
this.values[this.size] = default(TValue);
}
public virtual TValue this[int index]
{
get
{
if (index < 0 || index >= this.size)
{
throw new ArgumentOutOfRangeException();
}
return this.values[index];
}
set
{
if (index < 0 || index >= this.size)
{
throw new ArgumentOutOfRangeException();
}
this.values[index] = value;
this.version++;
}
}
[Serializable]
private sealed class SortedCollectionEnumerator : IEnumerator, IDisposable, IEnumerator
{
// Fields
private readonly SortedCollection collection;
private TValue currentValue;
private int index;
private int version;
// Methods
internal SortedCollectionEnumerator(SortedCollection collection)
{
this.collection = collection;
this.version = collection.version;
}
public void Dispose()
{
this.index = 0;
this.currentValue = default(TValue);
}
public bool MoveNext()
{
if (this.version != this.collection.version)
{
throw new ArgumentException("Collection was changed while iterating!");
}
if (this.index < this.collection.Count)
{
this.currentValue = this.collection.values[this.index];
this.index++;
return true;
}
this.index = this.collection.Count + 1;
this.currentValue = default(TValue);
return false;
}
void IEnumerator.Reset()
{
if (this.version != this.collection.version)
{
throw new ArgumentException("Collection was changed while iterating!");
}
this.index = 0;
this.currentValue = default(TValue);
}
// Properties
public TValue Current
{
get
{
return this.currentValue;
}
}
object IEnumerator.Current
{
get
{
if ((this.index == 0) || (this.index == this.collection.Count + 1))
{
throw new ArgumentException("Enumerator not initilized. Call MoveNext first.");
}
return this.currentValue;
}
}
}
}
}