michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef NS_TPRIORITY_QUEUE_H_ michael@0: #define NS_TPRIORITY_QUEUE_H_ michael@0: michael@0: #include "nsTArray.h" michael@0: #include "nsDebug.h" michael@0: michael@0: /** michael@0: * A templatized priority queue data structure that uses an nsTArray to serve as michael@0: * a binary heap. The default comparator causes this to act like a min-heap. michael@0: * Only the LessThan method of the comparator is used. michael@0: */ michael@0: template > michael@0: class nsTPriorityQueue michael@0: { michael@0: public: michael@0: typedef typename nsTArray::size_type size_type; michael@0: michael@0: /** michael@0: * Default constructor also creates a comparator object using the default michael@0: * constructor for type Compare. michael@0: */ michael@0: nsTPriorityQueue() : mCompare(Compare()) { } michael@0: michael@0: /** michael@0: * Constructor to allow a specific instance of a comparator object to be michael@0: * used. michael@0: */ michael@0: nsTPriorityQueue(const Compare& aComp) : mCompare(aComp) { } michael@0: michael@0: /** michael@0: * Copy constructor michael@0: */ michael@0: nsTPriorityQueue(const nsTPriorityQueue& aOther) michael@0: : mElements(aOther.mElements), michael@0: mCompare(aOther.mCompare) michael@0: { } michael@0: michael@0: /** michael@0: * @return True if the queue is empty or false otherwise. michael@0: */ michael@0: bool IsEmpty() const michael@0: { michael@0: return mElements.IsEmpty(); michael@0: } michael@0: michael@0: /** michael@0: * @return The number of elements in the queue. michael@0: */ michael@0: size_type Length() const michael@0: { michael@0: return mElements.Length(); michael@0: } michael@0: michael@0: /** michael@0: * @return The topmost element in the queue without changing the queue. This michael@0: * is the element 'a' such that there is no other element 'b' in the queue for michael@0: * which Compare(b, a) returns true. (Since this container does not check michael@0: * for duplicate entries there may exist 'b' for which Compare(a, b) returns michael@0: * false.) michael@0: */ michael@0: const T& Top() const michael@0: { michael@0: NS_ABORT_IF_FALSE(!mElements.IsEmpty(), "Empty queue"); michael@0: return mElements[0]; michael@0: } michael@0: michael@0: /** michael@0: * Adds an element to the queue michael@0: * @param aElement The element to add michael@0: * @return true on success, false on out of memory. michael@0: */ michael@0: bool Push(const T& aElement) michael@0: { michael@0: T* elem = mElements.AppendElement(aElement); michael@0: if (!elem) michael@0: return false; // Out of memory michael@0: michael@0: // Sift up michael@0: size_type i = mElements.Length() - 1; michael@0: while (i) { michael@0: size_type parent = (size_type)((i - 1) / 2); michael@0: if (mCompare.LessThan(mElements[parent], mElements[i])) { michael@0: break; michael@0: } michael@0: Swap(i, parent); michael@0: i = parent; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: /** michael@0: * Removes and returns the top-most element from the queue. michael@0: * @return The topmost element, that is, the element 'a' such that there is no michael@0: * other element 'b' in the queue for which Compare(b, a) returns true. michael@0: * @see Top() michael@0: */ michael@0: T Pop() michael@0: { michael@0: NS_ABORT_IF_FALSE(!mElements.IsEmpty(), "Empty queue"); michael@0: T pop = mElements[0]; michael@0: michael@0: // Move last to front michael@0: mElements[0] = mElements[mElements.Length() - 1]; michael@0: mElements.TruncateLength(mElements.Length() - 1); michael@0: michael@0: // Sift down michael@0: size_type i = 0; michael@0: while (2*i + 1 < mElements.Length()) { michael@0: size_type swap = i; michael@0: size_type l_child = 2*i + 1; michael@0: if (mCompare.LessThan(mElements[l_child], mElements[i])) { michael@0: swap = l_child; michael@0: } michael@0: size_type r_child = l_child + 1; michael@0: if (r_child < mElements.Length() && michael@0: mCompare.LessThan(mElements[r_child], mElements[swap])) { michael@0: swap = r_child; michael@0: } michael@0: if (swap == i) { michael@0: break; michael@0: } michael@0: Swap(i, swap); michael@0: i = swap; michael@0: } michael@0: michael@0: return pop; michael@0: } michael@0: michael@0: /** michael@0: * Removes all elements from the queue. michael@0: */ michael@0: void Clear() michael@0: { michael@0: mElements.Clear(); michael@0: } michael@0: michael@0: /** michael@0: * Provides readonly access to the queue elements as an array. Generally this michael@0: * should be avoided but may be needed in some situations such as when the michael@0: * elements contained in the queue need to be enumerated for cycle-collection. michael@0: * @return A pointer to the first element of the array. If the array is michael@0: * empty, then this pointer must not be dereferenced. michael@0: */ michael@0: const T* Elements() const michael@0: { michael@0: return mElements.Elements(); michael@0: } michael@0: michael@0: protected: michael@0: /** michael@0: * Swaps the elements at the specified indices. michael@0: */ michael@0: void Swap(size_type aIndexA, size_type aIndexB) michael@0: { michael@0: T temp = mElements[aIndexA]; michael@0: mElements[aIndexA] = mElements[aIndexB]; michael@0: mElements[aIndexB] = temp; michael@0: } michael@0: michael@0: nsTArray mElements; michael@0: Compare mCompare; // Comparator object michael@0: }; michael@0: michael@0: #endif // NS_TPRIORITY_QUEUE_H_