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

com.samskivert.util.Predicate Maven / Gradle / Ivy

There is a newer version: 1.9
Show newest version
//
// $Id$
//
// samskivert library - useful routines for java programs
// Copyright (C) 2001-2011 Michael Bayne, et al.
//
// 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

package com.samskivert.util;

import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;

import com.samskivert.annotation.ReplacedBy;

/**
 * Arbitrates membership.
 *
 * Example usage:
 * Find the best kind of peanut butter:
 * public Iterator findBestKinds (Collection pbs)
 * {
 *     return new Predicate() {
 *         public boolean isMatch (PeanutButter pb)
 *         {
 *              return pb.isCreamy() && !pb.containsPartiallyHydrogenatedOils();
 *         }
 *     }.filter(pbs.iterator());
 * }
 *
 * An interface like this may someday be in the Java library, but until then...
 */
@ReplacedBy("com.google.common.base.Predicate")
public abstract class Predicate
{
    //--------------------------------------------------------------------
    // But first, some handy utility classes:

    /**
     * A simple predicate that includes an object if it is an instance
     * of the specified class.
     */
    public static class InstanceOf extends Predicate
    {
        public InstanceOf (Class clazz)
        {
            _class = clazz;
        }

        @Override public boolean isMatch (T obj)
        {
            return _class.isInstance(obj);
        }

        /** The class that must be implemented by applicants. */
        protected Class _class;
    }

    /**
     * Includes an object if and only if all the predicates with which it
     * was constructed also include the object. The predicates
     * are tested in the order specified and testing is halted as soon
     * as one does not include the object. If the Predicate is constructed
     * with no arguments, it will behave like TRUE.
     */
    public static class And extends Predicate
    {
        public And (Predicate ... preds)
        {
            _preds = preds;
        }

        @Override public boolean isMatch (T obj)
        {
            for (Predicate pred : _preds) {
                if (!pred.isMatch(obj)) {
                    return false;
                }
            }
            return true;
        }

        /** The predicates that all must be satisfied. */
        protected Predicate[] _preds;
    }

    /**
     * Includes an object if at least one of the predicates specified in the
     * constructor include the object. The predicates are tested in the
     * order specified and testing is halted as soon as one includes
     * the object. If the predicate is constructed with no arguments,
     * it will behave like FALSE.
     */
    public static class Or extends Predicate
    {
        public Or (Predicate ... preds)
        {
            _preds = preds;
        }

        @Override public boolean isMatch (T obj)
        {
            for (Predicate pred : _preds) {
                if (pred.isMatch(obj)) {
                    return true;
                }
            }
            return false;
        }

        protected Predicate[] _preds;
    }

    /**
     * Negates any other predicate.
     */
    public static class Not extends Predicate
    {
        public Not (Predicate negated)
        {
            _pred = negated;
        }

        @Override public boolean isMatch (T obj)
        {
            return !_pred.isMatch(obj);
        }

        protected Predicate _pred;
    }

    /**
     * Returns a type-safe reference to the shared instance of a predicate that always returns
     * true.
     */
    public static  Predicate trueInstance ()
    {
        @SuppressWarnings("unchecked") Predicate pred = (Predicate)TRUE_INSTANCE;
        return pred;
    }

    /**
     * Returns a type-safe reference to the shared instance of a predicate that always returns
     * false.
     */
    public static  Predicate falseInstance ()
    {
        @SuppressWarnings("unchecked") Predicate pred = (Predicate)FALSE_INSTANCE;
        return pred;
    }

    //--------------------------------------------------------------------
    // Here's the sole abstract method in the Predicate class:

    /**
     * Does the specified object belong to the special set that we test for?
     */
    public abstract boolean isMatch (T obj);

    //--------------------------------------------------------------------
    // And finally, some handy utility methods:

    /**
     * Return a new iterator that contains only matching elements from
     * the input iterator.
     */
    public  Iterator filter (final Iterator input)
    {
        return new Iterator() {
            // from Iterator
            public boolean hasNext ()
            {
                return _found || findNext();
            }

            // from Iterator
            public E next ()
            {
                if (_found || findNext()) {
                    _found = false;
                    return _last;

                } else {
                    throw new NoSuchElementException();
                }
            }

            // from Iterator
            public void remove ()
            {
                if (_removeable) {
                    _removeable = false;
                    input.remove();

                } else {
                    throw new IllegalStateException();
                }
            }

            private boolean findNext ()
            {
                boolean result = false;
                while (input.hasNext()) {
                    E candidate = input.next();
                    if (isMatch(candidate)) {
                        _last = candidate;
                        result = true;
                        break;
                    }
                }

                _found = result;
                _removeable = result;
                return result;
            }

            private E _last;
            private boolean _found; // because _last == null is a valid element
            private boolean _removeable;
        };
    }

    /**
     * Remove non-matching elements from the specified collection.
     */
    public  void filter (Collection coll)
    {
        for (Iterator itr = coll.iterator(); itr.hasNext(); ) {
            if (!isMatch(itr.next())) {
                itr.remove();
            }
        }
    }

    /**
     * Create an Iterable view of the specified Iterable that only contains
     * elements that match the predicate.
     * This Iterable can be iterated over at any time in the future to
     * view the current predicate-matching elements of the input Iterable.
     */
    public  Iterable createView (final Iterable input)
    {
        return new Iterable() {
            public Iterator iterator() {
                return filter(input.iterator());
            }
        };
    }

    /**
     * Create a view of the specified collection that only contains elements
     * that match the predicate.
     * This collection can be examined at any time in the future to view
     * the current predicate-matching elements of the input collection.
     *
     * Note that the view is not modifiable and currently has poor
     * implementations of some methods.
     */
    public  Collection createView (final Collection input)
    {
        // TODO: create a collection of the same type?
        return new AbstractCollection() {
            @Override public int size ()
            {
                // oh god, oh god: we iterate and count
                int size = 0;
                for (Iterator iter = iterator(); iter.hasNext(); ) {
                    iter.next();
                    size++;
                }
                return size;
            }

            @Override public boolean add (E element)
            {
                return input.add(element);
            }

            @Override public boolean remove (Object element)
            {
                return input.remove(element);
            }

            @Override public boolean contains (Object element)
            {
                try {
                    @SuppressWarnings("unchecked")
                    E elem = (E) element;
                    return isMatch(elem) && input.contains(elem);

                } catch (ClassCastException cce) {
                    // since it's not an E, it can't be a member of our view
                    return false;
                }
            }

            @Override public Iterator iterator ()
            {
                return filter(input.iterator());
            }
        };
    }

    /** A shared predicate instance that always matches its input. */
    protected static final Predicate TRUE_INSTANCE = new Predicate() {
        @Override public boolean isMatch (Object object) {
            return true;
        }
    };

    /** A shared predicate instance that never matches its input. */
    protected static final Predicate FALSE_INSTANCE = new Predicate() {
        @Override public boolean isMatch (Object object) {
            return false;
        }
    };
}