From df2d5a460f060129e5c09148b9fa4df2f241d8b1 Mon Sep 17 00:00:00 2001 From: jjgreens Date: Wed, 14 Oct 2009 23:15:03 -0700 Subject: Replaced the update lists with a priority queue implementation in LLClientView Replaced the update lists with a priority queue implementation in LLClientView. The priority queues are based on the MinHeap implementation also included in this commit within the OpneSim.Framework namespace. Initially setup to exactly mimic the behavior beofre the change which was a first come first serve queue. --- OpenSim/Framework/MinHeap.cs | 375 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100755 OpenSim/Framework/MinHeap.cs (limited to 'OpenSim/Framework/MinHeap.cs') diff --git a/OpenSim/Framework/MinHeap.cs b/OpenSim/Framework/MinHeap.cs new file mode 100755 index 0000000..ad39bbc --- /dev/null +++ b/OpenSim/Framework/MinHeap.cs @@ -0,0 +1,375 @@ +using System; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace OpenSim.Framework +{ + public interface IHandle { } + + [Serializable, ComVisible(false)] + public class MinHeap : ICollection, ICollection + { + private class Handle : IHandle + { + internal int index = -1; + internal MinHeap heap = null; + + internal void Clear() + { + this.index = -1; + this.heap = null; + } + } + + private struct HeapItem + { + internal T value; + internal Handle handle; + + internal HeapItem(T value, Handle handle) + { + this.value = value; + this.handle = handle; + } + + internal void Clear() + { + this.value = default(T); + if (this.handle != null) + { + this.handle.Clear(); + this.handle = null; + } + } + } + + public const int DEFAULT_CAPACITY = 4; + + private HeapItem[] items; + private int size; + private object sync_root; + private int version; + + private Comparison comparison; + + public MinHeap() : this(DEFAULT_CAPACITY, Comparer.Default) { } + public MinHeap(int capacity) : this(capacity, Comparer.Default) { } + public MinHeap(IComparer comparer) : this(DEFAULT_CAPACITY, comparer) { } + public MinHeap(int capacity, IComparer comparer) : + this(capacity, new Comparison(comparer.Compare)) { } + public MinHeap(Comparison comparison) : this(DEFAULT_CAPACITY, comparison) { } + public MinHeap(int capacity, Comparison comparison) + { + this.items = new HeapItem[capacity]; + this.comparison = comparison; + this.size = this.version = 0; + } + + public int Count { get { return this.size; } } + + public bool IsReadOnly { get { return false; } } + + public bool IsSynchronized { get { return false; } } + + public T this[IHandle key] + { + get + { + Handle handle = ValidateThisHandle(key); + return this.items[handle.index].value; + } + + set + { + Handle handle = ValidateThisHandle(key); + this.items[handle.index].value = value; + if (!BubbleUp(handle.index)) + BubbleDown(handle.index); + } + } + + public object SyncRoot + { + get + { + if (this.sync_root == null) + Interlocked.CompareExchange(ref this.sync_root, new object(), null); + return this.sync_root; + } + } + + private Handle ValidateHandle(IHandle ihandle) + { + if (ihandle == null) + throw new ArgumentNullException("handle"); + Handle handle = ihandle as Handle; + if (handle == null) + throw new InvalidOperationException("handle is not valid"); + return handle; + } + + private Handle ValidateThisHandle(IHandle ihandle) + { + Handle handle = ValidateHandle(ihandle); + if (!object.ReferenceEquals(handle.heap, this)) + throw new InvalidOperationException("handle is not valid for this heap"); + if (handle.index < 0) + throw new InvalidOperationException("handle is not associated to a value"); + return handle; + } + + private void Set(HeapItem item, int index) + { + this.items[index] = item; + if (item.handle != null) + item.handle.index = index; + } + + private bool BubbleUp(int index) + { + HeapItem item = this.items[index]; + int current, parent; + + for (current = index, parent = (current - 1) / 2; + (current > 0) && (this.comparison(this.items[parent].value, item.value)) > 0; + current = parent, parent = (current - 1) / 2) + { + Set(this.items[parent], current); + } + + if (current != index) + { + Set(item, current); + ++this.version; + return true; + } + return false; + } + + private void BubbleDown(int index) + { + HeapItem item = this.items[index]; + int current, child; + + for (current = index, child = (2 * current) + 1; + current < this.size / 2; + current = child, child = (2 * current) + 1) + { + if ((child < this.size - 1) && this.comparison(this.items[child].value, this.items[child + 1].value) > 0) + ++child; + if (this.comparison(this.items[child].value, item.value) >= 0) + break; + Set(this.items[child], current); + } + + if (current != index) + { + Set(item, current); + ++this.version; + } + } + + public bool TryGetValue(IHandle key, out T value) + { + Handle handle = ValidateHandle(key); + if (handle.index > -1) + { + value = this.items[handle.index].value; + return true; + } + value = default(T); + return false; + } + + public bool ContainsHandle(IHandle ihandle) + { + Handle handle = ValidateHandle(ihandle); + return object.ReferenceEquals(handle.heap, this) && handle.index > -1; + } + + public void Add(T value, ref IHandle handle) + { + if (handle == null) + handle = new Handle(); + Add(value, handle); + } + + public void Add(T value, IHandle ihandle) + { + if (this.size == this.items.Length) + { + int capacity = (int)((this.items.Length * 200L) / 100L); + if (capacity < (this.items.Length + DEFAULT_CAPACITY)) + capacity = this.items.Length + DEFAULT_CAPACITY; + Array.Resize(ref this.items, capacity); + } + + Handle handle = null; + if (ihandle != null) + { + handle = ValidateHandle(ihandle); + handle.heap = this; + } + + HeapItem item = new MinHeap.HeapItem(value, handle); + + Set(item, this.size); + BubbleUp(this.size++); + } + + public void Add(T value) + { + Add(value, null); + } + + public T Min() + { + if (this.size == 0) + throw new InvalidOperationException("Heap is empty"); + + return this.items[0].value; + } + + public void Clear() + { + for (int index = 0; index < this.size; ++index) + this.items[index].Clear(); + this.size = 0; + ++this.version; + } + + public void TrimExcess() + { + int length = (int)(this.items.Length * 0.9); + if (this.size < length) + Array.Resize(ref this.items, Math.Min(this.size, DEFAULT_CAPACITY)); + } + + private void RemoveAt(int index) + { + if (this.size == 0) + throw new InvalidOperationException("Heap is empty"); + if (index >= this.size) + throw new ArgumentOutOfRangeException("index"); + + this.items[index].Clear(); + if (--this.size > 0 && index != this.size) + { + Set(this.items[this.size], index); + if (!BubbleUp(index)) + BubbleDown(index); + } + } + + public T RemoveMin() + { + if (this.size == 0) + throw new InvalidOperationException("Heap is empty"); + + HeapItem item = this.items[0]; + RemoveAt(0); + return item.value; + } + + public T Remove(IHandle ihandle) + { + Handle handle = ValidateThisHandle(ihandle); + HeapItem item = this.items[handle.index]; + RemoveAt(handle.index); + return item.value; + } + + private int GetIndex(T value) + { + EqualityComparer comparer = EqualityComparer.Default; + int index; + + for (index = 0; index < this.size; ++index) + { + if (comparer.Equals(this.items[index].value, value)) + return index; + } + return -1; + } + + public bool Contains(T value) + { + return GetIndex(value) != -1; + } + + public bool Remove(T value) + { + int index = GetIndex(value); + if (index != -1) + { + RemoveAt(index); + return true; + } + return false; + } + + public void CopyTo(T[] array, int index) + { + if (array == null) + throw new ArgumentNullException("array"); + if (array.Rank != 1) + throw new ArgumentException("Multidimensional array not supported"); + if (array.GetLowerBound(0) != 0) + throw new ArgumentException("Non-zero lower bound array not supported"); + + int length = array.Length; + if ((index < 0) || (index > length)) + throw new ArgumentOutOfRangeException("index"); + if ((length - index) < this.size) + throw new ArgumentException("Not enough space available in array starting at index"); + + for (int i = 0; i < this.size; ++i) + array[index + i] = this.items[i].value; + } + + public void CopyTo(Array array, int index) + { + if (array == null) + throw new ArgumentNullException("array"); + if (array.Rank != 1) + throw new ArgumentException("Multidimensional array not supported"); + if (array.GetLowerBound(0) != 0) + throw new ArgumentException("Non-zero lower bound array not supported"); + + int length = array.Length; + if ((index < 0) || (index > length)) + throw new ArgumentOutOfRangeException("index"); + if ((length - index) < this.size) + throw new ArgumentException("Not enough space available in array starting at index"); + + try + { + for (int i = 0; i < this.size; ++i) + array.SetValue(this.items[i].value, index + i); + } + catch (ArrayTypeMismatchException) + { + throw new ArgumentException("Invalid array type"); + } + } + + public IEnumerator GetEnumerator() + { + int version = this.version; + + for (int index = 0; index < this.size; ++index) + { + if (version != this.version) + throw new InvalidOperationException("Heap was modified while enumerating"); + yield return this.items[index].value; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} -- cgit v1.1