Thursday, September 18, 2003

ListIterator and List equivalent

A ListIterator is equivalent to the List interface. To demonstrate this, I'm writing a IteratorList class which implements the List interface over an underlying ListIterator; it's actually quite simple. More fun with iterators! Here it is (note, not tested—I just wanted to sketch it out to see what it'd look like):

/*
 * IteratorList.java
 * Copyright 2003 (C) B. K. Oxley (binkley)
 * <binkley@alumni.rice.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 * Created on June 4, 2003.
 */

package hm.binkley.util;

import java.lang.reflect.Array;
import java.util.AbstractList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

/**
 * <code>IteratorList</code> implements <code>List</code> from an
 * underlying <code>ListIterator</code>.
 *
 * @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a>
 * @version 1.0
 */
public class IteratorList extends AbstractList {
    /** The underlying list iterator. */
    private final ListIterator it;

    /**
     * Constructs a <code>IteratorList</code> code from an underyling
     * <code>ListIterator</code> object.
     *
     * @param it the list iterator
     */
    public IteratorList(ListIterator it) {
	this.it = it;
    }

    /**
     * Resets the underlying list iterator back to its starting state.
     */
    private void reset() {
	while (it.hasPrevious())
	    it.previous();
    }

    /**
     * Positions the underlying iterator before <var>index</var>.  The
     * caller needs to then call {@link #next()} as required.
     *
     * @param index the index
     * @throws IndexOutOfBoundsException if <var>index</var> is out of
     * range
     */
    private void scrollTo(int index) {
	if (index < 0)
	    throw new IndexOutOfBoundsException();

	// Ensure we call one extra next for the index itself
	while (index-- > 0)
	    if (it.hasNext())
		it.next();
	    else
		throw new IndexOutOfBoundsException();
    }

    /** {@inheritDoc} */
    public int size() {
	int n = 0;

	for ( ; it.hasNext(); ++n)
	    it.next();

	reset();

	return n;
    }

    /** {@inheritDoc} */
    public Object get(int index) {
	try {
	    scrollTo(index);

	    if (it.hasNext())
		return it.next();
	    else
		throw new IndexOutOfBoundsException();
	}

	finally {
	    reset();
	}
    }

    /** {@inheritDoc} */
    public Object set(int index, Object element) {
	try {
	    scrollTo(index);

	    if (it.hasNext()) {
		Object old = it.next();
		it.set(element);
		return old;
	    }

	    else
		throw new IndexOutOfBoundsException();
	}

	finally {
	    reset();
	}
    }

    /** {@inheritDoc} */
    public void add(int index, Object element) {
	try {
	    scrollTo(index);

	    if (it.hasNext()) {
		it.next();
		it.add(element);
	    }

	    else
		throw new IndexOutOfBoundsException();
	}

	finally {
	    reset();
	}
    }

    /** {@inheritDoc} */
    public Object remove(int index) {
	try {
	    scrollTo(index);

	    if (it.hasNext()) {
		Object old = it.next();
		it.remove();
		return old;
	    }

	    else
		throw new IndexOutOfBoundsException();
	}

	finally {
	    reset();
	}
    }
}

No comments: