/* Copyright (C) 2006 Christian Schneider * * This file is part of Nomad. * * Nomad is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Nomad 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 for more details. * * You should have received a copy of the GNU General Public License * along with Nomad; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Created on May 9, 2006 */ package net.sf.nmedit.nmutils.collections2; import java.util.NoSuchElementException; /** * A lightweight stack implementation. * * The basic stack operations {@link #add(T)}, * {@link #getTop()}, {@link #removeTop()}, {@link #isEmpty()}, * {@link #clear()} are performed in constant time <code>O(1)</code>. * * @author Christian Schneider */ public class List<T> { // the linked list private ListEntry<T> list = null; // predecessor of current selection private ListEntry<T> predecessor = null; // current selection private ListEntry<T> selection = null; /** * Returns the internal list. * @return the internal list */ public ListEntry<T> getInternalList() { return list; } /** * Returns the size of the list. * The operation requires time <code>O(n)</code> * @return the size of the list. */ public int size() { if (list == null) return 0; ListEntry pos = list; int size = 0; while (pos!=null) { size++; pos=pos.remaining; } return size; } /** * Adds the specified item to the front of the list. * The operation is performed in constant time <code>O(1)</code>. * @param item */ public void add(T item) { list = new ListEntry<T>(item, list); } /** * Returns true when the list contains the specified item. * The operation is performed in time <code>O(n)</code>. * Repeated calls with the same argument are performed * in constant time <code>O(1)</code> * * @param item the item * @return true when the list contains the specified item */ public boolean contains(T item) { return select(item); } /** * Returns the top element of the list. * @return the top element of the list */ public T getTop() { if (isEmpty()) throw new NoSuchElementException(); return list.item; } /** * Removes the top element of the list. * * @return the top element of the list. * @throws NoSuchElementException if the list was empty */ public T removeTop() { if (isEmpty()) throw new NoSuchElementException(); if (list==selection||list==predecessor) deselect(); ListEntry<T> entry = list; list = list.remaining; entry.remaining = null; return entry.item; } /** * Removes the specified element from the list. * The operation is performed in time <code>O(n)</code>. * If the {@link #contains(T)} opertion was called before * with the same argument, and the specified item is in the list, * the operation is performed in constant time <code>O(1)</code>. * * @param item * @return <code>true</code> when the element was found and removed. */ public boolean remove(T item) { if (select(item)) { if (list == selection) { list = selection.remaining; } else { predecessor.remaining = selection.remaining; } selection.remaining = null; deselect(); return true; } else return false; } /** * Returns the predecessor of the {@link ListEntry} that was * selected by {@link #select(T)}. * @return the predecessor of the current selection */ protected ListEntry<T> getPredecessor() { return predecessor; } /** * Returns the {@link ListEntry} that was * selected by {@link #select(T)}. * @return the current selection */ protected ListEntry<T> getSelection() { return selection; } /** * Selects the specified item. * * @param item * @return returns true, when the specified item is in the list */ protected boolean select(T item) { if (list==null) { deselect(); return false; // nothing to select } else if (selection!=null && selection.item==item) { return true; // already selected } else if (list.item==item) { predecessor = null; selection = list; // select return true; } else { // search in list predecessor = list; selection = list.remaining; while (selection!=null) { if (selection.item==item) { // found return true; } predecessor = selection; selection = selection.remaining; } // item not in list predecessor = null; return false; } } /** * deselects the current selection */ protected void deselect() { predecessor = null; selection = null; } /** * Returns <code>true</code> when the list is empty * @return <code>true</code> when the list is empty */ public boolean isEmpty() { return list==null; } /** * Removes each element from the list. */ public void clear() { list = null; } }