29 using System.Threading;
30 using System.Collections;
31 using System.Collections.Generic;
32 using System.Runtime.InteropServices;
34 namespace OpenSim.Framework
38 [Serializable, ComVisible(
false)]
39 public class MinHeap<T> : ICollection<T>, ICollection
43 internal int index = -1;
53 private struct HeapItem
56 internal Handle handle;
58 internal HeapItem(T value, Handle handle)
66 if (this.handle != null)
71 internal void ClearRef()
73 this.value =
default(T);
78 public const int DEFAULT_CAPACITY = 4;
80 private HeapItem[] items;
82 private object sync_root;
85 private Comparison<T> comparison;
87 public MinHeap() : this(DEFAULT_CAPACITY, Comparer<T>.Default) { }
88 public MinHeap(
int capacity) : this(capacity, Comparer<T>.Default) { }
89 public MinHeap(IComparer<T> comparer) : this(DEFAULT_CAPACITY, comparer) { }
90 public MinHeap(
int capacity, IComparer<T> comparer) :
91 this(capacity, new Comparison<T>(comparer.Compare)) { }
92 public MinHeap(Comparison<T> comparison) : this(DEFAULT_CAPACITY, comparison) { }
93 public MinHeap(
int capacity, Comparison<T> comparison)
95 this.items =
new HeapItem[capacity];
96 this.comparison = comparison;
97 this.size = this.version = 0;
100 public int Count {
get {
return this.size; } }
102 public bool IsReadOnly {
get {
return false; } }
104 public bool IsSynchronized {
get {
return false; } }
110 Handle handle = ValidateThisHandle(
key);
111 return this.items[handle.index].value;
116 Handle handle = ValidateThisHandle(
key);
117 this.items[handle.index].value = value;
118 if (!BubbleUp(handle.index))
119 BubbleDown(handle.index);
123 public object SyncRoot
127 if (this.sync_root == null)
128 Interlocked.CompareExchange<
object>(ref this.sync_root,
new object(), null);
129 return this.sync_root;
133 private Handle ValidateHandle(
IHandle ihandle)
136 throw new ArgumentNullException(
"handle");
137 Handle handle = ihandle as Handle;
139 throw new InvalidOperationException(
"handle is not valid");
143 private Handle ValidateThisHandle(IHandle ihandle)
145 Handle handle = ValidateHandle(ihandle);
146 if (!
object.ReferenceEquals(handle.heap,
this))
147 throw new InvalidOperationException(
"handle is not valid for this heap");
148 if (handle.index < 0)
149 throw new InvalidOperationException(
"handle is not associated to a value");
153 private void Set(HeapItem item,
int index)
155 this.items[index] = item;
156 if (item.handle != null)
157 item.handle.index = index;
160 private bool BubbleUp(
int index)
162 HeapItem item = this.items[index];
165 for (current = index, parent = (current - 1) / 2;
166 (current > 0) && (this.comparison(this.items[parent].value, item.value)) > 0;
167 current = parent, parent = (current - 1) / 2)
169 Set(this.items[parent], current);
172 if (current != index)
181 private void BubbleDown(
int index)
183 HeapItem item = this.items[index];
186 for (current = index, child = (2 * current) + 1;
187 current < this.size / 2;
188 current = child, child = (2 * current) + 1)
190 if ((child < this.size - 1) && this.comparison(this.items[child].value, this.items[child + 1].value) > 0)
192 if (this.comparison(this.items[child].value, item.value) >= 0)
194 Set(this.items[child], current);
197 if (current != index)
206 Handle handle = ValidateHandle(key);
207 if (handle.index > -1)
209 value = this.items[handle.index].value;
218 Handle handle = ValidateHandle(ihandle);
219 return object.ReferenceEquals(handle.heap,
this) && handle.index > -1;
225 handle =
new Handle();
231 if (this.size == this.items.Length)
233 int capacity = (int)((this.items.Length * 200L) / 100L);
234 if (capacity < (this.items.Length + DEFAULT_CAPACITY))
235 capacity = this.items.Length + DEFAULT_CAPACITY;
236 Array.Resize<HeapItem>(ref
this.items, capacity);
239 Handle handle = null;
242 handle = ValidateHandle(ihandle);
246 HeapItem item =
new MinHeap<T>.HeapItem(value, handle);
248 Set(item, this.size);
249 BubbleUp(this.size++);
260 throw new InvalidOperationException(
"Heap is empty");
262 return this.items[0].value;
267 for (
int index = 0; index < this.size; ++index)
268 this.items[index].Clear();
275 int length = (int)(this.items.Length * 0.9);
276 if (this.size < length)
277 Array.Resize<HeapItem>(ref this.items, Math.Min(this.size, DEFAULT_CAPACITY));
280 private void RemoveAt(
int index)
283 throw new InvalidOperationException(
"Heap is empty");
284 if (index >= this.size)
285 throw new ArgumentOutOfRangeException(
"index");
287 this.items[index].Clear();
288 if (--this.size > 0 && index != this.size)
290 Set(this.items[this.size], index);
291 this.items[this.size].ClearRef();
292 if (!BubbleUp(index))
300 throw new InvalidOperationException(
"Heap is empty");
302 HeapItem item = this.items[0];
309 Handle handle = ValidateThisHandle(ihandle);
310 HeapItem item = this.items[handle.index];
311 RemoveAt(handle.index);
315 private int GetIndex(T value)
317 EqualityComparer<T> comparer = EqualityComparer<T>.Default;
320 for (index = 0; index < this.size; ++index)
322 if (comparer.Equals(
this.items[index].value, value))
330 return GetIndex(value) != -1;
335 int index = GetIndex(value);
347 throw new ArgumentNullException(
"array");
349 throw new ArgumentException(
"Multidimensional array not supported");
350 if (array.GetLowerBound(0) != 0)
351 throw new ArgumentException(
"Non-zero lower bound array not supported");
353 int length = array.Length;
354 if ((index < 0) || (index > length))
355 throw new ArgumentOutOfRangeException(
"index");
356 if ((length - index) < this.size)
357 throw new ArgumentException(
"Not enough space available in array starting at index");
359 for (
int i = 0; i < this.size; ++i)
360 array[index + i] = this.items[i].value;
363 public void CopyTo(Array array,
int index)
366 throw new ArgumentNullException(
"array");
368 throw new ArgumentException(
"Multidimensional array not supported");
369 if (array.GetLowerBound(0) != 0)
370 throw new ArgumentException(
"Non-zero lower bound array not supported");
372 int length = array.Length;
373 if ((index < 0) || (index > length))
374 throw new ArgumentOutOfRangeException(
"index");
375 if ((length - index) < this.size)
376 throw new ArgumentException(
"Not enough space available in array starting at index");
380 for (
int i = 0; i < this.size; ++i)
381 array.SetValue(
this.items[i].value, index + i);
383 catch (ArrayTypeMismatchException)
385 throw new ArgumentException(
"Invalid array type");
391 int version = this.version;
393 for (
int index = 0; index < this.size; ++index)
395 if (version != this.version)
396 throw new InvalidOperationException(
"Heap was modified while enumerating");
397 yield
return this.items[index].value;
401 IEnumerator IEnumerable.GetEnumerator()
403 return GetEnumerator();
bool ContainsHandle(IHandle ihandle)
void CopyTo(T[] array, int index)
MinHeap(Comparison< T > comparison)
IEnumerator< T > GetEnumerator()
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString key
T Remove(IHandle ihandle)
void Add(T value, IHandle ihandle)
void Add(T value, ref IHandle handle)
MinHeap(IComparer< T > comparer)
MinHeap(int capacity, IComparer< T > comparer)
void CopyTo(Array array, int index)
bool TryGetValue(IHandle key, out T value)
MinHeap(int capacity, Comparison< T > comparison)