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