PageRenderTime 30ms CodeModel.GetById 20ms app.highlight 7ms RepoModel.GetById 0ms app.codeStats 1ms

/Aurora/Framework/Utilities/MinHeap.cs

https://bitbucket.org/VirtualReality/software-testing
C# | 443 lines | 349 code | 68 blank | 26 comment | 73 complexity | 04d1aca88a19d291747ca87ba3e0c484 MD5 | raw file
  1/*
  2 * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/
  3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4 *
  5 * Redistribution and use in source and binary forms, with or without
  6 * modification, are permitted provided that the following conditions are met:
  7 *     * Redistributions of source code must retain the above copyright
  8 *       notice, this list of conditions and the following disclaimer.
  9 *     * Redistributions in binary form must reproduce the above copyright
 10 *       notice, this list of conditions and the following disclaimer in the
 11 *       documentation and/or other materials provided with the distribution.
 12 *     * Neither the name of the Aurora-Sim Project nor the
 13 *       names of its contributors may be used to endorse or promote products
 14 *       derived from this software without specific prior written permission.
 15 *
 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 26 */
 27
 28using System;
 29using System.Collections;
 30using System.Collections.Generic;
 31using System.Runtime.InteropServices;
 32using System.Threading;
 33
 34namespace Aurora.Framework.Utilities
 35{
 36    public interface IHandle
 37    {
 38    }
 39
 40    [Serializable, ComVisible(false)]
 41    public class MinHeap<T> : ICollection<T>, ICollection
 42    {
 43        public const int DEFAULT_CAPACITY = 4;
 44        private readonly Comparison<T> comparison;
 45
 46        private HeapItem[] items;
 47        private int size;
 48        private object sync_root;
 49        private int version;
 50
 51        public MinHeap() : this(DEFAULT_CAPACITY, Comparer<T>.Default)
 52        {
 53        }
 54
 55        public MinHeap(int capacity) : this(capacity, Comparer<T>.Default)
 56        {
 57        }
 58
 59        public MinHeap(IComparer<T> comparer) : this(DEFAULT_CAPACITY, comparer)
 60        {
 61        }
 62
 63        public MinHeap(int capacity, IComparer<T> comparer) :
 64            this(capacity, comparer.Compare)
 65        {
 66        }
 67
 68        public MinHeap(Comparison<T> comparison) : this(DEFAULT_CAPACITY, comparison)
 69        {
 70        }
 71
 72        public MinHeap(int capacity, Comparison<T> comparison)
 73        {
 74            this.items = new HeapItem[capacity];
 75            this.comparison = comparison;
 76            this.size = this.version = 0;
 77        }
 78
 79        public T this[IHandle key]
 80        {
 81            get
 82            {
 83                Handle handle = ValidateThisHandle(key);
 84                return this.items[handle.index].value;
 85            }
 86
 87            set
 88            {
 89                Handle handle = ValidateThisHandle(key);
 90                this.items[handle.index].value = value;
 91                if (!BubbleUp(handle.index))
 92                    BubbleDown(handle.index);
 93            }
 94        }
 95
 96        #region ICollection Members
 97
 98        public bool IsSynchronized
 99        {
100            get { return false; }
101        }
102
103        public object SyncRoot
104        {
105            get
106            {
107                if (this.sync_root == null)
108                    Interlocked.CompareExchange<object>(ref this.sync_root, new object(), null);
109                return this.sync_root;
110            }
111        }
112
113        public void CopyTo(Array array, int index)
114        {
115            if (array == null)
116                throw new ArgumentNullException("array");
117            if (array.Rank != 1)
118                throw new ArgumentException("Multidimensional array not supported");
119            if (array.GetLowerBound(0) != 0)
120                throw new ArgumentException("Non-zero lower bound array not supported");
121
122            int length = array.Length;
123            if ((index < 0) || (index > length))
124                throw new ArgumentOutOfRangeException("index");
125            if ((length - index) < this.size)
126                throw new ArgumentException("Not enough space available in array starting at index");
127
128            try
129            {
130                for (int i = 0; i < this.size; ++i)
131                    array.SetValue(this.items[i].value, index + i);
132            }
133            catch (ArrayTypeMismatchException)
134            {
135                throw new ArgumentException("Invalid array type");
136            }
137        }
138
139        #endregion
140
141        #region ICollection<T> Members
142
143        public int Count
144        {
145            get { return this.size; }
146        }
147
148        public bool IsReadOnly
149        {
150            get { return false; }
151        }
152
153        public void Add(T value)
154        {
155            Add(value, null);
156        }
157
158        public void Clear()
159        {
160            for (int index = 0; index < this.size; ++index)
161                this.items[index].Clear();
162            this.size = 0;
163            ++this.version;
164        }
165
166        public bool Contains(T value)
167        {
168            return GetIndex(value) != -1;
169        }
170
171        public bool Remove(T value)
172        {
173            int index = GetIndex(value);
174            if (index != -1)
175            {
176                RemoveAt(index);
177                return true;
178            }
179            return false;
180        }
181
182        public void CopyTo(T[] array, int index)
183        {
184            if (array == null)
185                throw new ArgumentNullException("array");
186            if (array.Rank != 1)
187                throw new ArgumentException("Multidimensional array not supported");
188            if (array.GetLowerBound(0) != 0)
189                throw new ArgumentException("Non-zero lower bound array not supported");
190
191            int length = array.Length;
192            if ((index < 0) || (index > length))
193                throw new ArgumentOutOfRangeException("index");
194            if ((length - index) < this.size)
195                throw new ArgumentException("Not enough space available in array starting at index");
196
197            for (int i = 0; i < this.size; ++i)
198                array[index + i] = this.items[i].value;
199        }
200
201        public IEnumerator<T> GetEnumerator()
202        {
203            int version2 = this.version;
204
205            for (int index = 0; index < this.size; ++index)
206            {
207                if (version2 != this.version)
208                    throw new InvalidOperationException("Heap was modified while enumerating");
209                yield return this.items[index].value;
210            }
211        }
212
213        IEnumerator IEnumerable.GetEnumerator()
214        {
215            return GetEnumerator();
216        }
217
218        #endregion
219
220        private Handle ValidateHandle(IHandle ihandle)
221        {
222            if (ihandle == null)
223                throw new ArgumentNullException("handle");
224            Handle handle = ihandle as Handle;
225            if (handle == null)
226                throw new InvalidOperationException("handle is not valid");
227            return handle;
228        }
229
230        private Handle ValidateThisHandle(IHandle ihandle)
231        {
232            Handle handle = ValidateHandle(ihandle);
233            if (!ReferenceEquals(handle.heap, this))
234                throw new InvalidOperationException("handle is not valid for this heap");
235            if (handle.index < 0)
236                throw new InvalidOperationException("handle is not associated to a value");
237            return handle;
238        }
239
240        private void Set(HeapItem item, int index)
241        {
242            this.items[index] = item;
243            if (item.handle != null)
244                item.handle.index = index;
245        }
246
247        private bool BubbleUp(int index)
248        {
249            HeapItem item = this.items[index];
250            int current, parent;
251
252            for (current = index, parent = (current - 1)/2;
253                 (current > 0) && (this.comparison(this.items[parent].value, item.value)) > 0;
254                 current = parent, parent = (current - 1)/2)
255            {
256                Set(this.items[parent], current);
257            }
258
259            if (current != index)
260            {
261                Set(item, current);
262                ++this.version;
263                return true;
264            }
265            return false;
266        }
267
268        private void BubbleDown(int index)
269        {
270            HeapItem item = this.items[index];
271            int current, child;
272
273            for (current = index, child = (2*current) + 1;
274                 current < this.size/2;
275                 current = child, child = (2*current) + 1)
276            {
277                if ((child < this.size - 1) && this.comparison(this.items[child].value, this.items[child + 1].value) > 0)
278                    ++child;
279                if (this.comparison(this.items[child].value, item.value) >= 0)
280                    break;
281                Set(this.items[child], current);
282            }
283
284            if (current != index)
285            {
286                Set(item, current);
287                ++this.version;
288            }
289        }
290
291        public bool TryGetValue(IHandle key, out T value)
292        {
293            Handle handle = ValidateHandle(key);
294            if (handle.index > -1)
295            {
296                value = this.items[handle.index].value;
297                return true;
298            }
299            value = default(T);
300            return false;
301        }
302
303        public bool ContainsHandle(IHandle ihandle)
304        {
305            Handle handle = ValidateHandle(ihandle);
306            return ReferenceEquals(handle.heap, this) && handle.index > -1;
307        }
308
309        public void Add(T value, ref IHandle handle)
310        {
311            if (handle == null)
312                handle = new Handle();
313            Add(value, handle);
314        }
315
316        public void Add(T value, IHandle ihandle)
317        {
318            if (this.size == this.items.Length)
319            {
320                int capacity = (int) ((this.items.Length*200L)/100L);
321                if (capacity < (this.items.Length + DEFAULT_CAPACITY))
322                    capacity = this.items.Length + DEFAULT_CAPACITY;
323                Array.Resize(ref this.items, capacity);
324            }
325
326            Handle handle = null;
327            if (ihandle != null)
328            {
329                handle = ValidateHandle(ihandle);
330                handle.heap = this;
331            }
332
333            HeapItem item = new HeapItem(value, handle);
334
335            Set(item, this.size);
336            BubbleUp(this.size++);
337        }
338
339        public T Min()
340        {
341            if (this.size == 0)
342                throw new InvalidOperationException("Heap is empty");
343
344            return this.items[0].value;
345        }
346
347        public void TrimExcess()
348        {
349            int length = (int) (this.items.Length*0.9);
350            if (this.size < length)
351                Array.Resize(ref this.items, Math.Min(this.size, DEFAULT_CAPACITY));
352        }
353
354        private void RemoveAt(int index)
355        {
356            if (this.size == 0)
357                throw new InvalidOperationException("Heap is empty");
358            if (index >= this.size)
359                throw new ArgumentOutOfRangeException("index");
360
361            this.items[index].Clear();
362            if (--this.size > 0 && index != this.size)
363            {
364                Set(this.items[this.size], index);
365                if (!BubbleUp(index))
366                    BubbleDown(index);
367            }
368        }
369
370        public T RemoveMin()
371        {
372            if (this.size == 0)
373                throw new InvalidOperationException("Heap is empty");
374
375            HeapItem item = this.items[0];
376            RemoveAt(0);
377            return item.value;
378        }
379
380        public T Remove(IHandle ihandle)
381        {
382            Handle handle = ValidateThisHandle(ihandle);
383            HeapItem item = this.items[handle.index];
384            RemoveAt(handle.index);
385            return item.value;
386        }
387
388        private int GetIndex(T value)
389        {
390            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
391            int index;
392
393            for (index = 0; index < this.size; ++index)
394            {
395                if (comparer.Equals(this.items[index].value, value))
396                    return index;
397            }
398            return -1;
399        }
400
401        #region Nested type: Handle
402
403        private class Handle : IHandle
404        {
405            internal MinHeap<T> heap;
406            internal int index = -1;
407
408            internal void Clear()
409            {
410                this.index = -1;
411                this.heap = null;
412            }
413        }
414
415        #endregion
416
417        #region Nested type: HeapItem
418
419        private struct HeapItem
420        {
421            internal Handle handle;
422            internal T value;
423
424            internal HeapItem(T value, Handle handle)
425            {
426                this.value = value;
427                this.handle = handle;
428            }
429
430            internal void Clear()
431            {
432                this.value = default(T);
433                if (this.handle != null)
434                {
435                    this.handle.Clear();
436                    this.handle = null;
437                }
438            }
439        }
440
441        #endregion
442    }
443}