Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 485 lines (412 sloc) 13.94 kb
4f5a65b @otac0n Moved SplayTree to the Runtime assembly.
otac0n authored
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Diagnostics;
5
6 namespace IronJS.Runtime
7 {
8 public class SplayTree<TKey, TValue> : IDictionary<TKey, TValue> where TKey : IComparable<TKey>
9 {
10 private SplayTreeNode root;
11 private int count;
12 private int version = 0;
13
14 public void Add(TKey key, TValue value)
15 {
16 this.Set(key, value, throwOnExisting: true);
17 }
18
19 public void Add(KeyValuePair<TKey, TValue> item)
20 {
21 this.Set(item.Key, item.Value, throwOnExisting: true);
22 }
23
24 private void Set(TKey key, TValue value, bool throwOnExisting)
25 {
26 if (this.count == 0)
27 {
28 this.version++;
29 this.root = new SplayTreeNode(key, value);
30 this.count = 1;
31 return;
32 }
33
34 this.Splay(key);
35
36 var c = key.CompareTo(this.root.Key);
37 if (c == 0)
38 {
39 if (throwOnExisting)
40 {
41 throw new ArgumentException("An item with the same key already exists in the tree.");
42 }
43
44 this.version++;
45 this.root.Value = value;
46 return;
47 }
48
49 var n = new SplayTreeNode(key, value);
50 if (c < 0)
51 {
52 n.LeftChild = this.root.LeftChild;
53 n.RightChild = this.root;
54 this.root.LeftChild = null;
55 }
56 else
57 {
58 n.RightChild = this.root.RightChild;
59 n.LeftChild = this.root;
60 this.root.RightChild = null;
61 }
62
63 this.root = n;
64 this.count++;
65 this.Splay(key);
66 this.version++;
67 }
68
69 public void Clear()
70 {
71 this.root = null;
72 this.count = 0;
73 this.version++;
74 }
75
76 public bool ContainsKey(TKey key)
77 {
78 if (this.count == 0)
79 {
80 return false;
81 }
82
83 this.Splay(key);
84
85 return key.CompareTo(this.root.Key) == 0;
86 }
87
88 public bool Contains(KeyValuePair<TKey, TValue> item)
89 {
90 if (this.count == 0)
91 {
92 return false;
93 }
94
95 this.Splay(item.Key);
96
97 return item.Key.CompareTo(this.root.Key) == 0 && (object.ReferenceEquals(this.root.Value, item.Value) || (!object.ReferenceEquals(item.Value, null) && item.Value.Equals(this.root.Value)));
98 }
99
100 private void Splay(TKey key)
101 {
102 SplayTreeNode l, r, t, y, header;
103 l = r = header = new SplayTreeNode(default(TKey), default(TValue));
104 t = this.root;
105 while (true)
106 {
107 var c = key.CompareTo(t.Key);
108 if (c < 0)
109 {
110 if (t.LeftChild == null) break;
111 if (key.CompareTo(t.LeftChild.Key) < 0)
112 {
113 y = t.LeftChild;
114 t.LeftChild = y.RightChild;
115 y.RightChild = t;
116 t = y;
117 if (t.LeftChild == null) break;
118 }
119 r.LeftChild = t;
120 r = t;
121 t = t.LeftChild;
122 }
123 else if (c > 0)
124 {
125 if (t.RightChild == null) break;
126 if (key.CompareTo(t.RightChild.Key) > 0)
127 {
128 y = t.RightChild;
129 t.RightChild = y.LeftChild;
130 y.LeftChild = t;
131 t = y;
132 if (t.RightChild == null) break;
133 }
134 l.RightChild = t;
135 l = t;
136 t = t.RightChild;
137 }
138 else
139 {
140 break;
141 }
142 }
143 l.RightChild = t.LeftChild;
144 r.LeftChild = t.RightChild;
145 t.LeftChild = header.RightChild;
146 t.RightChild = header.LeftChild;
147 this.root = t;
148 }
149
150 public bool Remove(TKey key)
151 {
152 if (this.count == 0)
153 {
154 return false;
155 }
156
157 this.Splay(key);
158
159 if (key.CompareTo(this.root.Key) != 0)
160 {
161 return false;
162 }
163
164 if (this.root.LeftChild == null)
165 {
166 this.root = this.root.RightChild;
167 }
168 else
169 {
170 var swap = this.root.RightChild;
171 this.root = this.root.LeftChild;
172 this.Splay(key);
173 this.root.RightChild = swap;
174 }
175
176 this.version++;
177 this.count--;
178 return true;
179 }
180
181 public bool TryGetValue(TKey key, out TValue value)
182 {
183 if (this.count == 0)
184 {
185 value = default(TValue);
186 return false;
187 }
188
189 this.Splay(key);
190 if (key.CompareTo(this.root.Key) != 0)
191 {
192 value = default(TValue);
193 return false;
194 }
195
196 value = this.root.Value;
197 return true;
198 }
199
200 public TValue this[TKey key]
201 {
202 get
203 {
204 if (this.count == 0)
205 {
206 throw new KeyNotFoundException("The key was not found in the tree.");
207 }
208
209 this.Splay(key);
210 if (key.CompareTo(this.root.Key) != 0)
211 {
212 throw new KeyNotFoundException("The key was not found in the tree.");
213 }
214
215 return this.root.Value;
216 }
217
218 set
219 {
220 this.Set(key, value, throwOnExisting: false);
221 }
222 }
223
224 public int Count
225 {
226 get { return this.count; }
227 }
228
229 public bool IsReadOnly
230 {
231 get { return false; }
232 }
233
234 public bool Remove(KeyValuePair<TKey, TValue> item)
235 {
236 if (this.count == 0)
237 {
238 return false;
239 }
240
241 this.Splay(item.Key);
242
243 if (item.Key.CompareTo(this.root.Key) == 0 && (object.ReferenceEquals(this.root.Value, item.Value) || (!object.ReferenceEquals(item.Value, null) && item.Value.Equals(this.root.Value))))
244 {
245 return false;
246 }
247
248 if (this.root.LeftChild == null)
249 {
250 this.root = this.root.RightChild;
251 }
252 else
253 {
254 var swap = this.root.RightChild;
255 this.root = this.root.LeftChild;
256 this.Splay(item.Key);
257 this.root.RightChild = swap;
258 }
259
260 this.version++;
261 this.count--;
262 return true;
263 }
264
265 public void Trim(int depth)
266 {
267 if (depth < 0)
268 {
269 throw new ArgumentOutOfRangeException("depth", "The trim depth must not be negative.");
270 }
271
272 if (this.count == 0)
273 {
274 return;
275 }
276
277 if (depth == 0)
278 {
279 this.Clear();
280 }
281 else
282 {
283 var prevCount = this.count;
284 this.count = this.Trim(this.root, depth - 1);
285 if (prevCount != this.count)
286 {
287 this.version++;
288 }
289 }
290 }
291
292 private int Trim(SplayTreeNode node, int depth)
293 {
294 if (depth == 0)
295 {
296 node.LeftChild = null;
297 node.RightChild = null;
298 return 1;
299 }
300 else
301 {
302 int count = 1;
303
304 if (node.LeftChild != null)
305 {
306 count += Trim(node.LeftChild, depth - 1);
307 }
308
309 if (node.RightChild != null)
310 {
311 count += Trim(node.RightChild, depth - 1);
312 }
313
314 return count;
315 }
316 }
317
318 public ICollection<TKey> Keys
319 {
320 get { return new TiedList<TKey>(this, this.version, this.AsList(node => node.Key)); }
321 }
322
323 public ICollection<TValue> Values
324 {
325 get { return new TiedList<TValue>(this, this.version, this.AsList(node => node.Value)); }
326 }
327
328 public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
329 {
330 this.AsList(node => new KeyValuePair<TKey, TValue>(node.Key, node.Value)).CopyTo(array, arrayIndex);
331 }
332
333 public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
334 {
335 return new TiedList<KeyValuePair<TKey, TValue>>(this, this.version, this.AsList(node => new KeyValuePair<TKey, TValue>(node.Key, node.Value))).GetEnumerator();
336 }
337
338 private IList<TEnumerator> AsList<TEnumerator>(Func<SplayTreeNode, TEnumerator> selector)
339 {
340 if (this.root == null)
341 {
342 return new TEnumerator[0];
343 }
344
345 var result = new List<TEnumerator>(this.count);
346 PopulateList(this.root, result, selector);
347 return result;
348 }
349
350 private void PopulateList<TEnumerator>(SplayTreeNode node, List<TEnumerator> list, Func<SplayTreeNode, TEnumerator> selector)
351 {
352 if (node.LeftChild != null) PopulateList(node.LeftChild, list, selector);
353 list.Add(selector(node));
354 if (node.RightChild != null) PopulateList(node.RightChild, list, selector);
355 }
356
357 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
358 {
359 return this.GetEnumerator();
360 }
361
362 private sealed class SplayTreeNode
363 {
364 public readonly TKey Key;
365
366 public TValue Value;
367 public SplayTreeNode LeftChild;
368 public SplayTreeNode RightChild;
369
370 public SplayTreeNode(TKey key, TValue value)
371 {
372 this.Key = key;
373 this.Value = value;
374 }
375 }
376
377 [DebuggerDisplay("Count = {Count}")]
378 private sealed class TiedList<T> : IList<T>
379 {
380 private readonly SplayTree<TKey, TValue> tree;
381 private readonly int version;
382 private readonly IList<T> backingList;
383
384 public TiedList(SplayTree<TKey, TValue> tree, int version, IList<T> backingList)
385 {
386 if (tree == null)
387 {
388 throw new ArgumentNullException("tree");
389 }
390
391 if (backingList == null)
392 {
393 throw new ArgumentNullException("backingList");
394 }
395
396 this.tree = tree;
397 this.version = version;
398 this.backingList = backingList;
399 }
400
401 public int IndexOf(T item)
402 {
403 if (this.tree.version != this.version) throw new InvalidOperationException("The collection has been modified.");
404 return this.backingList.IndexOf(item);
405 }
406
407 public void Insert(int index, T item)
408 {
409 throw new NotSupportedException();
410 }
411
412 public void RemoveAt(int index)
413 {
414 throw new NotSupportedException();
415 }
416
417 public T this[int index]
418 {
419 get
420 {
421 if (this.tree.version != this.version) throw new InvalidOperationException("The collection has been modified.");
422 return this.backingList[index];
423 }
424 set
425 {
426 throw new NotSupportedException();
427 }
428 }
429
430 public void Add(T item)
431 {
432 throw new NotSupportedException();
433 }
434
435 public void Clear()
436 {
437 throw new NotSupportedException();
438 }
439
440 public bool Contains(T item)
441 {
442 if (this.tree.version != this.version) throw new InvalidOperationException("The collection has been modified.");
443 return this.backingList.Contains(item);
444 }
445
446 public void CopyTo(T[] array, int arrayIndex)
447 {
448 if (this.tree.version != this.version) throw new InvalidOperationException("The collection has been modified.");
449 this.backingList.CopyTo(array, arrayIndex);
450 }
451
452 public int Count
453 {
454 get { return this.tree.count; }
455 }
456
457 public bool IsReadOnly
458 {
459 get { return true; }
460 }
461
462 public bool Remove(T item)
463 {
464 throw new NotSupportedException();
465 }
466
467 public IEnumerator<T> GetEnumerator()
468 {
469 if (this.tree.version != this.version) throw new InvalidOperationException("The collection has been modified.");
470
471 foreach (var item in this.backingList)
472 {
473 yield return item;
474 if (this.tree.version != this.version) throw new InvalidOperationException("The collection has been modified.");
475 }
476 }
477
478 IEnumerator IEnumerable.GetEnumerator()
479 {
480 return this.GetEnumerator();
481 }
482 }
483 }
484 }
Something went wrong with that request. Please try again.