# HG changeset patch # User Jesse Glick # Date 1264632383 18000 # Node ID b3ae88304dd059b987d103e8d3552c0af70b815f # Parent 03dc6e747bb8e21715539de2715ac58d24f4eb45 Checking params for null. diff -r 03dc6e747bb8 -r b3ae88304dd0 openide.util/src/org/openide/util/Enumerations.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openide.util/src/org/openide/util/Enumerations.java Wed Jan 27 17:46:23 2010 -0500 @@ -0,0 +1,601 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2009 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. + */ + +package org.openide.util; + +import java.util.ArrayList; +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; + +/** + * Factory methods for various types of {@link Enumeration}. + * Allows composition of existing enumerations, filtering their contents, and/or modifying them. + * All of this is designed to be done lazily, i.e. elements created on demand. + * @since 4.37 + * @author Jaroslav Tulach + * @see NbCollections#checkedEnumerationByFilter + * @see NbCollections#iterable(Enumeration) + */ +public final class Enumerations extends Object { + /** No instances */ + private Enumerations() { + } + + /** + * An empty enumeration. + * Always returns false from + * empty().hasMoreElements() and throws NoSuchElementException + * from empty().nextElement(). + * @return the enumeration + */ + public static final Enumeration empty() { + Collection emptyL = Collections.emptyList(); + return Collections.enumeration(emptyL); + } + + /** + * Creates an enumeration with one element. + * @param obj the element to be present in the enumeration. + * @return enumeration + */ + public static Enumeration singleton(T obj) { + return Collections.enumeration(Collections.singleton(obj)); + } + + /** + * Concatenates the content of two enumerations into one. + * Until the + * end of en1 is reached its elements are being served. + * As soon as the en1 has no more elements, the content + * of en2 is being returned. + * + * @param en1 first enumeration + * @param en2 second enumeration + * @return enumeration + */ + public static Enumeration concat(Enumeration en1, Enumeration en2) { + ArrayList> two = new ArrayList>(); + two.add(en1); + two.add(en2); + return new SeqEn(Collections.enumeration(two)); + } + + /** + * Concatenates the content of many enumerations. + * The input value + * is enumeration of Enumeration elements and the result is composed + * all their content. Each of the provided enumeration is fully read + * and their content returned before the next enumeration is asked for + * their elements. + * + * @param enumOfEnums Enumeration of Enumeration elements + * @return enumeration + */ + public static Enumeration concat(Enumeration> enumOfEnums) { + return new SeqEn(enumOfEnums); + } + + /** + * Filters the input enumeration to new one that should contain + * each of the provided elements just once. + * The elements are compared + * using their default equals and hashCode methods. + * + * @param en enumeration to filter + * @return enumeration without duplicated items + */ + public static Enumeration removeDuplicates(Enumeration en) { + class RDupls implements Processor { + private Set set = new HashSet(); + + public T process(T o, Collection nothing) { + return set.add(o) ? o : null; + } + } + + return filter(en, new RDupls()); + } + + /** + * Returns an enumeration that iterates over provided array. + * @param arr the array of object + * @return enumeration of those objects + */ + public static Enumeration array(T... arr) { + return Collections.enumeration(Arrays.asList(arr)); + } + + /** + * Removes all nulls from the input enumeration. + * @param en enumeration that can contain nulls + * @return new enumeration without null values + */ + public static Enumeration removeNulls(Enumeration en) { + return filter(en, new RNulls()); + } + + /** + * For each element of the input enumeration en asks the + * {@link Processor} to provide a replacement. + * The toAdd argument of the processor is always null. + *

+ * Example to convert any objects into strings: + *

+     * Processor convertToString = new Processor() {
+     *     public Object process(Object obj, Collection alwaysNull) {
+     *         return obj.toString(); // converts to string
+     *     }
+     * };
+     * Enumeration strings = Enumerations.convert(elems, convertToString);
+     * 
+ * + * @param en enumeration of any objects + * @param processor a callback processor for the elements (its toAdd arguments is always null) + * @return new enumeration where all elements has been processed + */ + public static Enumeration convert(Enumeration en, Processor processor) { + return new AltEn(en, processor); + } + + /** + * Filters some elements out from the input enumeration. + * Just make the + * {@link Processor} return null. Please notice the toAdd + * argument of the processor is always null. + *

+ * Example to remove all objects that are not strings: + *

+     * Processor onlyString = new Processor() {
+     *     public Object process(Object obj, Collection alwaysNull) {
+     *         if (obj instanceof String) {
+     *             return obj;
+     *         } else {
+     *             return null;
+     *         }
+     *     }
+     * };
+     * Enumeration strings = Enumerations.filter(elems, onlyString);
+     * 
+ * + * @param en enumeration of any objects + * @param filter a callback processor for the elements (its toAdd arguments is always null) + * @return new enumeration which does not include non-processed (returned null from processor) elements + * @see NbCollections#checkedEnumerationByFilter + */ + public static Enumeration filter(Enumeration en, Processor filter) { + Parameters.notNull("en", en); + Parameters.notNull("filter", filter); + return new FilEn(en, filter); + } + + /** + * 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 queue by calling toAdd.add + * or toAdd.addAll. No other methods can be called on the + * provided toAdd collection. + *

+ * Example of doing breadth-first walk through a tree: + *

+     * 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);
+     * 
+ * + * @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 + * null if the filter returned null from its + * {@link Processor#process} method. + */ + public static Enumeration queue(Enumeration en, Processor filter) { + QEn q = new QEn(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 { + /** @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 toAdd); + } + + /** Altering enumeration implementation */ + private static final class AltEn extends Object implements Enumeration { + /** enumeration to filter */ + private Enumeration en; + + /** map to alter */ + private Processor process; + + /** + * @param en enumeration to filter + */ + public AltEn(Enumeration en, Processor 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 + + /** Sequence of enumerations */ + private static final class SeqEn extends Object implements Enumeration { + /** enumeration of Enumerations */ + private Enumeration> en; + + /** current enumeration */ + private Enumeration current; + + /** is {@link #current} up-to-date and has more elements? + * The combination current == null and + * checked == true means there are no more elements + * in this enumeration. + */ + private boolean checked = false; + + /** Constructs new enumeration from already existing. The elements + * of en should be also enumerations. The resulting + * enumeration contains elements of such enumerations. + * + * @param en enumeration of Enumerations that should be sequenced + */ + public SeqEn(Enumeration> en) { + this.en = en; + } + + /** Ensures that current enumeration is set. If there aren't more + * elements in the Enumerations, sets the field current to null. + */ + private void ensureCurrent() { + while ((current == null) || !current.hasMoreElements()) { + if (en.hasMoreElements()) { + current = en.nextElement(); + } else { + // no next valid enumeration + current = null; + + return; + } + } + } + + /** @return true if we have more elements */ + public boolean hasMoreElements() { + if (!checked) { + ensureCurrent(); + checked = true; + } + + return current != null; + } + + /** @return next element + * @exception NoSuchElementException if there is no next element + */ + public T nextElement() { + if (!checked) { + ensureCurrent(); + } + + if (current != null) { + checked = false; + + return current.nextElement(); + } else { + checked = true; + throw new java.util.NoSuchElementException(); + } + } + } + // end of SeqEn + + /** QueueEnumeration + */ + private static class QEn extends Object implements Enumeration { + /** next object to be returned */ + private ListItem next = null; + + /** last object in the queue */ + private ListItem last = null; + + /** processor to use */ + private Processor processor; + + public QEn(Processor 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 li = new ListItem(o); + last.next = li; + last = li; + } else { + next = last = new ListItem(o); + } + } + + /** Adds array of objects into the queue. + * @param arr array of objects to put into the queue + */ + public void put(Collection 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 toAdd = new ToAdd(this); + R out = processor.process(res, toAdd); + toAdd.finish(); + + return out; + } + + /** item in linked list of Objects */ + private static final class ListItem { + T object; + ListItem 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 extends Object implements Collection { + private QEn q; + + public ToAdd(QEn q) { + this.q = q; + } + + public void finish() { + this.q = null; + } + + public boolean add(T o) { + q.put(o); + + return true; + } + + public boolean addAll(Collection 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 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[] toArray(X[] a) { + throw new UnsupportedOperationException(msg()); + } + } + // end of ToAdd + } + // end of QEn + + /** Filtering enumeration */ + private static final class FilEn extends Object implements Enumeration { + /** marker object stating there is no nexte element prepared */ + private static final Object EMPTY = new Object(); + + /** enumeration to filter */ + private Enumeration 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 filter; + + /** + * @param en enumeration to filter + */ + public FilEn(Enumeration en, Processor 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 implements Processor { + public T process(T original, Collection toAdd) { + return original; + } + } + // end of RNulls +}