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 */
017package org.apache.commons.functor.core.algorithm;
018
019import java.io.Serializable;
020
021import org.apache.commons.functor.BinaryFunction;
022import org.apache.commons.functor.UnaryPredicate;
023import org.apache.commons.functor.UnaryProcedure;
024import org.apache.commons.functor.generator.Generator;
025
026/**
027 * Return the index of the first Object in a {@link Generator} matching a {@link UnaryPredicate}, or -1 if not found.
028 *
029 * @param <T> the procedure argument types
030 * @version $Revision: 1344796 $ $Date: 2012-05-31 12:12:39 -0400 (Thu, 31 May 2012) $
031 */
032public final class IndexOfInGenerator<T>
033    implements BinaryFunction<Generator<? extends T>, UnaryPredicate<? super T>, Number>, Serializable {
034    /**
035     * serialVersionUID declaration.
036     */
037    private static final long serialVersionUID = -11365986575536471L;
038    /**
039     * A static {@code IndexOfInGenerator} instance reference.
040     */
041    private static final IndexOfInGenerator<Object> INSTANCE = new IndexOfInGenerator<Object>();
042
043    /**
044     * Helper procedure.
045     *
046     * @param <T> the procedure argument type
047     */
048    private static class IndexProcedure<T> implements UnaryProcedure<T> {
049        /**
050         * The wrapped generator.
051         */
052        private final Generator<? extends T> generator;
053        /**
054         * The wrapped predicate.
055         */
056        private final UnaryPredicate<? super T> pred;
057        /**
058         * The number of iterations needed before the wrapped predicate found the target,
059         * {@code -1} means the target was not found.
060         */
061        private long index = -1L;
062        /**
063         * A local accumulator to increment the number of attempts.
064         */
065        private long current = 0L;
066
067        /**
068         * Create a new IndexProcedure.
069         *
070         * @param generator The wrapped generator
071         * @param pred The wrapped predicate
072         */
073        IndexProcedure(Generator<? extends T> generator, UnaryPredicate<? super T> pred) {
074            this.generator = generator;
075            this.pred = pred;
076        }
077
078        /**
079         * {@inheritDoc}
080         */
081        public void run(T obj) {
082            if (index < 0 && pred.test(obj)) {
083                index = current;
084                generator.stop();
085            }
086            current++;
087        }
088    }
089
090    /**
091     * {@inheritDoc}
092     * @param left Generator
093     * @param right UnaryPredicate
094     */
095    public Number evaluate(Generator<? extends T> left, UnaryPredicate<? super T> right) {
096        IndexProcedure<T> findProcedure = new IndexProcedure<T>(left, right);
097        left.run(findProcedure);
098        return Long.valueOf(findProcedure.index);
099    }
100
101    /**
102     * {@inheritDoc}
103     */
104    @Override
105    public boolean equals(Object obj) {
106        return obj == this || obj != null && obj.getClass().equals(getClass());
107    }
108
109    /**
110     * {@inheritDoc}
111     */
112    @Override
113    public int hashCode() {
114        return System.identityHashCode(INSTANCE);
115    }
116
117    /**
118     * {@inheritDoc}
119     */
120    @Override
121    public String toString() {
122        return "IndexOfInGenerator";
123    }
124
125    /**
126     * Get a static {@link IndexOfInGenerator} instance.
127     * @return {@link IndexOfInGenerator}
128     */
129    public static IndexOfInGenerator<Object> instance() {
130        return INSTANCE;
131    }
132}