001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.functor.core.algorithm;
018    
019    import java.io.Serializable;
020    import java.util.NoSuchElementException;
021    
022    import org.apache.commons.functor.BinaryFunction;
023    import org.apache.commons.functor.UnaryPredicate;
024    import org.apache.commons.functor.UnaryProcedure;
025    import org.apache.commons.functor.generator.Generator;
026    
027    /**
028     * Return the first Object in a {@link Generator} matching a {@link UnaryPredicate}.
029     *
030     * @param <E> the arguments type.
031     * @version $Revision: 1160622 $ $Date: 2011-08-23 13:03:37 +0200 (Tue, 23 Aug 2011) $
032     */
033    public final class FindWithinGenerator<E>
034        implements BinaryFunction<Generator<? extends E>, UnaryPredicate<? super E>, E>, Serializable {
035    
036        /**
037         * Basic instance.
038         */
039        public static final FindWithinGenerator<Object> INSTANCE = new FindWithinGenerator<Object>();
040    
041        /**
042         * serialVersionUID declaration.
043         */
044        private static final long serialVersionUID = -2824239991638326134L;
045    
046        /**
047         * Helper procedure.
048         *
049         * @param <T> the argument type.
050         */
051        private static class FindProcedure<T> implements UnaryProcedure<T> {
052            /**
053             * The object found, if any.
054             */
055            private T found;
056            /**
057             * Flag to mark an object has been found.
058             */
059            private boolean wasFound;
060            /**
061             * The adapted predicate.
062             */
063            private UnaryPredicate<? super T> pred;
064    
065            /**
066             * Create a new FindProcedure.
067             * @param pred the adapted predicate.
068             */
069            public FindProcedure(UnaryPredicate<? super T> pred) {
070                this.pred = pred;
071            }
072    
073            /**
074             * {@inheritDoc}
075             */
076            public void run(T obj) {
077                if (!wasFound && pred.test(obj)) {
078                    wasFound = true;
079                    found = obj;
080                }
081            }
082        }
083    
084        /**
085         * Flag to mark the {@link FindWithinGenerator#evaluate(Generator, UnaryPredicate)} method must return a user
086         * defined object when the adapted procedure does not find any object.
087         */
088        private final boolean useIfNone;
089        /**
090         * Object to be returned in the case the adapted procedure does not find any object.
091         */
092        private final E ifNone;
093    
094        /**
095         * Create a new FindWithinGenerator.
096         */
097        public FindWithinGenerator() {
098            super();
099            ifNone = null;
100            useIfNone = false;
101        }
102    
103        /**
104         * Create a new FindWithinGenerator.
105         * @param ifNone object to return if the Generator contains no matches.
106         */
107        public FindWithinGenerator(E ifNone) {
108            super();
109            this.ifNone = ifNone;
110            useIfNone = true;
111        }
112    
113        /**
114         * {@inheritDoc}
115         * @param left Generator
116         * @param right UnaryPredicate
117         */
118        public E evaluate(Generator<? extends E> left, UnaryPredicate<? super E> right) {
119            FindProcedure<E> findProcedure = new FindProcedure<E>(right);
120            left.run(findProcedure);
121            if (!findProcedure.wasFound) {
122                if (useIfNone) {
123                    return ifNone;
124                }
125                throw new NoSuchElementException("No element matching " + right + " was found.");
126            }
127            return findProcedure.found;
128        }
129    
130        /**
131         * {@inheritDoc}
132         */
133        public boolean equals(Object obj) {
134            if (obj == this) {
135                return true;
136            }
137            if (!(obj instanceof FindWithinGenerator<?>)) {
138                return false;
139            }
140            FindWithinGenerator<?> other = (FindWithinGenerator<?>) obj;
141            return other.useIfNone == useIfNone && !useIfNone
142                    || (other.ifNone == this.ifNone || other.ifNone != null && other.ifNone.equals(this.ifNone));
143        }
144    
145        /**
146         * {@inheritDoc}
147         */
148        public int hashCode() {
149            if (!this.useIfNone) {
150                return System.identityHashCode(INSTANCE);
151            }
152            int result = "FindWithinGenerator".hashCode();
153            result ^= this.ifNone == null ? 0 : this.ifNone.hashCode();
154            return result;
155        }
156    
157        /**
158         * Get a static {@link FindWithinGenerator} instance.
159         * @return {@link FindWithinGenerator}
160         */
161        public static FindWithinGenerator<Object> instance() {
162            return INSTANCE;
163        }
164    }