Mega Code Archive

 
Categories / Java / Collections Data Structure
 

Support for breadth-first enumerating

/*  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.  *  * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.  *  * The contents of this file are subject to the terms of either the GNU  * General Public License Version 2 only ("GPL") or the Common  * Development and Distribution License("CDDL") (collectively, the  * "License"). You may not use this file except in compliance with the  * License. You can obtain a copy of the License at  * http://www.netbeans.org/cddl-gplv2.html  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the  * specific language governing permissions and limitations under the  * License.  When distributing the software, include this License Header  * Notice in each file and include the License file at  * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this  * particular file as subject to the "Classpath" exception as provided  * by Sun in the GPL Version 2 section of the License file that  * accompanied this code. If applicable, add the following below the  * License Header, with the fields enclosed by brackets [] replaced by  * your own identifying information:  * "Portions Copyrighted [year] [name of copyright owner]"  *  * Contributor(s):  *  * The Original Software is NetBeans. The Initial Developer of the Original  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun  * Microsystems, Inc. All Rights Reserved.  *  * If you wish your version of this file to be governed by only the CDDL  * or only the GPL Version 2, indicate your decision by adding  * "[Contributor] elects to include this software in this distribution  * under the [CDDL or GPL Version 2] license." If you do not indicate a  * single choice of license, a recipient has the option to distribute  * your version of this file under either the CDDL, the GPL Version 2 or  * to extend the choice of license to its licensees as provided above.  * However, if you add GPL Version 2 code and therefore, elected the GPL  * Version 2 license, then the option applies only if the new code is  * made subject to such option by the copyright holder.  */ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; /**  * @since 4.37  * @author Jaroslav Tulach  */ final class Enumerations extends Object {     /**      * Support for breadth-first enumerating.      * Before any element is returned      * for the resulting enumeration it is processed in the {@link Processor} and      * the processor is allowed to modify it and also add additional elements      * at the (current) end of the <q>queue</q> by calling <code>toAdd.add</code>      * or <code>toAdd.addAll</code>. No other methods can be called on the      * provided <code>toAdd</code> collection.      * <p>      * Example of doing breadth-first walk through a tree:      * <pre>      * Processor queueSubnodes = new Processor() {      *     public Object process(Object obj, Collection toAdd) {      *         Node n = (Node)obj;      *         toAdd.addAll (n.getChildrenList());      *         return n;      *     }      * };      * Enumeration strings = Enumerations.queue(elems, queueSubnodes);      * </pre>      *      * @param en initial content of the resulting enumeration      * @param filter the processor that is called for each element and can      *        add and addAll elements to its toAdd Collection argument and      *        also change the value to be returned      * @return enumeration with the initial and queued content (it can contain      *       <code>null</code> if the filter returned <code>null</code> from its      *       {@link Processor#process} method.      */     public static <T,R> Enumeration<R> queue(Enumeration<? extends T> en, Processor<T,R> filter) {         QEn<T,R> q = new QEn<T,R>(filter);         while (en.hasMoreElements()) {             q.put(en.nextElement());         }         return q;     }     /**      * Processor interface that can filter out objects from the enumeration,      * change them or add aditional objects to the end of the current enumeration.      */     public static interface Processor<T,R> {         /** @param original the object that is going to be returned from the enumeration right now          * @return a replacement for this object          * @param toAdd can be non-null if one can add new objects at the end of the enumeration          */         public R process(T original, Collection<T> toAdd);     }     /** Altering enumeration implementation */     private static final class AltEn<T,R> extends Object implements Enumeration<R> {         /** enumeration to filter */         private Enumeration<? extends T> en;         /** map to alter */         private Processor<T,R> process;         /**         * @param en enumeration to filter         */         public AltEn(Enumeration<? extends T> en, Processor<T,R> process) {             this.en = en;             this.process = process;         }         /** @return true if there is more elements in the enumeration         */         public boolean hasMoreElements() {             return en.hasMoreElements();         }         /** @return next object in the enumeration         * @exception NoSuchElementException can be thrown if there is no next object         *   in the enumeration         */         public R nextElement() {             return process.process(en.nextElement(), null);         }     }      // end of AltEn     /** QueueEnumeration      */     private static class QEn<T,R> extends Object implements Enumeration<R> {         /** next object to be returned */         private ListItem<T> next = null;         /** last object in the queue */         private ListItem<T> last = null;         /** processor to use */         private Processor<T,R> processor;         public QEn(Processor<T,R> p) {             this.processor = p;         }         /** Put adds new object to the end of queue.         * @param o the object to add         */         public void put(T o) {             if (last != null) {                 ListItem<T> li = new ListItem<T>(o);                 last.next = li;                 last = li;             } else {                 next = last = new ListItem<T>(o);             }         }         /** Adds array of objects into the queue.         * @param arr array of objects to put into the queue         */         public void put(Collection<? extends T> arr) {             for (T e : arr) {                 put(e);             }         }         /** Is there any next object?         * @return true if there is next object, false otherwise         */         public boolean hasMoreElements() {             return next != null;         }         /** @return next object in enumeration         * @exception NoSuchElementException if there is no next object         */         public R nextElement() {             if (next == null) {                 throw new NoSuchElementException();             }             T res = next.object;             if ((next = next.next) == null) {                 last = null;             }             ;             ToAdd<T,R> toAdd = new ToAdd<T,R>(this);             R out = processor.process(res, toAdd);             toAdd.finish();             return out;         }         /** item in linked list of Objects */         private static final class ListItem<T> {             T object;             ListItem<T> next;             /** @param o the object for this item */             ListItem(T o) {                 object = o;             }         }         /** Temporary collection that supports only add and addAll operations*/         private static final class ToAdd<T,R> extends Object implements Collection<T> {             private QEn<T,R> q;             public ToAdd(QEn<T,R> q) {                 this.q = q;             }             public void finish() {                 this.q = null;             }             public boolean add(T o) {                 q.put(o);                 return true;             }             public boolean addAll(Collection<? extends T> c) {                 q.put(c);                 return true;             }             private String msg() {                 return "Only add and addAll are implemented"; // NOI18N             }             public void clear() {                 throw new UnsupportedOperationException(msg());             }             public boolean contains(Object o) {                 throw new UnsupportedOperationException(msg());             }             public boolean containsAll(Collection c) {                 throw new UnsupportedOperationException(msg());             }             public boolean isEmpty() {                 throw new UnsupportedOperationException(msg());             }             public Iterator<T> iterator() {                 throw new UnsupportedOperationException(msg());             }             public boolean remove(Object o) {                 throw new UnsupportedOperationException(msg());             }             public boolean removeAll(Collection c) {                 throw new UnsupportedOperationException(msg());             }             public boolean retainAll(Collection c) {                 throw new UnsupportedOperationException(msg());             }             public int size() {                 throw new UnsupportedOperationException(msg());             }             public Object[] toArray() {                 throw new UnsupportedOperationException(msg());             }             public<X> X[] toArray(X[] a) {                 throw new UnsupportedOperationException(msg());             }         }          // end of ToAdd     }      // end of QEn     /** Filtering enumeration */     private static final class FilEn<T,R> extends Object implements Enumeration<R> {         /** marker object stating there is no nexte element prepared */         private static final Object EMPTY = new Object();         /** enumeration to filter */         private Enumeration<? extends T> en;         /** element to be returned next time or {@link #EMPTY} if there is         * no such element prepared */         private R next = empty();         /** the set to use as filter */         private Processor<T,R> filter;         /**         * @param en enumeration to filter         */         public FilEn(Enumeration<? extends T> en, Processor<T,R> filter) {             this.en = en;             this.filter = filter;         }         /** @return true if there is more elements in the enumeration         */         public boolean hasMoreElements() {             if (next != empty()) {                 // there is a object already prepared                 return true;             }             while (en.hasMoreElements()) {                 // read next                 next = filter.process(en.nextElement(), null);                 if (next != null) {                     // if the object is accepted                     return true;                 }                 ;             }             next = empty();             return false;         }         /** @return next object in the enumeration         * @exception NoSuchElementException can be thrown if there is no next object         *   in the enumeration         */         public R nextElement() {             if ((next == EMPTY) && !hasMoreElements()) {                 throw new NoSuchElementException();             }             R res = next;             next = empty();             return res;         }         @SuppressWarnings("unchecked")         private R empty() {             return (R)EMPTY;         }     }      // end of FilEn     /** Returns true from contains if object is not null */     private static class RNulls<T> implements Processor<T,T> {         public T process(T original, Collection<T> toAdd) {             return original;         }     }      // end of RNulls }