#region License Information
/* HeuristicLab
* Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using HeuristicLab.Common;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Collections {
[StorableClass]
[Serializable]
public class ObservableArray : IObservableArray {
[Storable]
protected T[] array;
#region Properties
public int Length {
get { return array.Length; }
}
int ICollection.Count {
get { return array.Length; }
}
bool ICollection.IsReadOnly {
get { return array.IsReadOnly; }
}
public T this[int index] {
get {
return array[index];
}
set {
T item = array[index];
if (!((item == null) && (value == null)) && ((item == null) || (!item.Equals(value)))) {
array[index] = value;
OnItemsReplaced(new IndexedItem[] { new IndexedItem(index, value) }, new IndexedItem[] { new IndexedItem(index, item) });
OnPropertyChanged("Item[]");
}
}
}
#endregion
#region Constructors
public ObservableArray() {
array = new T[0];
}
public ObservableArray(int length) {
array = new T[length];
}
public ObservableArray(T[] array) {
this.array = (T[])array.Clone();
}
public ObservableArray(IEnumerable collection) {
array = collection.ToArray();
}
[StorableConstructor]
protected ObservableArray(bool deserializing) { }
#endregion
#region Access
public bool Contains(T item) {
return IndexOf(item) != -1;
}
public int IndexOf(T item) {
return Array.IndexOf(array, item);
}
public int IndexOf(T item, int startIndex) {
return Array.IndexOf(array, item, startIndex);
}
public int IndexOf(T item, int startIndex, int count) {
return Array.IndexOf(array, item, startIndex, count);
}
public int LastIndexOf(T item) {
return Array.LastIndexOf(array, item);
}
public int LastIndexOf(T item, int startIndex) {
return Array.LastIndexOf(array, item, startIndex);
}
public int LastIndexOf(T item, int startIndex, int count) {
return Array.LastIndexOf(array, item, startIndex, count);
}
public int BinarySearch(T item) {
return Array.BinarySearch(array, item);
}
public int BinarySearch(T item, IComparer comparer) {
return Array.BinarySearch(array, item, comparer);
}
public int BinarySearch(int index, int count, T item) {
return Array.BinarySearch(array, index, count, item);
}
public int BinarySearch(int index, int count, T item, IComparer comparer) {
return Array.BinarySearch(array, index, count, item, comparer);
}
public bool Exists(Predicate match) {
return Array.Exists(array, match);
}
public T Find(Predicate match) {
return Array.Find(array, match);
}
public T[] FindAll(Predicate match) {
return Array.FindAll(array, match);
}
public T FindLast(Predicate match) {
return Array.FindLast(array, match);
}
public int FindIndex(Predicate match) {
return Array.FindIndex(array, match);
}
public int FindIndex(int startIndex, Predicate match) {
return Array.FindIndex(array, startIndex, match);
}
public int FindIndex(int startIndex, int count, Predicate match) {
return Array.FindIndex(array, startIndex, count, match);
}
public int FindLastIndex(Predicate match) {
return Array.FindLastIndex(array, match);
}
public int FindLastIndex(int startIndex, Predicate match) {
return Array.FindLastIndex(array, startIndex, match);
}
public int FindLastIndex(int startIndex, int count, Predicate match) {
return Array.FindLastIndex(array, startIndex, count, match);
}
#endregion
#region Manipulation
void ICollection.Add(T item) {
throw new NotSupportedException();
}
void IList.Insert(int index, T item) {
throw new NotSupportedException();
}
bool ICollection.Remove(T item) {
throw new NotSupportedException();
}
void IList.RemoveAt(int index) {
throw new NotSupportedException();
}
public void Clear(int index, int length) {
if (length > 0) {
IndexedItem[] oldItems = GetIndexedItems(index, length);
Array.Clear(array, index, length);
OnPropertyChanged("Item[]");
OnItemsReplaced(GetIndexedItems(index, length), oldItems);
}
}
void ICollection.Clear() {
Clear(0, array.Length);
}
public void Resize(int newSize) {
if (newSize != array.Length) {
IndexedItem[] oldItems = GetIndexedItems();
Array.Resize(ref array, newSize);
OnPropertyChanged("Length");
OnPropertyChanged("Item[]");
OnCollectionReset(GetIndexedItems(), oldItems);
}
}
public void Reverse() {
if (array.Length > 1) {
IndexedItem[] oldItems = GetIndexedItems();
Array.Reverse(array);
OnPropertyChanged("Item[]");
OnItemsMoved(GetIndexedItems(), oldItems);
}
}
public void Reverse(int index, int length) {
if (length > 1) {
IndexedItem[] oldItems = GetIndexedItems(index, length);
Array.Reverse(array, index, length);
OnPropertyChanged("Item[]");
OnItemsMoved(GetIndexedItems(index, length), oldItems);
}
}
public void Sort() {
if (array.Length > 1) {
IndexedItem[] oldItems = GetIndexedItems();
array.StableSort();
OnPropertyChanged("Item[]");
OnItemsMoved(GetIndexedItems(), oldItems);
}
}
public void Sort(Comparison comparison) {
if (array.Length > 1) {
IndexedItem[] oldItems = GetIndexedItems();
array.StableSort(comparison);
OnPropertyChanged("Item[]");
OnItemsMoved(GetIndexedItems(), oldItems);
}
}
public void Sort(IComparer comparer) {
if (array.Length > 1) {
IndexedItem[] oldItems = GetIndexedItems();
array.StableSort(comparer);
OnPropertyChanged("Item[]");
OnItemsMoved(GetIndexedItems(), oldItems);
}
}
public void Sort(int index, int length) {
if (length > 1) {
IndexedItem[] oldItems = GetIndexedItems(index, length);
array.StableSort(index, length);
OnPropertyChanged("Item[]");
OnItemsMoved(GetIndexedItems(index, length), oldItems);
}
}
public void Sort(int index, int length, IComparer comparer) {
if (length > 1) {
IndexedItem[] oldItems = GetIndexedItems(index, length);
array.StableSort(index, length, comparer);
OnPropertyChanged("Item[]");
OnItemsMoved(GetIndexedItems(index, length), oldItems);
}
}
#endregion
#region Conversion
public ReadOnlyObservableArray AsReadOnly() {
return new ReadOnlyObservableArray(this);
}
public void CopyTo(T[] array) {
Array.Copy(this.array, array, this.array.Length);
}
public void CopyTo(T[] array, int arrayIndex) {
Array.Copy(this.array, 0, array, arrayIndex, this.array.Length);
}
public void CopyTo(int index, T[] array, int arrayIndex, int count) {
Array.Copy(this.array, index, array, arrayIndex, count);
}
public TOutput[] ConvertAll(Converter converter) {
return Array.ConvertAll(array, converter);
}
#endregion
#region Processing
public void ForEach(Action action) {
Array.ForEach(array, action);
}
public bool TrueForAll(Predicate match) {
return Array.TrueForAll(array, match);
}
#endregion
#region Enumeration
public IEnumerator GetEnumerator() {
foreach (object o in ((IEnumerable)this))
yield return (T)o;
}
IEnumerator IEnumerable.GetEnumerator() {
return array.GetEnumerator();
}
#endregion
#region Events
[field: NonSerialized]
public event CollectionItemsChangedEventHandler> ItemsReplaced;
protected virtual void OnItemsReplaced(IEnumerable> items, IEnumerable> oldItems) {
CollectionItemsChangedEventHandler> handler = ItemsReplaced;
if (handler != null) handler(this, new CollectionItemsChangedEventArgs>(items, oldItems));
}
[field: NonSerialized]
public event CollectionItemsChangedEventHandler> ItemsMoved;
protected virtual void OnItemsMoved(IEnumerable> items, IEnumerable> oldItems) {
CollectionItemsChangedEventHandler> handler = ItemsMoved;
if (handler != null) handler(this, new CollectionItemsChangedEventArgs>(items, oldItems));
}
[field: NonSerialized]
public event CollectionItemsChangedEventHandler> CollectionReset;
protected virtual void OnCollectionReset(IEnumerable> items, IEnumerable> oldItems) {
CollectionItemsChangedEventHandler> handler = CollectionReset;
if (handler != null) handler(this, new CollectionItemsChangedEventArgs>(items, oldItems));
}
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) {
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Private helpers
private IndexedItem[] GetIndexedItems() {
IndexedItem[] items = new IndexedItem[array.Length];
for (int i = 0; i < array.Length; i++)
items[i] = new IndexedItem(i, array[i]);
return items;
}
private IndexedItem[] GetIndexedItems(int index, int count) {
IndexedItem[] items = new IndexedItem[count];
for (int i = 0; i < count; i++)
items[i] = new IndexedItem(index + i, array[index + i]);
return items;
}
#endregion
}
}