Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
KeyedSortedList.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections;
5 using System.Collections.Generic;
6 using System.Collections.Specialized;
7 using System.Runtime.InteropServices;
8 using SiliconStudio.Core.Serialization.Serializers;
9 
10 namespace SiliconStudio.Core.Collections
11 {
12  /// <summary>
13  /// List of items, stored sequentially and sorted by an implicit invariant key that are extracted from items by implementing <see cref="GetKeyForItem"/>.
14  /// </summary>
15  /// <typeparam name="TKey">The type of the key.</typeparam>
16  /// <typeparam name="T"></typeparam>
17  public abstract class KeyedSortedList<TKey, T> : IList<T>
18  {
19  private IComparer<TKey> comparer;
20  protected FastListStruct<T> items = new FastListStruct<T>(1);
21 
22  protected KeyedSortedList() : this(null)
23  {
24  }
25 
26  protected KeyedSortedList(IComparer<TKey> comparer)
27  {
28  if (comparer == null)
29  comparer = Comparer<TKey>.Default;
30 
31  this.comparer = comparer;
32  }
33 
34  /// <summary>
35  /// Extracts the key for the specified element.
36  /// </summary>
37  /// <param name="item">The element from which to extract the key.</param>
38  /// <returns></returns>
39  protected abstract TKey GetKeyForItem(T item);
40 
41  /// <summary>
42  /// Called every time an item should be added at a given index.
43  /// </summary>
44  /// <param name="index">The index.</param>
45  /// <param name="item">The item.</param>
46  protected virtual void InsertItem(int index, T item)
47  {
48  items.Insert(index, item);
49  }
50 
51  /// <summary>
52  /// Called every time an item should be removed at a given index.
53  /// </summary>
54  /// <param name="index">The index.</param>
55  protected virtual void RemoveItem(int index)
56  {
57  items.RemoveAt(index);
58  }
59 
60  /// <inheritdoc/>
61  public void Add(T item)
62  {
63  var key = GetKeyForItem(item);
64 
65  var index = BinarySearch(key);
66  if (index >= 0)
67  throw new InvalidOperationException("An item with the same key has already been added.");
68 
69  InsertItem(~index, item);
70  }
71 
72  public bool Contains(TKey key)
73  {
74  return BinarySearch(key) >= 0;
75  }
76 
77  public bool Remove(TKey key)
78  {
79  var index = BinarySearch(key);
80  if (index < 0)
81  return false;
82 
83  RemoveItem(index);
84 
85  return true;
86  }
87 
88  /// <inheritdoc/>
89  public T this[int index]
90  {
91  get { return items[index]; }
92  set { items[index] = value; }
93  }
94 
95  public T this[TKey key]
96  {
97  get
98  {
99  int index = BinarySearch(key);
100  if (index < 0)
101  throw new KeyNotFoundException();
102  return items[index];
103  }
104  set
105  {
106  int index = BinarySearch(key);
107  if (index >= 0)
108  items[index] = value;
109  else
110  items.Insert(~index, value);
111  }
112  }
113 
114  /// <inheritdoc/>
115  public void Clear()
116  {
117  items.Clear();
118  }
119 
120  /// <inheritdoc/>
121  public bool Contains(T item)
122  {
123  return items.Contains(item);
124  }
125 
126  /// <inheritdoc/>
127  void ICollection<T>.CopyTo(T[] array, int arrayIndex)
128  {
129  throw new NotImplementedException();
130  }
131 
132  /// <inheritdoc/>
133  bool ICollection<T>.Remove(T item)
134  {
135  throw new NotImplementedException();
136  }
137 
138  /// <inheritdoc/>
139  public int Count
140  {
141  get { return items.Count; }
142  }
143 
144  /// <inheritdoc/>
145  public bool IsReadOnly
146  {
147  get { return false; }
148  }
149 
150  /// <inheritdoc/>
151  public int IndexOf(T item)
152  {
153  return items.IndexOf(item);
154  }
155 
156  /// <inheritdoc/>
157  void IList<T>.Insert(int index, T item)
158  {
159  throw new NotImplementedException();
160  }
161 
162  /// <inheritdoc/>
163  public void RemoveAt(int index)
164  {
165  items.RemoveAt(index);
166  }
167 
168  /// <inheritdoc/>
169  IEnumerator<T> IEnumerable<T>.GetEnumerator()
170  {
171  return new Enumerator(items);
172  }
173 
174  /// <inheritdoc/>
175  IEnumerator IEnumerable.GetEnumerator()
176  {
177  return new Enumerator(items);
178  }
179 
180  public Enumerator GetEnumerator()
181  {
182  return new Enumerator(items);
183  }
184 
185  public int BinarySearch(TKey searchKey)
186  {
187  var values = items.Items;
188  int start = 0;
189  int end = items.Count - 1;
190 
191  while (start <= end)
192  {
193  int middle = start + ((end - start) >> 1);
194  var itemKey = GetKeyForItem(values[middle]);
195 
196  var compareResult = comparer.Compare(itemKey, searchKey);
197 
198  if (compareResult == 0)
199  {
200  return middle;
201  }
202  if (compareResult < 0)
203  {
204  start = middle + 1;
205  }
206  else
207  {
208  end = middle - 1;
209  }
210  }
211  return ~start;
212  }
213 
214  #region Nested type: Enumerator
215 
216  [StructLayout(LayoutKind.Sequential)]
217  public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator
218  {
219  private readonly FastListStruct<T> list;
220  private int index;
221  private T current;
222 
223  internal Enumerator(FastListStruct<T> list)
224  {
225  this.list = list;
226  index = 0;
227  current = default(T);
228  }
229 
230  public void Dispose()
231  {
232  }
233 
234  public bool MoveNext()
235  {
236  if (index < list.Count)
237  {
238  current = list.Items[index];
239  index++;
240  return true;
241  }
242  return MoveNextRare();
243  }
244 
245  private bool MoveNextRare()
246  {
247  index = list.Count + 1;
248  current = default(T);
249  return false;
250  }
251 
252  public T Current
253  {
254  get { return current; }
255  }
256 
257  object IEnumerator.Current
258  {
259  get { return Current; }
260  }
261 
262  void IEnumerator.Reset()
263  {
264  index = 0;
265  current = default(T);
266  }
267  }
268 
269  #endregion
270  }
271 }
virtual void RemoveItem(int index)
Called every time an item should be removed at a given index.
virtual void InsertItem(int index, T item)
Called every time an item should be added at a given index.