All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.emf.common.util.AbstractTreeIterator Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2002-2006 IBM Corporation and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: 
 *   IBM - Initial API and implementation
 */
package org.eclipse.emf.common.util;


import java.util.Iterator;


/**
 * An extensible tree iterator implementation 
 * that iterates over an object, it's children, their children, and so on.
 * Clients need only implement {@link #getChildren getChildren} 
 * in order to implement a fully functional tree iterator.
 */
public abstract class AbstractTreeIterator extends BasicEList> implements TreeIterator
{
  private static final long serialVersionUID = 1L;

  /**
   * Whether the first call to next returns the initial root object 
   * or begins with the first child of the root object.
   */
  protected boolean includeRoot;

  /**
   * The root object for which the iteration is initiated.
   */
  protected Object object;

  /**
   * The iterator that would be cut short by a call to {@link #prune}.
   */
  protected Iterator nextPruneIterator;

  /**
   * The iterator to which a {@link #remove} call will delegated.
   */
  protected Iterator nextRemoveIterator;

  /**
   * Creates an instance that iterates over an object, it's children, their children, and so on.
   * @param object the root object of the tree.
   */
  public AbstractTreeIterator(E object)
  {
    this.object = object;
    this.includeRoot = true;
  }

  /**
   * 

Creates and instance that iterates over an object (but only if includeRoot is true), * it's children, their children, and so on.

*

If includeRoot is true, the object is expected * to be of the type E. */ public AbstractTreeIterator(Object object, boolean includeRoot) { this.object = object; this.includeRoot = includeRoot; } /** * Returns the iterator that yields the children of the object. * @param object the object for which children are required. * @return the iterator that yields the children. */ protected abstract Iterator getChildren(Object object); /** * Returns whether there are more elements. * @return whether there are more elements. */ public boolean hasNext() { if (data == null && !includeRoot) { return hasAnyChildren(); } else { return hasMoreChildren(); } } private boolean hasAnyChildren() { Iterator nextPruneIterator = this.nextPruneIterator; nextPruneIterator = getChildren(object); add(nextPruneIterator); return nextPruneIterator.hasNext(); } private boolean hasMoreChildren() { // We don't create an iterator stack until the root mapping itself has been returned by next once. // After that the stack should be non-empty and the top iterator should yield true for hasNext. return data == null || !isEmpty() && ((Iterator)data[size - 1]).hasNext(); } /** * Returns the next object and advances the iterator. * @return the next object. */ public E next() { // If we are still on the root mapping itself... // if (data == null) { // Yield that mapping, create a stack, record it as the next one to prune, and add it to the stack. // nextPruneIterator = getChildren(object); add(nextPruneIterator); if (includeRoot) { @SuppressWarnings("unchecked") E result = (E)object; return result; } } // Get the top iterator, retrieve it's result, and record it as the one to which remove will be delegated. // @SuppressWarnings("unchecked") Iterator currentIterator = (Iterator)data[size - 1]; E result = currentIterator.next(); nextRemoveIterator = currentIterator; // If the result about to be returned has children... // Iterator iterator = getChildren(result); if (iterator.hasNext()) { // Record the iterator as the next one to prune, and add it to the stack. // nextPruneIterator = iterator; add(iterator); } else { // There will be no iterator to prune. // nextPruneIterator = null; // While the current iterator has no next... // while (!currentIterator.hasNext()) { // Pop it from the stack. // data[--size] = null; // If the stack is empty, we're done. // if (isEmpty()) { break; } // Get the next one down and then test it for has next. // @SuppressWarnings("unchecked") Iterator nextIterator = (Iterator)data[size - 1]; currentIterator = nextIterator; } } return result; } /** * Removes the last object returned by {@link #next()} from the underlying tree; * it's an optional operation. * @exception IllegalStateException * if next has not yet been called or has been called only the yield the root object, * or remove has already been called after the last call to the next method. * */ public void remove() { if (nextRemoveIterator == null) { throw new IllegalStateException("There is no valid object to remove."); } nextRemoveIterator.remove(); } /** * Prunes the iterator so that it skips over all the nodes below the most recent result of calling {@link #next next()}. */ public void prune() { // If there is an iterator to prune. // if (nextPruneIterator != null) { // If that iterator is still at the top of the stack... // if (!isEmpty() && data[size - 1] == nextPruneIterator) { // Pop it off the stack. // data[--size] = null; // Keep popping the stack until an iterator that has a next is at the top. // while (!isEmpty() && !((Iterator)data[size - 1]).hasNext()) { data[--size] = null; } } // You can only prune once. // nextPruneIterator = null; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy