Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
MultiValueSortedList.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.Linq;
7 
8 namespace SiliconStudio.Core.Collections
9 {
10  /// <summary>
11  /// Represents a priority queue, where keys are sorted and each key might have mlutiple values.
12  /// </summary>
13  /// <remarks>
14  /// Storage is based on a <see cref="List{TKey}"/> and a <see cref="List{KeyValuePair{TKey, TValue}}"/>.
15  /// </remarks>
16  /// <typeparam name="TKey">The type of the key.</typeparam>
17  /// <typeparam name="TValue">The type of the value.</typeparam>
18  public class MultiValueSortedList<TKey, TValue> : ILookup<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, ICollection, IEnumerable where TKey : IComparable<TKey>
19  {
20  private struct Grouping : IGrouping<TKey, TValue>
21  {
22  public IEnumerator<TValue> GetEnumerator() { return enumerable.GetEnumerator(); }
23  IEnumerator IEnumerable.GetEnumerator() { return enumerable.GetEnumerator(); }
24  public TKey Key { get { return key; } }
25  public Grouping(TKey key, IEnumerable<TValue> values) { this.key = key; enumerable = values; }
26  private readonly TKey key;
27  private readonly IEnumerable<TValue> enumerable;
28  }
29 
30  private struct GroupingEnumerator : IEnumerator<IGrouping<TKey, TValue>>
31  {
32  public void Dispose() { keys.Dispose(); }
33  public bool MoveNext() { return keys.MoveNext(); }
34  public void Reset() { keys.Reset(); }
35  public IGrouping<TKey, TValue> Current { get { return new Grouping(keys.Current, list[keys.Current]); } }
36  object IEnumerator.Current { get { return new Grouping(keys.Current, list[keys.Current]); } }
37  public GroupingEnumerator(MultiValueSortedList<TKey, TValue> list) { keys = list.DistinctKeys().GetEnumerator(); this.list = list; }
38  readonly IEnumerator<TKey> keys;
40  }
41 
42  private readonly List<KeyValuePair<TKey, TValue>> list = new List<KeyValuePair<TKey, TValue>>();
43  private readonly List<TKey> keys = new List<TKey>();
44 
45  public IEnumerable<TKey> Keys { get { return DistinctKeys(); } }
46  public IEnumerable<TValue> Values { get { return list.Select(x => x.Value); } }
47 
48  private IEnumerable<TKey> DistinctKeys()
49  {
50  if (keys.Count == 0)
51  return keys;
52 
53  bool first = true;
54  TKey distinctKey = default(TKey);
55  return keys.Where(x =>
56  {
57  bool result = first || !distinctKey.Equals(x);
58  distinctKey = x;
59  first = false;
60  return result;
61  });
62  }
63 
64  private int KeyToIndex(object key)
65  {
66  return keys.BinarySearch((TKey)key);
67  }
68 
69  public IEnumerator<IGrouping<TKey, TValue>> GetEnumerator()
70  {
71  return new GroupingEnumerator(this);
72  }
73 
74 
75  IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
76  {
77  return list.GetEnumerator();
78  }
79 
80  IEnumerator IEnumerable.GetEnumerator()
81  {
82  return list.GetEnumerator();
83  }
84 
85  public void Add(KeyValuePair<TKey, TValue> item)
86  {
87  int lower = 0;
88  int greater = list.Count;
89  int current = (lower + greater) >> 1;
90  while (greater - lower > 1)
91  {
92  if (keys[current].CompareTo(item.Key) < 0)
93  {
94  lower = current;
95  }
96  else
97  {
98  greater = current;
99  }
100  current = (lower + greater) >> 1;
101  }
102  list.Insert(greater, item);
103  keys.Insert(greater, item.Key);
104  }
105 
106  public bool Contains(object key)
107  {
108  return KeyToIndex(key) >= 0;
109  }
110 
111  public void Add(object key, object value)
112  {
113  Add(new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value));
114  }
115 
117  {
118  list.Clear();
119  keys.Clear();
120  }
121 
122  public bool Contains(KeyValuePair<TKey, TValue> item)
123  {
124  return KeyToIndex(item.Key) >= 0;
125  }
126 
127  public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
128  {
129  list.CopyTo(array, arrayIndex);
130  }
131 
132  public bool Remove(KeyValuePair<TKey, TValue> item)
133  {
134  bool removed = false;
135  for (int i = KeyToIndex(item.Key); i >= 0; i = KeyToIndex(item.Key))
136  {
137  list.RemoveAt(i);
138  keys.RemoveAt(i);
139  removed = true;
140  }
141  return removed;
142  }
143 
144  public void CopyTo(Array array, int index)
145  {
146  ((ICollection)list).CopyTo(array, index);
147  }
148 
149  public bool Contains(TKey key)
150  {
151  return KeyToIndex(key) >= 0;
152  }
153 
154  public int Count { get { return list.Count; } }
155 
156  public IEnumerable<TValue> this[TKey key] { get { return list.Skip(KeyToIndex(key)).TakeWhile(x => x.Key.Equals(key)).Select(x => x.Value); } }
157 
158  int ICollection.Count { get { return list.Count; } }
159 
160  public object SyncRoot { get { return ((ICollection)list).SyncRoot; } }
161 
162  public bool IsSynchronized { get { return ((ICollection)list).IsSynchronized; } }
163 
164  int ICollection<KeyValuePair<TKey, TValue>>.Count { get { return list.Count; } }
165 
166  public bool IsFixedSize { get { return false; } }
167 
168  bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly { get { return false; } }
169 
170  public bool ContainsKey(TKey key)
171  {
172  return KeyToIndex(key) >= 0;
173  }
174 
175  public void Add(TKey key, TValue value)
176  {
177  Add(new KeyValuePair<TKey, TValue>(key, value));
178  }
179 
180  public bool Remove(TKey key)
181  {
182  bool removed = false;
183  for (int i = KeyToIndex(key); i >= 0; i = KeyToIndex(key))
184  {
185  list.RemoveAt(i);
186  keys.RemoveAt(i);
187  removed = true;
188  }
189  return removed;
190  }
191  }
192 }
SiliconStudio.Paradox.Input.Keys Keys
void CopyTo(KeyValuePair< TKey, TValue >[] array, int arrayIndex)
System.Collections.ICollection ICollection
Represents a priority queue, where keys are sorted and each key might have mlutiple values...