FileDocCategorySizeDatePackage
DoublyLinkedList.javaAPI DocphoneME MR2 API (J2ME)7579Wed May 02 18:00:34 BST 2007com.sun.perseus.util

DoublyLinkedList.java

/*
 *
 *
 * Portions Copyright  2000-2007 Sun Microsystems, Inc. All Rights
 * Reserved.  Use is subject to license terms.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */

/*****************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included with this distribution in  *
 * the LICENSE file.                                                         *
 *****************************************************************************/

package com.sun.perseus.util;

/**
 * A simple Doubly Linked list class, designed to avoid
 * O(n) behaviour on insert and delete.
 *
 * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a>
 * @version $Id: DoublyLinkedList.java,v 1.2 2006/04/21 06:35:47 st125089 Exp $
 */
public class DoublyLinkedList {

    // ========================================================================
    // Inner static Node class
    // ========================================================================

    /**
     * Basic doubly linked list node interface.
     */
    public static class Node {
        /**
         * This node's next neighbour
         */
        private Node next = null;

        /**
         * This node's previous neighbour
         */
        private Node prev = null;
        
        /**
         * @return this node's next neighbour in the list
         */
        public final Node getNext() { 
            return next; 
        }

        /**
         * @return this node's previous neighbour
         */
        public final Node getPrev() { 
            return prev; 
        }
        
        /**
         * @param newNext the new next node
         */
        protected final void setNext(final Node newNext) { 
            next = newNext; 
        }

        /**
         * @param newPrev the new previous node
         */
        protected final void setPrev(final Node newPrev) { 
            prev = newPrev; 
        }
        
        /**
         * Unlink this node from it's current list...
         */
        protected final void unlink() {
            if (getNext() != null) {
                getNext().setPrev(getPrev());
            }

            if (getPrev() != null) {
                getPrev().setNext(getNext());
            }
            setNext(null);
            setPrev(null);
        }
        
        /**
         * Link this node in, infront of nde (unlinks it's self
         * before hand if needed).
         * @param nde the node to link in before.
         */
        protected final void insertBefore(final Node nde) {
            // Already here...
            if (this == nde) {
                return;
            }
            
            if (getPrev() != null) {
                unlink();
            }

            // Actually insert this node...
            if (nde == null) {
                // empty lst...
                setNext(this);
                setPrev(this);
            } else {
                setNext(nde);
                setPrev(nde.getPrev());
                nde.setPrev(this);
                if (getPrev() != null) {
                    getPrev().setNext(this);
                }
            }
        }
    }

    // ========================================================================
    // End of inner static Node class
    // ========================================================================
    

    /**
     * The list's head. The previous node is the tail of the list
     */
    private Node head = null;

    /**
     * The list's size
     */
    private int  size = 0;
    
    /**
     * Default constructor
     */
    public DoublyLinkedList() {
    }
            
    /**
     * @return the number of elements currently in the list.
     */
    public int getSize() { 
        return size; 
    }

    /**
     * Removes all elements from the list.
     */
    public void empty() {
        while (size > 0) {
            pop();
        }
    }
            
    /**
     * Get the current head element
     * @return The current 'first' element in list.
     */
    public Node getHead() { 
        return head; 
    }

    /**
     * Get the current tail element
     * @return The current 'last' element in list.
     */
    public Node getTail() { 
        if (head != null) {
            return head.getPrev(); 
        } else {
            return null;
        }
    }

    /**
     * Adds <code>nde</code> to the head of the list.
     * In perl this is called an 'unpop'.  <code>nde</code> should
     * not currently be part of any list.
     * @param nde the node to add to the list.
     */
    public void add(final Node nde) {
        nde.insertBefore(head);
        head = nde;
        size++;
    }
        
    /**
     * Removes nde from the list it is part of (should be this
     * one, otherwise results are undefined).  If nde is the
     * current head element, then the next element becomes head,
     * if there are no more elements the list becomes empty.
     * @param nde <code>Node</code> to remove.
     */
    public void remove(final Node nde) {
        if (nde == head) {
            if (head.getNext() == head) {
                head = null;  // Last node...
            } else {
                head = head.getNext();
            }
        }
        nde.unlink();
        size--;
    }

    /**
     * Removes 'head' from list and returns it. Returns null if list is empty.
     * @return current head element, next element becomes head.
     */
    public Node pop() {
        if (head == null) {
            return null;
        }
            
        Node nde = head;
        remove(nde);
        return nde;
    }

    /**
     * Removes 'tail' from list and returns it. Returns null if list is empty.
     * @return current tail element.
     */
    public Node unpush() {
        if (head == null) {
            return null;
        }
            
        Node nde = getTail();
        remove(nde);
        return nde;
    }



    /**
     * @param nde the <code>Node</code> to add to tail of list
     */
    public void push(final Node nde) {
        nde.insertBefore(head);
        if (head == null) {
            head = nde;
        }
        size++;
    }

    /**
     * @param nde the <code>Node</code> to put to the head of list
     */
    public void unpop(final Node nde) {
        nde.insertBefore(head);
        head = nde;
        size++;
    }
}