Java/Collections Data Structure/History

Материал из Java эксперт
Перейти к: навигация, поиск

History management

   <source lang="java">
 

/*

* Copyright (c) 1998-2002 Carnegie Mellon University.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS"" AND
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
* NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

import java.util.Enumeration; public class History {

   protected Object[] history;   // array of history objects (arranged as
                       // a circular queue)
   protected int start;      // points to oldest object in history
   protected int end;        // points after newest object in history
   protected int curr;       // points to current object;
                   // either start <= curr < end (modulo history.length)
                   // or start == curr == end
   /**
    * Make a History.
    * @param   max     Maximum length of history
    */
   public History (int max) {
       history = new Object[max+1];
       start = end = curr = 0;
   }
   /**
    * Make a duplicate of another History.
    * @param   h History to copy
    */
   public History (History h) {
       this.history = new Object[h.history.length];
       System.arraycopy (h.history, 0, this.history, 0, h.history.length);
       this.start = h.start;
       this.end = h.end;
       this.curr = h.curr;
   }
   /**
    * Clear the history.
    */
   public void clear () {
       for (int i = 0; i < history.length; ++i)
           history[i] = null;
       int s = start;
       int e = end;
       start = end = curr = 0;
       if (s != e)
           fireRemoved (s, (e > 0) ? e-1 : history.length-1);
   }
   /**
    * Double the capacity of the history.
    */
   public void expand () {
       Object[] newHistory = new Object[(history.length * 2) - 1];
       int i = 0;
       int newCurr = 0;
       for (int j = start; j != end; j = (j+1) % history.length, ++i) {
           newHistory[i] = history[j];
           if (j == curr)
               newCurr = i;
       }
       history = newHistory;
       start = 0;
       end = i;
       curr = newCurr;
   }
   /**
    * Add an object to the history after the current point (deleting all
    * objects forward of this point).  If history overflows, the oldest
    * object is thrown away.
    * @param obj   Object to add to history
    */
   public void put (Object obj) {
       if (!isEmpty ()) {
           // throw away all objects after curr
           int newEnd = (curr+1) % history.length;
           if (newEnd != end) {
               int e = end;
               end = newEnd;
               fireRemoved (newEnd, (e > 0) ? e-1 : history.length-1);
           }
       }
       add (obj);
   }
   /**
    * Add an object to the end of the history, moving the current point to it.
    * If history overflows, the oldest object is thrown away.
    * @param obj   Object to add to history
    */
   public void add (Object obj) {
       if (isFull ()) {
           // throw away oldest object to make room
           start = (start+1) % history.length;
           fireRemoved (start, start);
       }
       // insert the new object at end
       history[end] = obj;
       curr = end;
       end = (end+1) % history.length;
       fireAdded (curr, curr);
       System.out.println("after put: start=" + start + ", end=" + end + ", curr=" + curr);
   }
   /**
    * Get the current object of the history.
    * @return current object of history, or null if history is empty.
    */
   public Object get () {
       return !isEmpty () ? history[curr] : null;
   }
   /**
    * Get the object that would be returned by back(), without actually
    * changing the current object.
    * @return object before current object, or null if at beginning of 
    * history or history is empty.
    */
   public Object peekBack () {
       if (curr == start)
           return null;
       else {
           int bk = (curr > 0) ? curr-1 : history.length-1;
           return history[bk];
       }
   }
   /**
    * Get the object that would be returned by forward(), without actually
    * changing the current object.
    * @return object after current object, or null if at end of 
    * history or history is empty.
    */
   public Object peekForward () {
       if (start == end)
           return null;
       int fw = (curr+1) % history.length;
       if (fw == end)
           return null;
       else 
           return history[fw];
   }
   /**
    * Replace the current object of the history. The rest of the history
    * is unaffected, and the current pointer stays where it is.
*

If the history is empty, * then this call is equivalent to put(obj). * @param obj object to substitute */ public void replace (Object obj) { if (isEmpty ()) put (obj); else { history[curr] = obj; fireChanged (curr, curr); } } /** * Move back one object in the history, if possible. * @return previous object in the history, or null if at start. */ public Object back () { if (curr == start) return null; else { curr = (curr > 0) ? curr-1 : history.length-1; fireChanged (curr, curr); return history[curr]; } } /** * Move forward one object in the history, if possible. * @return next object in the history, or null if at end of history. */ public Object forward () { if (start == end) return null; int newCurr = (curr+1) % history.length; if (newCurr == end) return null; else { curr = newCurr; fireChanged (curr, curr); return history[curr]; } } /** * Move to first (oldest) object in the history, if possible. * @return first object in the history, or null if history empty. */ public Object toStart () { if (curr != start) { curr = start; fireChanged (curr, curr); } return history[curr]; } /** * Move to last (newest) object in the history, if possible. * @return last object in the history, or null if history empty. */ public Object toEnd () { if (start == end) return null; int newCurr = (end > 0) ? end-1 : history.length-1; if (curr != newCurr) { curr = newCurr; fireChanged (curr, curr); } return history[curr]; } /** * Test whether back() will succeed. * @return true if and only if there are objects before the current object */ public boolean canBack () { return (curr != start); } /** * Test whether forward() will succeed. * @return true if and only if there are objects after the current object */ public boolean canForward () { return ((curr+1) % history.length != end); } /** * Test whether history is empty. * @return true if and only if history contains no objects */ public boolean isEmpty () { return start == end; } /** * Test whether history is full. * @return true if and only if history contains max objects */ public boolean isFull () { return start == (end+1) % history.length; } /** * Test whether history already contains an object. * @param obj Object to search for * @return true if and only if history contains an object that equals() obj */ public boolean contains (Object obj) { for (int i = start; i != end; i = (i+1) % history.length) if (history[i].equals (obj)) return true; return false; } /** * Get the objects in the history. * @returns enumeration yielding the history objects in order from * oldest to newest. */ public Enumeration elements () { return new HistoryEnumeration (start, end); } /** * Get the objects AFTER the current object. * @returns enumeration yielding the history objects after current, * in order from oldest to newest. */ public Enumeration forwardElements () { return (curr == end)  ? new HistoryEnumeration (curr, end)  : new HistoryEnumeration ((curr + 1) % history.length, end); } /** * Get the objects BEFORE the current object. * @returns enumeration yielding the history objects before current, * in order from oldest to newest. */ public Enumeration backElements () { return new HistoryEnumeration (start, curr); } class HistoryEnumeration implements Enumeration { int p; int e; public HistoryEnumeration (int start, int end) { p = start; e = end; } public boolean hasMoreElements () { return p != e; } public Object nextElement () { Object obj = history[p]; p = (p+1) % history.length; return obj; } } protected void fireRemoved (int i, int j) { } protected void fireAdded (int i, int j) { } protected void fireChanged (int i, int j) { } } </source>