| WeakBumpyStack |

    1   /*
    2    *  Copyright (c) 1998-2001, The University of Sheffield.
    3    *
    4    *  This file is part of GATE (see http://gate.ac.uk/), and is free
    5    *  software, licenced under the GNU Library General Public License,
    6    *  Version 2, June 1991 (in the distribution as file licence.html,
    7    *  and also available at http://gate.ac.uk/gate/licence.html).
    8    *
    9    *  Valentin Tablan, 10/Oct/2001
    10   *
    11   *  $Id: WeakBumpyStack.java,v 1.4 2001/11/24 18:23:24 hamish Exp $
    12   */
    13
    14  ////////////////////////////////////////////////////////////////////
    15  //////////// DEVELOPERS: SEE WARNING IN JAVADOC COMMENT FOR
    16  //////////// THIS CLASS!!!!
    17  ////////////////////////////////////////////////////////////////////
    18
    19  package gate.util;
    20
    21  import java.util.*;
    22  import java.lang.ref.*;
    23
    24  import gate.*;
    25
    26  /**
    27   * Weak stack that allow you to bump an element to the front.
    28   * Objects that are only referenced by this stack will be candidates for
    29   * garbage collection and wil be removed from the stack as soon as the garbage
    30   * collector marks them for collection.
    31   * <P>
    32   * <B>*** WARNING: ***</B> the test for this class,
    33   * <TT>TestBumpyStack.testSelfCleaning</TT> is not a proper test; it doesn't
    34   * fail even when it should, and only prints a warning when DEBUG is true.
    35   * This is because to test it properly you need to force garbage collection,
    36   * and that isn't possible. So, if you work on this class <B>you must
    37   * turn DEBUG on on TestBumpyStack</B> in order to run the tests in a
    38   * meaningfull way.
    39   */
    40  public class WeakBumpyStack extends AbstractList
    41  {
    42
    43    /**
    44     * Creates a new empty stack.
    45     */
    46    public WeakBumpyStack(){
    47      supportStack = new Stack();
    48      refQueue = new ReferenceQueue();
    49    }
    50
    51    /**
    52     * Pushes an item onto the top of this stack. This has exactly
    53     * the same effect as:
    54     * <blockquote><pre>
    55     * addElement(item)</pre></blockquote>
    56     *
    57     * @param   item   the item to be pushed onto this stack.
    58     * @return  the <code>item</code> argument.
    59     */
    60    public Object push(Object item){
    61      supportStack.push(new WeakReference(item,refQueue));
    62      return item;
    63    }
    64
    65    /**
    66     * Removes the object at the top of this stack and returns that
    67     * object as the value of this function.
    68     *
    69     * @return     The object at the top of this stack.
    70     * @exception  EmptyStackException  if this stack is empty.
    71     */
    72    public synchronized Object pop(){
    73      processQueue();
    74      //we need to check for null in case the top reference has just been cleared
    75      Object res = null;
    76      while(res == null){
    77        res = ((WeakReference)supportStack.pop()).get();
    78      }
    79      return res;
    80    }
    81
    82
    83    /**
    84     * Looks at the object at the top of this stack without removing it
    85     * from the stack.
    86     *
    87     * @return     the object at the top of this stack.
    88     * @exception  EmptyStackException  if this stack is empty.
    89     */
    90    public synchronized Object peek(){
    91      processQueue();
    92      //we need to check for null in case the top reference has just been cleared
    93      Object res = null;
    94      while(res == null){
    95        res = ((WeakReference)supportStack.peek()).get();
    96      }
    97      return res;
    98    }
    99
    100   /**
    101    * Tests if this stack is empty.
    102    *
    103    * @return  <code>true</code> if and only if this stack contains
    104    *          no items; <code>false</code> otherwise.
    105    */
    106   public boolean empty() {
    107     processQueue();
    108     return supportStack.empty();
    109   }
    110
    111
    112   /** Bump an item to the front of the stack.
    113     * @param item the item to bump
    114     * @return true when the item was found, else false
    115     */
    116   public boolean bump(Object item) {
    117     processQueue();
    118
    119     int itemIndex = search(item);
    120
    121     if(itemIndex == -1) // not a member of the stack
    122       return false;
    123     else if(itemIndex == 1) // at the front already
    124       return true;
    125
    126     WeakReference wr = (WeakReference)supportStack.remove(itemIndex - 1);
    127     supportStack.push(wr);
    128     return true;
    129   } // bump
    130
    131   /**
    132    * Returns the 1-based position where an object is on this stack.
    133    * If the object <tt>o</tt> occurs as an item in this stack, this
    134    * method returns the distance from the top of the stack of the
    135    * occurrence nearest the top of the stack; the topmost item on the
    136    * stack is considered to be at distance <tt>1</tt>. The <tt>equals</tt>
    137    * method is used to compare <tt>o</tt> to the
    138    * items in this stack.
    139    *
    140    * @param   o   the desired object.
    141    * @return  the 1-based position from the top of the stack where
    142    *          the object is located; the return value <code>-1</code>
    143    *          indicates that the object is not on the stack.
    144    */
    145   public synchronized int search(Object o) {
    146     processQueue();
    147     int i = supportStack.size() - 1;
    148     while(i >= 0 &&
    149           !((WeakReference)supportStack.get(i)).get().equals(o)) i--;
    150     if (i >= 0) {
    151       return supportStack.size() - i;
    152     }
    153     return -1;
    154   }
    155
    156
    157   /**
    158    * Checks the queue for any new weak references that have been cleared and
    159    * queued and removes them from the underlying stack.
    160    *
    161    * This method should be called by every public method before realising its
    162    * internal logic.
    163    */
    164   protected void processQueue(){
    165     WeakReference wr;
    166     while ((wr = (WeakReference)refQueue.poll()) != null) {
    167       supportStack.remove(wr);
    168     }
    169   }
    170
    171   /**
    172    * Returns the element at the specified position in this list.
    173    *
    174    * @param  index index of element to return.
    175    * @return the element at the specified position in this list.
    176    * @throws    IndexOutOfBoundsException if index is out of range <tt>(index
    177    *      &lt; 0 || index &gt;= size())</tt>.
    178    */
    179   public Object get(int index) {
    180     processQueue();
    181     //we need to check for null in case the top reference has just been cleared
    182     Object res = null;
    183     while(res == null){
    184       res = ((WeakReference)supportStack.get(index)).get();
    185     }
    186     return res;
    187   }
    188
    189   /**
    190    * Returns the number of elements in this list.
    191    *
    192    * @return  the number of elements in this list.
    193    */
    194   public int size() {
    195     processQueue();
    196     return supportStack.size();
    197   }
    198
    199   /**
    200    * Replaces the element at the specified position in this list with
    201    * the specified element.
    202    *
    203    * @param index index of element to replace.
    204    * @param element element to be stored at the specified position.
    205    * @return the element previously at the specified position.
    206    * @throws    IndexOutOfBoundsException if index out of range
    207    *      <tt>(index &lt; 0 || index &gt;= size())</tt>.
    208    */
    209   public Object set(int index, Object element) {
    210     processQueue();
    211     WeakReference ref = (WeakReference)
    212                         supportStack.set(index,
    213                                          new WeakReference(element, refQueue));
    214     return ref.get();
    215   }
    216
    217   /**
    218    * Inserts the specified element at the specified position in this
    219    * list. Shifts the element currently at that position (if any) and
    220    * any subsequent elements to the right (adds one to their indices).
    221    *
    222    * @param index index at which the specified element is to be inserted.
    223    * @param element element to be inserted.
    224    * @throws    IndexOutOfBoundsException if index is out of range
    225    *      <tt>(index &lt; 0 || index &gt; size())</tt>.
    226    */
    227   public void add(int index, Object element) {
    228     processQueue();
    229     supportStack.add(index, new WeakReference(element, refQueue));
    230   }
    231
    232   /**
    233    * Removes the element at the specified position in this list.
    234    * Shifts any subsequent elements to the left (subtracts one from their
    235    * indices).
    236    *
    237    * @param index the index of the element to removed.
    238    * @return the element that was removed from the list.
    239    * @throws    IndexOutOfBoundsException if index out of range <tt>(index
    240    *      &lt; 0 || index &gt;= size())</tt>.
    241    */
    242   public Object remove(int index) {
    243     processQueue();
    244     //we need to check for null in case the top reference has just been cleared
    245     Object res = null;
    246     while(res == null){
    247       res = ((WeakReference)supportStack.remove(index)).get();
    248     }
    249     return res;
    250   }
    251
    252   ReferenceQueue refQueue;
    253
    254   /**
    255    * This is the underlying stack object for this weak stack. It holds weak
    256    * references to the objects that are the actual contents of this stack.
    257    */
    258   Stack supportStack;
    259 } // class BumpyStack
    260

| WeakBumpyStack |