source: trunk/sources/HeuristicLab.Collections/3.3/ObservableArray.cs @ 10324

Last change on this file since 10324 was 10324, checked in by gkronber, 7 years ago

#2106: changed methods for sorting in ObservableArray and ObservableList to use a stable sort (via Enumerable.OrderBy()). This is implemented as extension methods in HeuristicLab.Common. This implementation requires additional memory O(n).
The unit tests for tabu search had to be updated as the stable sort changes the results of the sample.
(minor bug fix in TestRandom)

File size: 11.2 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections;
24using System.Collections.Generic;
25using System.ComponentModel;
26using System.Linq;
27using HeuristicLab.Common;
28using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
29
30namespace HeuristicLab.Collections {
31  [StorableClass]
32  [Serializable]
33  public class ObservableArray<T> : IObservableArray<T> {
34    [Storable]
35    protected T[] array;
36
37    #region Properties
38    public int Length {
39      get { return array.Length; }
40    }
41    int ICollection<T>.Count {
42      get { return array.Length; }
43    }
44    bool ICollection<T>.IsReadOnly {
45      get { return array.IsReadOnly; }
46    }
47
48    public T this[int index] {
49      get {
50        return array[index];
51      }
52      set {
53        T item = array[index];
54        if (!((item == null) && (value == null)) && ((item == null) || (!item.Equals(value)))) {
55          array[index] = value;
56          OnItemsReplaced(new IndexedItem<T>[] { new IndexedItem<T>(index, value) }, new IndexedItem<T>[] { new IndexedItem<T>(index, item) });
57          OnPropertyChanged("Item[]");
58        }
59      }
60    }
61    #endregion
62
63    #region Constructors
64    public ObservableArray() {
65      array = new T[0];
66    }
67    public ObservableArray(int length) {
68      array = new T[length];
69    }
70    public ObservableArray(T[] array) {
71      this.array = (T[])array.Clone();
72    }
73    public ObservableArray(IEnumerable<T> collection) {
74      array = collection.ToArray();
75    }
76    [StorableConstructor]
77    protected ObservableArray(bool deserializing) { }
78    #endregion
79
80    #region Access
81    public bool Contains(T item) {
82      return IndexOf(item) != -1;
83    }
84    public int IndexOf(T item) {
85      return Array.IndexOf<T>(array, item);
86    }
87    public int IndexOf(T item, int startIndex) {
88      return Array.IndexOf<T>(array, item, startIndex);
89    }
90    public int IndexOf(T item, int startIndex, int count) {
91      return Array.IndexOf<T>(array, item, startIndex, count);
92    }
93
94    public int LastIndexOf(T item) {
95      return Array.LastIndexOf<T>(array, item);
96    }
97    public int LastIndexOf(T item, int startIndex) {
98      return Array.LastIndexOf<T>(array, item, startIndex);
99    }
100    public int LastIndexOf(T item, int startIndex, int count) {
101      return Array.LastIndexOf<T>(array, item, startIndex, count);
102    }
103
104    public int BinarySearch(T item) {
105      return Array.BinarySearch<T>(array, item);
106    }
107    public int BinarySearch(T item, IComparer<T> comparer) {
108      return Array.BinarySearch<T>(array, item, comparer);
109    }
110    public int BinarySearch(int index, int count, T item) {
111      return Array.BinarySearch<T>(array, index, count, item);
112    }
113    public int BinarySearch(int index, int count, T item, IComparer<T> comparer) {
114      return Array.BinarySearch<T>(array, index, count, item, comparer);
115    }
116
117    public bool Exists(Predicate<T> match) {
118      return Array.Exists<T>(array, match);
119    }
120
121    public T Find(Predicate<T> match) {
122      return Array.Find<T>(array, match);
123    }
124    public T[] FindAll(Predicate<T> match) {
125      return Array.FindAll<T>(array, match);
126    }
127    public T FindLast(Predicate<T> match) {
128      return Array.FindLast<T>(array, match);
129    }
130
131    public int FindIndex(Predicate<T> match) {
132      return Array.FindIndex<T>(array, match);
133    }
134    public int FindIndex(int startIndex, Predicate<T> match) {
135      return Array.FindIndex<T>(array, startIndex, match);
136    }
137    public int FindIndex(int startIndex, int count, Predicate<T> match) {
138      return Array.FindIndex<T>(array, startIndex, count, match);
139    }
140
141    public int FindLastIndex(Predicate<T> match) {
142      return Array.FindLastIndex<T>(array, match);
143    }
144    public int FindLastIndex(int startIndex, Predicate<T> match) {
145      return Array.FindLastIndex<T>(array, startIndex, match);
146    }
147    public int FindLastIndex(int startIndex, int count, Predicate<T> match) {
148      return Array.FindLastIndex<T>(array, startIndex, count, match);
149    }
150    #endregion
151
152    #region Manipulation
153    void ICollection<T>.Add(T item) {
154      throw new NotSupportedException();
155    }
156    void IList<T>.Insert(int index, T item) {
157      throw new NotSupportedException();
158    }
159    bool ICollection<T>.Remove(T item) {
160      throw new NotSupportedException();
161    }
162    void IList<T>.RemoveAt(int index) {
163      throw new NotSupportedException();
164    }
165
166    public void Clear(int index, int length) {
167      if (length > 0) {
168        IndexedItem<T>[] oldItems = GetIndexedItems(index, length);
169        Array.Clear(array, index, length);
170        OnPropertyChanged("Item[]");
171        OnItemsReplaced(GetIndexedItems(index, length), oldItems);
172      }
173    }
174    void ICollection<T>.Clear() {
175      Clear(0, array.Length);
176    }
177
178    public void Resize(int newSize) {
179      if (newSize != array.Length) {
180        IndexedItem<T>[] oldItems = GetIndexedItems();
181        Array.Resize<T>(ref array, newSize);
182        OnPropertyChanged("Length");
183        OnPropertyChanged("Item[]");
184        OnCollectionReset(GetIndexedItems(), oldItems);
185      }
186    }
187
188    public void Reverse() {
189      if (array.Length > 1) {
190        IndexedItem<T>[] oldItems = GetIndexedItems();
191        Array.Reverse(array);
192        OnPropertyChanged("Item[]");
193        OnItemsMoved(GetIndexedItems(), oldItems);
194      }
195    }
196    public void Reverse(int index, int length) {
197      if (length > 1) {
198        IndexedItem<T>[] oldItems = GetIndexedItems(index, length);
199        Array.Reverse(array, index, length);
200        OnPropertyChanged("Item[]");
201        OnItemsMoved(GetIndexedItems(index, length), oldItems);
202      }
203    }
204
205    public void Sort() {
206      if (array.Length > 1) {
207        IndexedItem<T>[] oldItems = GetIndexedItems();
208        array.StableSort();
209        OnPropertyChanged("Item[]");
210        OnItemsMoved(GetIndexedItems(), oldItems);
211      }
212    }
213    public void Sort(Comparison<T> comparison) {
214      if (array.Length > 1) {
215        IndexedItem<T>[] oldItems = GetIndexedItems();
216        array.StableSort(comparison);
217        OnPropertyChanged("Item[]");
218        OnItemsMoved(GetIndexedItems(), oldItems);
219      }
220    }
221    public void Sort(IComparer<T> comparer) {
222      if (array.Length > 1) {
223        IndexedItem<T>[] oldItems = GetIndexedItems();
224        array.StableSort(comparer);
225        OnPropertyChanged("Item[]");
226        OnItemsMoved(GetIndexedItems(), oldItems);
227      }
228    }
229    public void Sort(int index, int length) {
230      if (length > 1) {
231        IndexedItem<T>[] oldItems = GetIndexedItems(index, length);
232        array.StableSort(index, length);
233        OnPropertyChanged("Item[]");
234        OnItemsMoved(GetIndexedItems(index, length), oldItems);
235      }
236    }
237    public void Sort(int index, int length, IComparer<T> comparer) {
238      if (length > 1) {
239        IndexedItem<T>[] oldItems = GetIndexedItems(index, length);
240        array.StableSort(index, length, comparer);
241        OnPropertyChanged("Item[]");
242        OnItemsMoved(GetIndexedItems(index, length), oldItems);
243      }
244    }
245    #endregion
246
247    #region Conversion
248    public ReadOnlyObservableArray<T> AsReadOnly() {
249      return new ReadOnlyObservableArray<T>(this);
250    }
251    public void CopyTo(T[] array) {
252      Array.Copy(this.array, array, this.array.Length);
253    }
254    public void CopyTo(T[] array, int arrayIndex) {
255      Array.Copy(this.array, 0, array, arrayIndex, this.array.Length);
256    }
257    public void CopyTo(int index, T[] array, int arrayIndex, int count) {
258      Array.Copy(this.array, index, array, arrayIndex, count);
259    }
260    public TOutput[] ConvertAll<TOutput>(Converter<T, TOutput> converter) {
261      return Array.ConvertAll<T, TOutput>(array, converter);
262    }
263    #endregion
264
265    #region Processing
266    public void ForEach(Action<T> action) {
267      Array.ForEach<T>(array, action);
268    }
269    public bool TrueForAll(Predicate<T> match) {
270      return Array.TrueForAll<T>(array, match);
271    }
272    #endregion
273
274    #region Enumeration
275    public IEnumerator<T> GetEnumerator() {
276      foreach (object o in ((IEnumerable)this))
277        yield return (T)o;
278    }
279    IEnumerator IEnumerable.GetEnumerator() {
280      return array.GetEnumerator();
281    }
282    #endregion
283
284    #region Events
285    [field: NonSerialized]
286    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsReplaced;
287    protected virtual void OnItemsReplaced(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
288      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsReplaced;
289      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
290    }
291
292    [field: NonSerialized]
293    public event CollectionItemsChangedEventHandler<IndexedItem<T>> ItemsMoved;
294    protected virtual void OnItemsMoved(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
295      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = ItemsMoved;
296      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
297    }
298
299    [field: NonSerialized]
300    public event CollectionItemsChangedEventHandler<IndexedItem<T>> CollectionReset;
301    protected virtual void OnCollectionReset(IEnumerable<IndexedItem<T>> items, IEnumerable<IndexedItem<T>> oldItems) {
302      CollectionItemsChangedEventHandler<IndexedItem<T>> handler = CollectionReset;
303      if (handler != null) handler(this, new CollectionItemsChangedEventArgs<IndexedItem<T>>(items, oldItems));
304    }
305
306    [field: NonSerialized]
307    public event PropertyChangedEventHandler PropertyChanged;
308    protected virtual void OnPropertyChanged(string propertyName) {
309      PropertyChangedEventHandler handler = PropertyChanged;
310      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
311    }
312    #endregion
313
314    #region Private helpers
315    private IndexedItem<T>[] GetIndexedItems() {
316      IndexedItem<T>[] items = new IndexedItem<T>[array.Length];
317      for (int i = 0; i < array.Length; i++)
318        items[i] = new IndexedItem<T>(i, array[i]);
319      return items;
320    }
321    private IndexedItem<T>[] GetIndexedItems(int index, int count) {
322      IndexedItem<T>[] items = new IndexedItem<T>[count];
323      for (int i = 0; i < count; i++)
324        items[i] = new IndexedItem<T>(index + i, array[index + i]);
325      return items;
326    }
327    #endregion
328  }
329}
Note: See TracBrowser for help on using the repository browser.