Coverage Report - org.apache.myfaces.shared.util.PriorityQueue
 
Classes in this File Line Coverage Branch Coverage Complexity
PriorityQueue
0%
0/74
0%
0/36
2.5
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.myfaces.shared.util;
 20  
 
 21  
 /** A PriorityQueue maintains a partial ordering of its elements such that the
 22  
  * least element can always be found in constant time.  Put()'s and pop()'s
 23  
  * require log(size) time.
 24  
  *
 25  
  * <p><b>NOTE</b>: This class will pre-allocate a full array of
 26  
  * length <code>maxSize+1</code> if instantiated via the
 27  
  * {@link #PriorityQueue(int,boolean)} constructor with
 28  
  * <code>prepopulate</code> set to <code>true</code>.
 29  
  * 
 30  
  * @lucene.internal
 31  
  * @see org.apache.lucene.util.PriorityQueue
 32  
 */
 33  
 public abstract class PriorityQueue<T>
 34  
 {
 35  
     private int size;
 36  
     private final int maxSize;
 37  
     private final T[] heap;
 38  
 
 39  
     public PriorityQueue(int maxSize)
 40  
     {
 41  0
         this(maxSize, true);
 42  0
     }
 43  
 
 44  
     @SuppressWarnings("unchecked")
 45  
     public PriorityQueue(int maxSize, boolean prepopulate)
 46  0
     {
 47  0
         size = 0;
 48  
         int heapSize;
 49  0
         if (0 == maxSize)
 50  
         {
 51  
             // We allocate 1 extra to avoid if statement in top()
 52  0
             heapSize = 2;
 53  
         }
 54  
         else
 55  
         {
 56  0
             if (maxSize == Integer.MAX_VALUE)
 57  
             {
 58  
                 // Don't wrap heapSize to -1, in this case, which
 59  
                 // causes a confusing NegativeArraySizeException.
 60  
                 // Note that very likely this will simply then hit
 61  
                 // an OOME, but at least that's more indicative to
 62  
                 // caller that this values is too big.  We don't +1
 63  
                 // in this case, but it's very unlikely in practice
 64  
                 // one will actually insert this many objects into
 65  
                 // the PQ:
 66  0
                 heapSize = Integer.MAX_VALUE;
 67  
             }
 68  
             else
 69  
             {
 70  
                 // NOTE: we add +1 because all access to heap is
 71  
                 // 1-based not 0-based.  heap[0] is unused.
 72  0
                 heapSize = maxSize + 1;
 73  
             }
 74  
         }
 75  0
         heap = (T[]) new Object[heapSize]; // T is unbounded type, so this unchecked cast works always
 76  0
         this.maxSize = maxSize;
 77  
 
 78  0
         if (prepopulate)
 79  
         {
 80  
             // If sentinel objects are supported, populate the queue with them
 81  0
             T sentinel = getSentinelObject();
 82  0
             if (sentinel != null)
 83  
             {
 84  0
                 heap[1] = sentinel;
 85  0
                 for (int i = 2; i < heap.length; i++)
 86  
                 {
 87  0
                     heap[i] = getSentinelObject();
 88  
                 }
 89  0
                 size = maxSize;
 90  
             }
 91  
         }
 92  0
     }
 93  
 
 94  
     /** Determines the ordering of objects in this priority queue.  Subclasses
 95  
      *  must define this one method.
 96  
      *  @return <code>true</code> iff parameter <tt>a</tt> is less than parameter <tt>b</tt>.
 97  
      */
 98  
     protected abstract boolean lessThan(T a, T b);
 99  
 
 100  
     /**
 101  
      * This method can be overridden by extending classes to return a sentinel
 102  
      * object which will be used by the {@link PriorityQueue#PriorityQueue(int,boolean)} 
 103  
      * constructor to fill the queue, so that the code which uses that queue can always
 104  
      * assume it's full and only change the top without attempting to insert any new
 105  
      * object.<br>
 106  
      * 
 107  
      * Those sentinel values should always compare worse than any non-sentinel
 108  
      * value (i.e., {@link #lessThan} should always favor the
 109  
      * non-sentinel values).<br>
 110  
      * 
 111  
      * By default, this method returns false, which means the queue will not be
 112  
      * filled with sentinel values. Otherwise, the value returned will be used to
 113  
      * pre-populate the queue. Adds sentinel values to the queue.<br>
 114  
      * 
 115  
      * If this method is extended to return a non-null value, then the following
 116  
      * usage pattern is recommended:
 117  
      * 
 118  
      * <pre>
 119  
      * // extends getSentinelObject() to return a non-null value.
 120  
      * PriorityQueue<MyObject> pq = new MyQueue<MyObject>(numHits);
 121  
      * // save the 'top' element, which is guaranteed to not be null.
 122  
      * MyObject pqTop = pq.top();
 123  
      * &lt;...&gt;
 124  
      * // now in order to add a new element, which is 'better' than top (after 
 125  
      * // you've verified it is better), it is as simple as:
 126  
      * pqTop.change().
 127  
      * pqTop = pq.updateTop();
 128  
      * </pre>
 129  
      * 
 130  
      * <b>NOTE:</b> if this method returns a non-null value, it will be called by
 131  
      * the {@link PriorityQueue#PriorityQueue(int,boolean)} constructor 
 132  
      * {@link #size()} times, relying on a new object to be returned and will not
 133  
      * check if it's null again. Therefore you should ensure any call to this
 134  
      * method creates a new instance and behaves consistently, e.g., it cannot
 135  
      * return null if it previously returned non-null.
 136  
      * 
 137  
      * @return the sentinel object to use to pre-populate the queue, or null if
 138  
      *         sentinel objects are not supported.
 139  
      */
 140  
     protected T getSentinelObject()
 141  
     {
 142  0
         return null;
 143  
     }
 144  
 
 145  
     /**
 146  
      * Adds an Object to a PriorityQueue in log(size) time. If one tries to add
 147  
      * more objects than maxSize from initialize an
 148  
      * {@link ArrayIndexOutOfBoundsException} is thrown.
 149  
      * 
 150  
      * @return the new 'top' element in the queue.
 151  
      */
 152  
     public final T add(T element)
 153  
     {
 154  0
         size++;
 155  0
         heap[size] = element;
 156  0
         upHeap();
 157  0
         return heap[1];
 158  
     }
 159  
 
 160  
     /**
 161  
      * Adds an Object to a PriorityQueue in log(size) time.
 162  
      * It returns the object (if any) that was
 163  
      * dropped off the heap because it was full. This can be
 164  
      * the given parameter (in case it is smaller than the
 165  
      * full heap's minimum, and couldn't be added), or another
 166  
      * object that was previously the smallest value in the
 167  
      * heap and now has been replaced by a larger one, or null
 168  
      * if the queue wasn't yet full with maxSize elements.
 169  
      */
 170  
     public T insertWithOverflow(T element)
 171  
     {
 172  0
         if (size < maxSize)
 173  
         {
 174  0
             add(element);
 175  0
             return null;
 176  
         }
 177  0
         else if (size > 0 && !lessThan(element, heap[1]))
 178  
         {
 179  0
             T ret = heap[1];
 180  0
             heap[1] = element;
 181  0
             updateTop();
 182  0
             return ret;
 183  
         }
 184  
         else
 185  
         {
 186  0
             return element;
 187  
         }
 188  
     }
 189  
 
 190  
     /** Returns the least element of the PriorityQueue in constant time. */
 191  
     public final T top()
 192  
     {
 193  
         // We don't need to check size here: if maxSize is 0,
 194  
         // then heap is length 2 array with both entries null.
 195  
         // If size is 0 then heap[1] is already null.
 196  0
         return heap[1];
 197  
     }
 198  
 
 199  
     /** Removes and returns the least element of the PriorityQueue in log(size)
 200  
       time. */
 201  
     public final T pop()
 202  
     {
 203  0
         if (size > 0)
 204  
         {
 205  0
             T result = heap[1]; // save first value
 206  0
             heap[1] = heap[size]; // move last to first
 207  0
             heap[size] = null; // permit GC of objects
 208  0
             size--;
 209  0
             downHeap(); // adjust heap
 210  0
             return result;
 211  
         }
 212  
         else
 213  
         {
 214  0
             return null;
 215  
         }
 216  
     }
 217  
 
 218  
     /**
 219  
      * Should be called when the Object at top changes values. Still log(n) worst
 220  
      * case, but it's at least twice as fast to
 221  
      * 
 222  
      * <pre>
 223  
      * pq.top().change();
 224  
      * pq.updateTop();
 225  
      * </pre>
 226  
      * 
 227  
      * instead of
 228  
      * 
 229  
      * <pre>
 230  
      * o = pq.pop();
 231  
      * o.change();
 232  
      * pq.push(o);
 233  
      * </pre>
 234  
      * 
 235  
      * @return the new 'top' element.
 236  
      */
 237  
     public final T updateTop()
 238  
     {
 239  0
         downHeap();
 240  0
         return heap[1];
 241  
     }
 242  
 
 243  
     /** Returns the number of elements currently stored in the PriorityQueue. */
 244  
     public final int size()
 245  
     {
 246  0
         return size;
 247  
     }
 248  
 
 249  
     /** Removes all entries from the PriorityQueue. */
 250  
     public final void clear()
 251  
     {
 252  0
         for (int i = 0; i <= size; i++)
 253  
         {
 254  0
             heap[i] = null;
 255  
         }
 256  0
         size = 0;
 257  0
     }
 258  
 
 259  
     private final void upHeap()
 260  
     {
 261  0
         int i = size;
 262  0
         T node = heap[i]; // save bottom node
 263  0
         int j = i >>> 1;
 264  0
         while (j > 0 && lessThan(node, heap[j]))
 265  
         {
 266  0
             heap[i] = heap[j]; // shift parents down
 267  0
             i = j;
 268  0
             j = j >>> 1;
 269  
         }
 270  0
         heap[i] = node; // install saved node
 271  0
     }
 272  
 
 273  
     private final void downHeap()
 274  
     {
 275  0
         int i = 1;
 276  0
         T node = heap[i]; // save top node
 277  0
         int j = i << 1; // find smaller child
 278  0
         int k = j + 1;
 279  0
         if (k <= size && lessThan(heap[k], heap[j]))
 280  
         {
 281  0
             j = k;
 282  
         }
 283  0
         while (j <= size && lessThan(heap[j], node))
 284  
         {
 285  0
             heap[i] = heap[j]; // shift up child
 286  0
             i = j;
 287  0
             j = i << 1;
 288  0
             k = j + 1;
 289  0
             if (k <= size && lessThan(heap[k], heap[j]))
 290  
             {
 291  0
                 j = k;
 292  
             }
 293  
         }
 294  0
         heap[i] = node; // install saved node
 295  0
     }
 296  
 
 297  
     /** This method returns the internal heap array as Object[].
 298  
      * @lucene.internal
 299  
      */
 300  
     protected final Object[] getHeapArray()
 301  
     {
 302  0
         return (Object[]) heap;
 303  
     }
 304  
 }