#region License Information /* HeuristicLab * Copyright (C) 2002-2019 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 } }