You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ki...@apache.org on 2013/09/12 06:29:48 UTC

svn commit: r1522355 [1/5] - in /commons/proper/functor/trunk: core/src/main/java/org/apache/commons/functor/adapter/ core/src/main/java/org/apache/commons/functor/core/algorithm/ core/src/main/java/org/apache/commons/functor/generator/ core/src/main/j...

Author: kinow
Date: Thu Sep 12 04:29:46 2013
New Revision: 1522355

URL: http://svn.apache.org/r1522355
Log:
[FUNCTOR-14] Merge branch generators-FUNCTOR-14. Adding the loop and range packages, and simplifying the BaseGenerator type.

Added:
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/GenerateUntil.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/GenerateWhile.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/IteratorToGeneratorAdapter.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/LoopGenerator.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/TransformedGenerator.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/UntilGenerate.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/WhileGenerate.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/package-info.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/BoundType.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/CharacterRange.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/DoubleRange.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/Endpoint.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/FloatRange.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/IntegerRange.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/LongRange.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/NumericRange.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/Range.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/Ranges.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/package-info.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/loop/
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/loop/TestGenerateUntil.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/loop/TestGenerateWhile.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/loop/TestIteratorToGeneratorAdapter.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/loop/TestLoopGenerator.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/loop/TestTransformedGenerator.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/loop/TestUntilGenerate.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/loop/TestWhileGenerate.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/range/
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/range/TestCharacterRange.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/range/TestDoubleRange.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/range/TestEndpoint.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/range/TestFloatRange.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/range/TestIntegerRange.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/range/TestLongRange.java
Removed:
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/GenerateUntil.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/GenerateWhile.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/IteratorToGeneratorAdapter.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/TransformedGenerator.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/UntilGenerate.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/WhileGenerate.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/util/IntegerRange.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/util/LongRange.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/TestGenerateUntil.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/TestGenerateWhile.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/TestIteratorToGeneratorAdapter.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/TestTransformedGenerator.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/TestUntilGenerate.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/TestWhileGenerate.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/util/TestIntegerRange.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/util/TestLongRange.java
Modified:
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/adapter/FullyBoundNullaryPredicate.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/adapter/FullyBoundNullaryProcedure.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/core/algorithm/IndexOfInGenerator.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/BaseGenerator.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/FilteredGenerator.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/Generator.java
    commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/util/EachElement.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/TestAlgorithms.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/core/algorithm/TestFindWithinGenerator.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/core/algorithm/TestFoldLeft.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/core/algorithm/TestFoldRight.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/core/algorithm/TestGeneratorContains.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/core/algorithm/TestIndexOfInGenerator.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/example/QuicksortExample.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/example/kata/two/TestBinaryChop.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/example/lines/Lines.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/example/lines/TestLines.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/example/map/FixedSizeMap.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/TestBaseGenerator.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/TestFilteredGenerator.java
    commons/proper/functor/trunk/core/src/test/java/org/apache/commons/functor/generator/util/TestEachElement.java
    commons/proper/functor/trunk/src/changes/changes.xml
    commons/proper/functor/trunk/src/site/xdoc/examples.xml

Modified: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/adapter/FullyBoundNullaryPredicate.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/adapter/FullyBoundNullaryPredicate.java?rev=1522355&r1=1522354&r2=1522355&view=diff
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/adapter/FullyBoundNullaryPredicate.java (original)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/adapter/FullyBoundNullaryPredicate.java Thu Sep 12 04:29:46 2013
@@ -24,7 +24,7 @@ import org.apache.commons.lang3.Validate
 
 /**
  * Adapts a
- * {@link BinaryNullaryPredicate BinaryNullaryPredicate}
+ * {@link BinaryPredicate BinaryPredicate}
  * to the
  * {@link org.apache.commons.functor.NullaryPredicate NullaryPredicate} interface
  * using a constant left-side argument.

Modified: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/adapter/FullyBoundNullaryProcedure.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/adapter/FullyBoundNullaryProcedure.java?rev=1522355&r1=1522354&r2=1522355&view=diff
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/adapter/FullyBoundNullaryProcedure.java (original)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/adapter/FullyBoundNullaryProcedure.java Thu Sep 12 04:29:46 2013
@@ -24,7 +24,7 @@ import org.apache.commons.lang3.Validate
 
 /**
  * Adapts a
- * {@link BinaryNullaryProcedure BinaryNullaryProcedure}
+ * {@link BinaryProcedure BinaryProcedure}
  * to the
  * {@link NullaryProcedure NullaryProcedure} interface
  * using a constant left-side argument.
@@ -43,7 +43,7 @@ public final class FullyBoundNullaryProc
      * serialVersionUID declaration.
      */
     private static final long serialVersionUID = -904891610081737737L;
-    /** The {@link BinaryNullaryProcedure BinaryNullaryProcedure} I'm wrapping. */
+    /** The {@link BinaryProcedure BinaryProcedure} I'm wrapping. */
     private final BinaryProcedure<Object, Object> procedure;
     /** The left parameter to pass to {@code procedure}. */
     private final Object left;

Modified: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/core/algorithm/IndexOfInGenerator.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/core/algorithm/IndexOfInGenerator.java?rev=1522355&r1=1522354&r2=1522355&view=diff
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/core/algorithm/IndexOfInGenerator.java (original)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/core/algorithm/IndexOfInGenerator.java Thu Sep 12 04:29:46 2013
@@ -21,20 +21,21 @@ import java.io.Serializable;
 import org.apache.commons.functor.BinaryFunction;
 import org.apache.commons.functor.Predicate;
 import org.apache.commons.functor.Procedure;
-import org.apache.commons.functor.generator.Generator;
+import org.apache.commons.functor.generator.loop.LoopGenerator;
 
 /**
- * Return the index of the first Object in a {@link Generator} matching a {@link Predicate}, or -1 if not found.
+ * Return the index of the first Object in a {@link LoopGenerator} matching a
+ * {@link Predicate}, or -1 if not found.
  *
  * @param <T> the procedure argument types
  * @version $Revision$ $Date$
  */
 public final class IndexOfInGenerator<T>
-    implements BinaryFunction<Generator<? extends T>, Predicate<? super T>, Number>, Serializable {
+    implements BinaryFunction<LoopGenerator<? extends T>, Predicate<? super T>, Number>, Serializable {
     /**
      * serialVersionUID declaration.
      */
-    private static final long serialVersionUID = -11365986575536471L;
+    private static final long serialVersionUID = -2672603607256310480L;
     /**
      * A static {@code IndexOfInGenerator} instance reference.
      */
@@ -49,7 +50,7 @@ public final class IndexOfInGenerator<T>
         /**
          * The wrapped generator.
          */
-        private final Generator<? extends T> generator;
+        private final LoopGenerator<? extends T> generator;
         /**
          * The wrapped predicate.
          */
@@ -70,7 +71,7 @@ public final class IndexOfInGenerator<T>
          * @param generator The wrapped generator
          * @param pred The wrapped predicate
          */
-        IndexProcedure(Generator<? extends T> generator, Predicate<? super T> pred) {
+        IndexProcedure(LoopGenerator<? extends T> generator, Predicate<? super T> pred) {
             this.generator = generator;
             this.pred = pred;
         }
@@ -89,10 +90,10 @@ public final class IndexOfInGenerator<T>
 
     /**
      * {@inheritDoc}
-     * @param left Generator
+     * @param left LoopGenerator
      * @param right Predicate
      */
-    public Number evaluate(Generator<? extends T> left, Predicate<? super T> right) {
+    public Number evaluate(LoopGenerator<? extends T> left, Predicate<? super T> right) {
         IndexProcedure<T> findProcedure = new IndexProcedure<T>(left, right);
         left.run(findProcedure);
         return Long.valueOf(findProcedure.index);

Modified: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/BaseGenerator.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/BaseGenerator.java?rev=1522355&r1=1522354&r2=1522355&view=diff
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/BaseGenerator.java (original)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/BaseGenerator.java Thu Sep 12 04:29:46 2013
@@ -29,52 +29,9 @@ import org.apache.commons.functor.genera
  */
 public abstract class BaseGenerator<E> implements Generator<E> {
 
-    /** A generator can wrap another generator. */
-    private final Generator<?> wrappedGenerator;
-
-    /** Set to true when the generator is {@link #stop stopped}. */
-    private boolean stopped = false;
-
     /** Create a new generator. */
     public BaseGenerator() {
-        this(null);
-    }
-
-    /**
-     * A generator can wrap another generator. When wrapping generators you
-     * should use probably this constructor since doing so will cause the
-     * {@link #stop} method to stop the wrapped generator as well.
-     * @param generator Generator to wrap
-     */
-    public BaseGenerator(Generator<?> generator) {
-        this.wrappedGenerator = generator;
-    }
-
-    /**
-     * Get the generator that is being wrapped.
-     * @return Generator
-     */
-    protected Generator<?> getWrappedGenerator() {
-        return wrappedGenerator;
-    }
-
-    /**
-     * {@inheritDoc}
-     * Stop the generator. Will stop the wrapped generator if one was set.
-     */
-    public void stop() {
-        if (wrappedGenerator != null) {
-            wrappedGenerator.stop();
-        }
-        stopped = true;
-    }
-
-    /**
-     * {@inheritDoc}
-     * Check if the generator is stopped.
-     */
-    public boolean isStopped() {
-        return stopped;
+        super();
     }
 
     /**

Modified: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/FilteredGenerator.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/FilteredGenerator.java?rev=1522355&r1=1522354&r2=1522355&view=diff
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/FilteredGenerator.java (original)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/FilteredGenerator.java Thu Sep 12 04:29:46 2013
@@ -31,7 +31,12 @@ import org.apache.commons.lang3.Validate
 public class FilteredGenerator<E> extends BaseGenerator<E> {
 
     /**
-     * The wrapped generator.
+     * A generator can wrap another generator.
+     * */
+    private Generator<? extends E> wrappedGenerator;
+
+    /**
+     * The predicate used to filter.
      */
     private final Predicate<? super E> pred;
 
@@ -41,7 +46,7 @@ public class FilteredGenerator<E> extend
      * @param pred filtering Predicate
      */
     public FilteredGenerator(Generator<? extends E> wrapped, Predicate<? super E> pred) {
-        super(Validate.notNull(wrapped, "Generator argument was null"));
+        this.wrappedGenerator = Validate.notNull(wrapped, "Generator argument was null");
         this.pred = Validate.notNull(pred, "Predicate argument was null");
     }
 
@@ -53,12 +58,11 @@ public class FilteredGenerator<E> extend
     }
 
     /**
-     * {@inheritDoc}
+     * Get the generator that is being wrapped.
+     * @return Generator
      */
-    @SuppressWarnings("unchecked")
-    @Override
     protected Generator<? extends E> getWrappedGenerator() {
-        return (Generator<? extends E>) super.getWrappedGenerator();
+        return this.wrappedGenerator;
     }
 
     /**

Modified: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/Generator.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/Generator.java?rev=1522355&r1=1522354&r2=1522355&view=diff
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/Generator.java (original)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/Generator.java Thu Sep 12 04:29:46 2013
@@ -33,21 +33,10 @@ public interface Generator<E> {
     void run(Procedure<? super E> proc);
 
     /**
-     * Stop the generator. Will stop the wrapped generator if one was set.
-     */
-    void stop();
-
-    /**
-     * Check if the generator is stopped.
-     * @return true if stopped
-     */
-    boolean isStopped();
-
-    /**
      * Transforms this generator using the passed in
      * transformer. An example transformer might turn the contents of the
      * generator into a {@link Collection} of elements.
-     * @param <Z> the returned value type of the input {@link Function}.
+     * @param <Z> the returned value type of the input {@link Function}
      * @param transformer Function to apply to this
      * @return transformation result
      */
@@ -55,7 +44,7 @@ public interface Generator<E> {
 
     /**
      * Same as to(new CollectionTransformer(collection)).
-     * @param <C> the collection type
+     * @param <C> the returned collection type
      * @param collection Collection to which my elements should be added
      * @return <code>collection</code>
      */

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/GenerateUntil.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/GenerateUntil.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/GenerateUntil.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/GenerateUntil.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.generator.loop;
+
+import org.apache.commons.functor.Predicate;
+import org.apache.commons.functor.Procedure;
+import org.apache.commons.functor.generator.Generator;
+import org.apache.commons.lang3.Validate;
+
+/**
+ * Wrap another {@link Generator} such that {@link #run(Procedure)} terminates once
+ * a condition has been satisfied (test after).
+ *
+ * @param <E> the type of elements held in this generator.
+ * @version $Revision: 1508677 $ $Date: 2013-07-30 19:48:02 -0300 (Tue, 30 Jul 2013) $
+ */
+public class GenerateUntil<E> extends LoopGenerator<E> {
+
+    /**
+     * The condition has to verified in order to execute the generation.
+     */
+    private final Predicate<? super E> test;
+
+    /**
+     * Create a new GenerateUntil.
+     * @param wrapped {@link Generator}
+     * @param test {@link Predicate}
+     */
+    public GenerateUntil(Generator<? extends E> wrapped, Predicate<? super E> test) {
+        super(Validate.notNull(wrapped, "Generator argument was null"));
+        this.test = Validate.notNull(test, "Predicate argument was null");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void run(final Procedure<? super E> proc) {
+        getWrappedGenerator().run(new Procedure<E>() {
+            public void run(E obj) {
+                proc.run(obj);
+                if (test.test(obj)) {
+                    GenerateUntil.this.stop();
+                }
+            }
+        });
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof GenerateUntil<?>)) {
+            return false;
+        }
+        GenerateUntil<?> other = (GenerateUntil<?>) obj;
+        return other.getWrappedGenerator().equals(getWrappedGenerator()) && other.test.equals(test);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int result = "GenerateUntil".hashCode();
+        result <<= 2;
+        Generator<?> gen = getWrappedGenerator();
+        result ^= gen.hashCode();
+        result <<= 2;
+        result ^= test.hashCode();
+        return result;
+    }
+}

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/GenerateWhile.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/GenerateWhile.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/GenerateWhile.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/GenerateWhile.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.generator.loop;
+
+import org.apache.commons.functor.Predicate;
+import org.apache.commons.functor.Procedure;
+import org.apache.commons.functor.generator.Generator;
+import org.apache.commons.lang3.Validate;
+
+/**
+ * Wrap another {@link Generator} such that {@link #run(Procedure)} continues
+ * as long as a condition is true (test after).
+ *
+ * @param <E> the type of elements held in this generator.
+ * @version $Revision: 1508677 $ $Date: 2013-07-30 19:48:02 -0300 (Tue, 30 Jul 2013) $
+ */
+public class GenerateWhile<E> extends LoopGenerator<E> {
+
+    /**
+     * The condition has to verified in order to execute the generation.
+     */
+    private final Predicate<? super E> test;
+
+    /**
+     * Create a new GenerateWhile.
+     * @param wrapped {@link Generator}
+     * @param test {@link Predicate}
+     */
+    public GenerateWhile(Generator<? extends E> wrapped, Predicate<? super E> test) {
+        super(Validate.notNull(wrapped, "Generator argument was null"));
+        this.test = Validate.notNull(test, "Predicate argument was null");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void run(final Procedure<? super E> proc) {
+        getWrappedGenerator().run(new Procedure<E>() {
+            public void run(E obj) {
+                proc.run(obj);
+                if (!test.test(obj)) {
+                    GenerateWhile.this.stop();
+                }
+            }
+        });
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof GenerateWhile<?>)) {
+            return false;
+        }
+        GenerateWhile<?> other = (GenerateWhile<?>) obj;
+        return other.getWrappedGenerator().equals(getWrappedGenerator()) && other.test.equals(test);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int result = "GenerateWhile".hashCode();
+        result <<= 2;
+        Generator<?> gen = getWrappedGenerator();
+        result ^= gen.hashCode();
+        result <<= 2;
+        result ^= test.hashCode();
+        return result;
+    }
+}

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/IteratorToGeneratorAdapter.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/IteratorToGeneratorAdapter.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/IteratorToGeneratorAdapter.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/IteratorToGeneratorAdapter.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,109 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.functor.generator.loop;
+
+import java.util.Iterator;
+
+import org.apache.commons.functor.Procedure;
+import org.apache.commons.lang3.Validate;
+
+/**
+ * Adapts an {@link Iterator} to the {@link LoopGenerator} interface.
+ *
+ * @param <E> the type of elements held in this generator.
+ * @since 1.0
+ * @version $Revision: 1508677 $ $Date: 2013-07-30 19:48:02 -0300 (Tue, 30 Jul 2013) $
+ */
+public final class IteratorToGeneratorAdapter<E> extends LoopGenerator<E> {
+    // instance variables
+    //-----------------------------------------------------
+
+    /**
+     * The adapted iterator.
+     */
+    private final Iterator<? extends E> iter;
+
+    // constructors
+    //-----------------------------------------------------
+    /**
+     * Create a new IteratorToGeneratorAdapter.
+     * @param iter Iterator to adapt
+     */
+    public IteratorToGeneratorAdapter(Iterator<? extends E> iter) {
+        this.iter = Validate.notNull(iter, "Iterator argument was null");
+    }
+
+    // instance methods
+    //-----------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public void run(Procedure<? super E> proc) {
+        while (iter.hasNext()) {
+            proc.run(iter.next());
+            if (isStopped()) {
+                break;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof IteratorToGeneratorAdapter<?>)) {
+            return false;
+        }
+        IteratorToGeneratorAdapter<?> that = (IteratorToGeneratorAdapter<?>) obj;
+        return this.iter.equals(that.iter);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int hash = "IteratorToGeneratorAdapater".hashCode();
+        hash <<= 2;
+        hash ^= iter.hashCode();
+        return hash;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        return "IteratorToGeneratorAdapter<" + iter + ">";
+    }
+
+    // static methods
+    //-----------------------------------------------------
+    /**
+     * Adapt an Iterator to the Generator interface.
+     *
+     * @param <E> the type of elements held in this generator.
+     * @param iter to adapt
+     * @return IteratorToGeneratorAdapter
+     */
+    public static <E> IteratorToGeneratorAdapter<E> adapt(Iterator<? extends E> iter) {
+        return null == iter ? null : new IteratorToGeneratorAdapter<E>(iter);
+    }
+
+}

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/LoopGenerator.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/LoopGenerator.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/LoopGenerator.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/LoopGenerator.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,78 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.functor.generator.loop;
+
+import org.apache.commons.functor.generator.BaseGenerator;
+import org.apache.commons.functor.generator.Generator;
+
+/**
+ * Base class for generators that control execution flow, and may need to
+ * stop the generation.
+ *
+ * @param <E> the type of elements held in this generator.
+ * @since 1.0
+ * @version $Revision$ $Date$
+ */
+public abstract class LoopGenerator<E> extends BaseGenerator<E> {
+
+    /** A generator can wrap another generator. */
+    private final Generator<? extends E> wrappedGenerator;
+
+    /** Set to true when the generator is {@link #stop stopped}. */
+    private boolean stopped = false;
+
+    /** Create a new generator. */
+    public LoopGenerator() {
+        this(null);
+    }
+
+    /**
+     * A generator can wrap another generator. When wrapping generators you
+     * should use probably this constructor since doing so will cause the
+     * {@link #stop} method to stop the wrapped generator as well.
+     * @param generator Generator to wrap
+     */
+    public LoopGenerator(Generator<? extends E> generator) {
+        this.wrappedGenerator = generator;
+    }
+
+    /**
+     * Get the generator that is being wrapped.
+     * @return Generator
+     */
+    protected Generator<? extends E> getWrappedGenerator() {
+        return wrappedGenerator;
+    }
+
+    /**
+     * Stop the generator. Will stop the wrapped generator if one was set.
+     */
+    public void stop() {
+        if (wrappedGenerator != null && wrappedGenerator instanceof LoopGenerator<?>) {
+            ((LoopGenerator<?>) wrappedGenerator).stop();
+        }
+        stopped = true;
+    }
+
+    /**
+     * Check if the generator is stopped.
+     * @return <code>true</code> if the generator is stopped, <code>false</code>
+     * otherwise
+     */
+    public boolean isStopped() {
+        return stopped;
+    }
+
+}

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/TransformedGenerator.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/TransformedGenerator.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/TransformedGenerator.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/TransformedGenerator.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.generator.loop;
+
+import org.apache.commons.functor.Function;
+import org.apache.commons.functor.Procedure;
+import org.apache.commons.functor.generator.Generator;
+import org.apache.commons.lang3.Validate;
+
+/**
+ * Generator that transforms the elements of another Generator.
+ *
+ * @param <I> the type of elements held in the wrapped generator.
+ * @param <E> the type of elements held in this generator.
+ * @version $Revision: 1508677 $ $Date: 2013-07-30 19:48:02 -0300 (Tue, 30 Jul 2013) $
+ */
+public class TransformedGenerator<I, E> extends LoopGenerator<E> {
+
+    /**
+     * The Function to apply to each element.
+     */
+    private final Function<? super I, ? extends E> func;
+
+    /**
+     * Create a new TransformedGenerator.
+     * @param wrapped Generator to transform
+     * @param func Function to apply to each element
+     */
+    // Even though we are passing a Generator<? extends I> to super, and using
+    // it in TransformedGenerator#run, what gets actually passed to the Procedure
+    // is a <? extends E>, returned by func.
+    @SuppressWarnings("unchecked")
+    public TransformedGenerator(Generator<? extends I> wrapped, Function<? super I, ? extends E> func) {
+        super((Generator<? extends E>) Validate.notNull(wrapped, "Generator argument was null"));
+        this.func = Validate.notNull(func, "Function argument was null");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // See comment above in the public constructor
+    @SuppressWarnings("unchecked")
+    public void run(final Procedure<? super E> proc) {
+        ((Generator<? extends I>) getWrappedGenerator()).run(new Procedure<I>() {
+            public void run(I obj) {
+                proc.run(func.evaluate(obj));
+            }
+        });
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof TransformedGenerator<?, ?>)) {
+            return false;
+        }
+        TransformedGenerator<?, ?> other = (TransformedGenerator<?, ?>) obj;
+        return other.getWrappedGenerator().equals(getWrappedGenerator()) && other.func == func;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int result = "TransformedGenerator".hashCode();
+        result <<= 2;
+        Generator<?> gen = getWrappedGenerator();
+        result ^= gen.hashCode();
+        result <<= 2;
+        result ^= func.hashCode();
+        return result;
+    }
+}

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/UntilGenerate.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/UntilGenerate.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/UntilGenerate.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/UntilGenerate.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.generator.loop;
+
+import org.apache.commons.functor.Predicate;
+import org.apache.commons.functor.Procedure;
+import org.apache.commons.functor.generator.Generator;
+import org.apache.commons.lang3.Validate;
+
+/**
+ * Wrap another {@link Generator} such that {@link #run(Procedure)} terminates once
+ * a condition has been satisfied.
+ *
+ * @param <E> the type of elements held in this generator.
+ * @version $Revision: 1508677 $ $Date: 2013-07-30 19:48:02 -0300 (Tue, 30 Jul 2013) $
+ */
+public class UntilGenerate<E> extends LoopGenerator<E> {
+
+    /**
+     * The condition has to verified in order to execute the generation.
+     */
+    private final Predicate<? super E> test;
+
+    /**
+     * Create a new UntilGenerate.
+     * @param wrapped {@link Generator}
+     * @param test {@link Predicate}
+     */
+    public UntilGenerate(Predicate<? super E> test, Generator<? extends E> wrapped) {
+        super(Validate.notNull(wrapped, "Generator argument was null"));
+        this.test = Validate.notNull(test, "Predicate argument was null");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void run(final Procedure<? super E> proc) {
+        getWrappedGenerator().run(new Procedure<E>() {
+            public void run(E obj) {
+                if (test.test(obj)) {
+                    UntilGenerate.this.stop();
+                } else {
+                    proc.run(obj);
+                }
+            }
+        });
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof UntilGenerate<?>)) {
+            return false;
+        }
+        UntilGenerate<?> other = (UntilGenerate<?>) obj;
+        return other.getWrappedGenerator().equals(getWrappedGenerator()) && other.test.equals(test);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int result = "UntilGenerate".hashCode();
+        result <<= 2;
+        Generator<?> gen = getWrappedGenerator();
+        result ^= gen.hashCode();
+        result <<= 2;
+        result ^= test.hashCode();
+        return result;
+    }
+}

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/WhileGenerate.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/WhileGenerate.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/WhileGenerate.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/WhileGenerate.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.generator.loop;
+
+import org.apache.commons.functor.Predicate;
+import org.apache.commons.functor.Procedure;
+import org.apache.commons.functor.generator.Generator;
+import org.apache.commons.lang3.Validate;
+
+/**
+ * Wrap another {@link Generator} such that {@link #run(Procedure)} continues
+ * as long as a condition is true (test before).
+ *
+ * @param <E> the type of elements held in this generator.
+ * @version $Revision: 1508677 $ $Date: 2013-07-30 19:48:02 -0300 (Tue, 30 Jul 2013) $
+ */
+public class WhileGenerate<E> extends LoopGenerator<E> {
+
+    /**
+     * The condition has to verified in order to execute the generation.
+     */
+    private final Predicate<? super E> test;
+
+    /**
+     * Create a new WhileGenerate.
+     * @param test {@link Predicate}
+     * @param wrapped {@link Generator}
+     */
+    public WhileGenerate(Predicate<? super E> test, Generator<? extends E> wrapped) {
+        super(Validate.notNull(wrapped, "Generator argument was null"));
+        this.test = Validate.notNull(test, "Predicate argument was null");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void run(final Procedure<? super E> proc) {
+        getWrappedGenerator().run(new Procedure<E>() {
+            public void run(E obj) {
+                if (!test.test(obj)) {
+                    WhileGenerate.this.stop();
+                } else {
+                    proc.run(obj);
+                }
+            }
+        });
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof WhileGenerate<?>)) {
+            return false;
+        }
+        WhileGenerate<?> other = (WhileGenerate<?>) obj;
+        return other.getWrappedGenerator().equals(getWrappedGenerator()) && other.test.equals(test);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int result = "WhileGenerate".hashCode();
+        result <<= 2;
+        Generator<?> gen = getWrappedGenerator();
+        result ^= gen.hashCode();
+        result <<= 2;
+        result ^= test.hashCode();
+        return result;
+    }
+}

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/package-info.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/package-info.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/package-info.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/loop/package-info.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,19 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * <p>
+ * Contains code related to Generators that control execution flow.
+ * </p>
+ */
+package org.apache.commons.functor.generator.loop;

Modified: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/util/EachElement.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/util/EachElement.java?rev=1522355&r1=1522354&r2=1522355&view=diff
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/util/EachElement.java (original)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/generator/util/EachElement.java Thu Sep 12 04:29:46 2013
@@ -19,7 +19,7 @@ import java.util.Iterator;
 import java.util.Map;
 
 import org.apache.commons.functor.generator.Generator;
-import org.apache.commons.functor.generator.IteratorToGeneratorAdapter;
+import org.apache.commons.functor.generator.loop.IteratorToGeneratorAdapter;
 
 /**
  * Generator factory for each element of a "collection".

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/BoundType.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/BoundType.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/BoundType.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/BoundType.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.range;
+
+/**
+ * Determine the bound type of a range.
+ *
+ * @see org.apache.commons.functor.range.Range
+ * @see org.apache.commons.functor.range.Endpoint
+ * @since 1.0
+ * @version $Revision$ $Date$
+ */
+public enum BoundType {
+    // values
+    // ---------------------------------------------------------------
+    /**
+     * Represents an <b>open</b> bound, which value <b>is not</b> included in
+     * the range.
+     */
+    OPEN,
+    /**
+     * Represents a <b>closed</b> bound, which value <b>is included</b> in the
+     * range.
+     */
+    CLOSED;
+
+}

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/CharacterRange.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/CharacterRange.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/CharacterRange.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/CharacterRange.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,349 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.range;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.commons.functor.BinaryFunction;
+import org.apache.commons.lang3.Validate;
+
+/**
+ * A generator for a range of characters.
+ *
+ * @since 1.0
+ * @version $Revision$ $Date$
+ */
+public final class CharacterRange implements Range<Character, Integer> {
+
+    // attributes
+    // ---------------------------------------------------------------
+    /**
+     * Default left bound type.
+     */
+    public static final BoundType DEFAULT_LEFT_BOUND_TYPE = BoundType.CLOSED;
+
+    /**
+     * Default right bound type.
+     */
+    public static final BoundType DEFAULT_RIGHT_BOUND_TYPE = BoundType.CLOSED;
+
+    /**
+     * Left limit.
+     */
+    private final Endpoint<Character> leftEndpoint;
+
+    /**
+     * Right limit.
+     */
+    private final Endpoint<Character> rightEndpoint;
+
+    /**
+     * Increment step.
+     */
+    private final int step;
+
+    /**
+     * Current value.
+     */
+    private char currentValue;
+
+    /**
+     * Calculate default step.
+     */
+    public static final BinaryFunction<Character, Character, Integer> DEFAULT_STEP
+        = new BinaryFunction<Character, Character, Integer>() {
+
+        public Integer evaluate(Character left, Character right) {
+            return left > right ? -1 : 1;
+        }
+    };
+
+    // constructors
+    // ---------------------------------------------------------------
+    /**
+     * Create a new CharacterRange.
+     *
+     * @param from start
+     * @param to end
+     */
+    public CharacterRange(char from, char to) {
+        this(from, to, DEFAULT_STEP.evaluate(from, to).intValue());
+    }
+
+    /**
+     * Create a new CharacterRange.
+     *
+     * @param from start
+     * @param to end
+     * @param step increment
+     */
+    public CharacterRange(char from, char to, int step) {
+        this(from, BoundType.CLOSED, to, BoundType.CLOSED, step);
+    }
+
+    /**
+     * Create a new CharacterRange.
+     *
+     * @param from start
+     * @param to end
+     */
+    public CharacterRange(Endpoint<Character> from, Endpoint<Character> to) {
+        this(from.getValue(), from.getBoundType(), to.getValue(), to.getBoundType(),
+                DEFAULT_STEP.evaluate(from.getValue(), to.getValue()));
+    }
+
+    /**
+     * Create a new CharacterRange.
+     *
+     * @param from start
+     * @param to end
+     * @param step increment
+     */
+    public CharacterRange(Endpoint<Character> from, Endpoint<Character> to, int step) {
+        this(from.getValue(), from.getBoundType(), to.getValue(), to.getBoundType(), step);
+    }
+
+    /**
+     * Create a new CharacterRange.
+     *
+     * @param from start
+     * @param leftBoundType type of left bound
+     * @param to end
+     * @param rightBoundType type of right bound
+     */
+    public CharacterRange(char from, BoundType leftBoundType, char to,
+                        BoundType rightBoundType) {
+        this(from, leftBoundType, to, rightBoundType, DEFAULT_STEP.evaluate(from, to));
+    }
+
+    /**
+     * Create a new CharacterRange.
+     *
+     * @param from start
+     * @param leftBoundType type of left bound
+     * @param to end
+     * @param rightBoundType type of right bound
+     * @param step increment
+     */
+    public CharacterRange(char from, BoundType leftBoundType, char to,
+                          BoundType rightBoundType, int step) {
+        this.leftEndpoint = Validate
+            .notNull(new Endpoint<Character>(from, leftBoundType),
+                     "Left Endpoint argument must not be null");
+        this.rightEndpoint = Validate
+            .notNull(new Endpoint<Character>(to, rightBoundType),
+                     "Right Endpoint argument must not be null");
+        this.step = step;
+        if (from != to && Integer.signum(step) != Integer.signum(to - from)) {
+            throw new IllegalArgumentException("Will never reach " + to
+                                               + " from " + from
+                                               + " using step " + step);
+        }
+        if (this.leftEndpoint.getBoundType() == BoundType.CLOSED) {
+            this.currentValue = this.leftEndpoint.getValue();
+        } else {
+            this.currentValue = (char) (this.leftEndpoint.getValue() + this.step);
+        }
+    }
+    // range methods
+    // ---------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public Endpoint<Character> getLeftEndpoint() {
+        return this.leftEndpoint;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Endpoint<Character> getRightEndpoint() {
+        return this.rightEndpoint;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Integer getStep() {
+        return this.step;
+    }
+
+    // iterable, iterator methods
+    // ---------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext() {
+        final int to = this.rightEndpoint.getValue();
+        if (step < 0) {
+            if (this.rightEndpoint.getBoundType() == BoundType.CLOSED) {
+                return this.currentValue >= to;
+            } else {
+                return this.currentValue > to;
+            }
+        } else {
+            if (this.rightEndpoint.getBoundType() == BoundType.CLOSED) {
+                return this.currentValue <= to;
+            } else {
+                return this.currentValue < to;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Character next() {
+        final int step = this.getStep();
+        final char r = this.currentValue;
+        this.currentValue += step;
+        return r;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<Character> iterator() {
+        return this;
+    }
+
+    // object methods
+    // ---------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        return "CharacterRange<" + this.leftEndpoint.toLeftString() + ", "
+                + this.rightEndpoint.toRightString() + ", " + step + ">";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof CharacterRange)) {
+            return false;
+        }
+        CharacterRange that = (CharacterRange) obj;
+        return this.leftEndpoint.equals(that.leftEndpoint)
+                && this.rightEndpoint.equals(that.rightEndpoint)
+                && this.step == that.step;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int hash = "CharacterRange".hashCode();
+        hash <<= 2;
+        hash ^= this.leftEndpoint.getValue();
+        hash <<= 2;
+        hash ^= this.rightEndpoint.getValue();
+        hash <<= 2;
+        hash ^= this.step;
+        return hash;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEmpty() {
+        double leftValue = this.getLeftEndpoint().getValue().charValue();
+        double rightValue = this.getRightEndpoint().getValue().charValue();
+        boolean closedLeft = this.getLeftEndpoint().getBoundType() == BoundType.CLOSED;
+        boolean closedRight = this.getRightEndpoint().getBoundType() == BoundType.CLOSED;
+        if (!closedLeft && !closedRight
+                && this.getLeftEndpoint().equals(this.getRightEndpoint())) {
+            return Boolean.TRUE;
+        }
+        double step = this.getStep().intValue();
+        if (step > 0.0) {
+            double firstValue = closedLeft ? leftValue : leftValue + step;
+            return closedRight ? firstValue > rightValue
+                              : firstValue >= rightValue;
+        } else {
+            double firstValue = closedLeft ? leftValue : leftValue + step;
+            return closedRight ? firstValue < rightValue
+                              : firstValue <= rightValue;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains(Character obj) {
+        if (obj == null) {
+            return Boolean.FALSE;
+        }
+        char leftValue = this.getLeftEndpoint().getValue().charValue();
+        char rightValue = this.getRightEndpoint().getValue().charValue();
+        boolean includeLeft = this.getLeftEndpoint().getBoundType() == BoundType.CLOSED;
+        boolean includeRight = this.getRightEndpoint().getBoundType() == BoundType.CLOSED;
+        int step = this.getStep().intValue();
+        int value = (int) obj.charValue();
+
+        int firstValue = 0;
+        int lastValue = 0;
+
+        if (step < 0.0) {
+            firstValue = includeLeft ? leftValue : leftValue + step;
+            lastValue = includeRight ? rightValue : rightValue + 1;
+            if (value > firstValue || value < lastValue) {
+                return Boolean.FALSE;
+            }
+        } else {
+            firstValue = includeLeft ? leftValue : leftValue + step;
+            lastValue = includeRight ? rightValue : rightValue - 1;
+            if (value < firstValue || value > lastValue) {
+                return Boolean.FALSE;
+            }
+        }
+        return ((double) (value - firstValue) / step + 1) % 1.0 == 0.0;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean containsAll(Collection<Character> col) {
+        if (col == null || col.size() == 0) {
+            return Boolean.FALSE;
+        }
+        boolean r = Boolean.TRUE;
+        for (Character t : col) {
+            if (!this.contains(t)) {
+                r = Boolean.FALSE;
+                break;
+            }
+        }
+        return r;
+    }
+
+}

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/DoubleRange.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/DoubleRange.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/DoubleRange.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/DoubleRange.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.range;
+
+import java.util.Iterator;
+
+import org.apache.commons.functor.BinaryFunction;
+import org.apache.commons.lang3.Validate;
+
+/**
+ * A generator for a range of doubles.
+ *
+ * @since 1.0
+ * @version $Revision$ $Date$
+ */
+public class DoubleRange extends NumericRange<Double> {
+
+    // attributes
+    // ---------------------------------------------------------------
+    /**
+     * Left limit.
+     */
+    private final Endpoint<Double> leftEndpoint;
+
+    /**
+     * Right limit.
+     */
+    private final Endpoint<Double> rightEndpoint;
+
+    /**
+     * Increment step.
+     */
+    private final double step;
+
+    /**
+     * Current value.
+     */
+    private double currentValue;
+
+    /**
+     * Calculate default step.
+     */
+    public static final BinaryFunction<Double, Double, Double> DEFAULT_STEP =
+            new BinaryFunction<Double, Double, Double>() {
+
+        public Double evaluate(Double left, Double right) {
+            return left > right ? -1.0d : 1.0d;
+        }
+    };
+
+    // constructors
+    // ---------------------------------------------------------------
+    /**
+     * Create a new DoubleRange.
+     *
+     * @param from start
+     * @param to end
+     */
+    public DoubleRange(Number from, Number to) {
+        this(from.doubleValue(), to.doubleValue());
+    }
+
+    /**
+     * Create a new DoubleRange.
+     *
+     * @param from start
+     * @param to end
+     * @param step increment
+     */
+    public DoubleRange(Number from, Number to, Number step) {
+        this(from.doubleValue(), to.doubleValue(), step.doubleValue());
+    }
+
+    /**
+     * Create a new DoubleRange.
+     *
+     * @param from start
+     * @param to end
+     */
+    public DoubleRange(double from, double to) {
+        this(from, to, DEFAULT_STEP.evaluate(from, to).intValue());
+    }
+
+    /**
+     * Create a new DoubleRange.
+     *
+     * @param from start
+     * @param to end
+     * @param step increment
+     */
+    public DoubleRange(double from, double to, double step) {
+        this(from, DEFAULT_LEFT_BOUND_TYPE, to, DEFAULT_RIGHT_BOUND_TYPE, step);
+    }
+
+    /**
+     * Create a new DoubleRange.
+     *
+     * @param from start
+     * @param to end
+     */
+    public DoubleRange(Endpoint<Double> from, Endpoint<Double> to) {
+        this(from.getValue(), from.getBoundType(), to.getValue(), to.getBoundType(),
+                DEFAULT_STEP.evaluate(from.getValue(), to.getValue()));
+    }
+
+    /**
+     * Create a new DoubleRange.
+     *
+     * @param from start
+     * @param leftBoundType type of left bound
+     * @param to end
+     * @param rightBoundType type of right bound
+     */
+    public DoubleRange(double from, BoundType leftBoundType, double to,
+                        BoundType rightBoundType) {
+        this(from, leftBoundType, to, rightBoundType, DEFAULT_STEP.evaluate(from, to));
+    }
+
+    /**
+     * Create a new DoubleRange.
+     *
+     * @param from start
+     * @param to end
+     * @param step increment
+     */
+    public DoubleRange(Endpoint<Double> from, Endpoint<Double> to, double step) {
+        this(from.getValue(), from.getBoundType(), to.getValue(), to.getBoundType(), step);
+    }
+
+    /**
+     * Create a new DoubleRange.
+     *
+     * @param from start
+     * @param leftBoundType type of left bound
+     * @param to end
+     * @param rightBoundType type of right bound
+     * @param step increment
+     */
+    public DoubleRange(double from, BoundType leftBoundType, double to,
+                       BoundType rightBoundType, double step) {
+        this.leftEndpoint = Validate
+            .notNull(new Endpoint<Double>(from, leftBoundType),
+                     "Left Endpoint argument must not be null");
+        this.rightEndpoint = Validate
+            .notNull(new Endpoint<Double>(to, rightBoundType),
+                     "Right Endpoint argument must not be null");
+        this.step = step;
+        if (from != to && Math.signum(step) != Math.signum(to - from)) {
+            throw new IllegalArgumentException("Will never reach " + to
+                                               + " from " + from
+                                               + " using step " + step);
+        }
+        if (this.leftEndpoint.getBoundType() == BoundType.CLOSED) {
+            this.currentValue = this.leftEndpoint.getValue();
+        } else {
+            this.currentValue = this.leftEndpoint.getValue() + this.step;
+        }
+    }
+
+    // range methods
+    // ---------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public Endpoint<Double> getLeftEndpoint() {
+        return this.leftEndpoint;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Endpoint<Double> getRightEndpoint() {
+        return this.rightEndpoint;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Double getStep() {
+        return this.step;
+    }
+ // iterable, iterator methods
+    // ---------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext() {
+        final double to = this.rightEndpoint.getValue();
+        if (step < 0) {
+            if (this.rightEndpoint.getBoundType() == BoundType.CLOSED) {
+                return this.currentValue >= to;
+            } else {
+                return this.currentValue > to;
+            }
+        } else {
+            if (this.rightEndpoint.getBoundType() == BoundType.CLOSED) {
+                return this.currentValue <= to;
+            } else {
+                return this.currentValue < to;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Double next() {
+        final double step = this.getStep();
+        final double r = this.currentValue;
+        this.currentValue += step;
+        return r;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<Double> iterator() {
+        return this;
+    }
+
+    // object methods
+    // ---------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        return "DoubleRange<" + this.leftEndpoint.toLeftString() + ", "
+                + this.rightEndpoint.toRightString() + ", " + this.step + ">";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof DoubleRange)) {
+            return false;
+        }
+        DoubleRange that = (DoubleRange) obj;
+        return this.leftEndpoint.equals(that.leftEndpoint)
+                && this.rightEndpoint.equals(that.rightEndpoint)
+                && this.step == that.step;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int hash = "DoubleRange".hashCode();
+        hash <<= 2;
+        hash ^= this.leftEndpoint.getValue().hashCode();
+        hash <<= 2;
+        hash ^= this.rightEndpoint.getValue().hashCode();
+        hash <<= 2;
+        hash ^= Double.valueOf(this.step).hashCode();
+        return hash;
+    }
+
+}

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/Endpoint.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/Endpoint.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/Endpoint.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/Endpoint.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.range;
+
+/**
+ * Represent an endpoint of a range. This can be the left endpoint or the right
+ * endpoint. It is also called left limit or right limit, and can be open
+ * (exclusive, unbounded) or closed (inclusive, bounded).
+ *
+ * @param <T> type of the value held by this endpoint
+ * @since 1.0
+ * @version $Revision$ $Date$
+ */
+public class Endpoint<T extends Comparable<?>> {
+
+    /**
+     * The endpoint value.
+     */
+    private final T value;
+
+    /**
+     * The endpoint bound type.
+     */
+    private final BoundType boundType;
+
+    /**
+     * Create an endpoint.
+     *
+     * @param value value
+     * @param boundType bound type
+     */
+    public Endpoint(T value, BoundType boundType) {
+        this.value = value;
+        this.boundType = boundType;
+    }
+
+    /**
+     * @return Object
+     */
+    public T getValue() {
+        return value;
+    }
+
+    /**
+     * @return BoundType
+     */
+    public BoundType getBoundType() {
+        return boundType;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        String boundType = this.boundType == BoundType.OPEN ? "OPEN" : "CLOSED";
+        return "Endpoint<" + this.value + ", " + boundType + ">";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof Endpoint)) {
+            return false;
+        }
+        Endpoint<?> that = (Endpoint<?>) obj;
+        return this.boundType == that.boundType
+                && this.value.equals(that.value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int hash = "Endpoint".hashCode();
+        hash <<= 2;
+        hash ^= this.value.toString().hashCode();
+        hash <<= 2;
+        hash ^= Boolean.valueOf(this.boundType == BoundType.OPEN).hashCode();
+        return hash;
+    }
+
+    /**
+     * Print the left endpoint and bound type.
+     *
+     * @return String
+     */
+    public String toLeftString() {
+        return (this.boundType == BoundType.OPEN ? "(" : "[") + this.value;
+    }
+
+    /**
+     * Print the right endpoint and bound type.
+     *
+     * @return String
+     */
+    public String toRightString() {
+        return this.value + (this.boundType == BoundType.OPEN ? ")" : "]");
+    }
+
+}

Added: commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/FloatRange.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/FloatRange.java?rev=1522355&view=auto
==============================================================================
--- commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/FloatRange.java (added)
+++ commons/proper/functor/trunk/core/src/main/java/org/apache/commons/functor/range/FloatRange.java Thu Sep 12 04:29:46 2013
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.functor.range;
+
+import java.util.Iterator;
+
+import org.apache.commons.functor.BinaryFunction;
+import org.apache.commons.lang3.Validate;
+
+/**
+ * A generator for a range of float.
+ *
+ * @since 1.0
+ * @version $Revision$ $Date$
+ */
+public class FloatRange extends NumericRange<Float> {
+
+    // attributes
+    // ---------------------------------------------------------------
+    /**
+     * Left limit.
+     */
+    private final Endpoint<Float> leftEndpoint;
+
+    /**
+     * Right limit.
+     */
+    private final Endpoint<Float> rightEndpoint;
+
+    /**
+     * Increment step.
+     */
+    private final float step;
+
+    /**
+     * Current value.
+     */
+    private float currentValue;
+
+    /**
+     * Calculate default step.
+     */
+    public static final BinaryFunction<Float, Float, Float> DEFAULT_STEP = new BinaryFunction<Float, Float, Float>() {
+
+        public Float evaluate(Float left, Float right) {
+            return left > right ? -1.0f : 1.0f;
+        }
+    };
+
+    // constructors
+    // ---------------------------------------------------------------
+    /**
+     * Create a new FloatRange.
+     *
+     * @param from start
+     * @param to end
+     */
+    public FloatRange(Number from, Number to) {
+        this(from.floatValue(), to.floatValue());
+    }
+
+    /**
+     * Create a new FloatRange.
+     *
+     * @param from start
+     * @param to end
+     * @param step increment
+     */
+    public FloatRange(Number from, Number to, Number step) {
+        this(from.floatValue(), to.floatValue(), step.floatValue());
+    }
+
+    /**
+     * Create a new FloatRange.
+     *
+     * @param from start
+     * @param to end
+     */
+    public FloatRange(float from, float to) {
+        this(from, to, DEFAULT_STEP.evaluate(from, to).floatValue());
+    }
+
+    /**
+     * Create a new FloatRange.
+     *
+     * @param from start
+     * @param to end
+     * @param step increment
+     */
+    public FloatRange(float from, float to, float step) {
+        this(from, DEFAULT_LEFT_BOUND_TYPE, to, DEFAULT_RIGHT_BOUND_TYPE, step);
+    }
+
+    /**
+     * Create a new FloatRange.
+     *
+     * @param from start
+     * @param to end
+     */
+    public FloatRange(Endpoint<Float> from, Endpoint<Float> to) {
+        this(from.getValue(), from.getBoundType(), to.getValue(), to.getBoundType(),
+                DEFAULT_STEP.evaluate(from.getValue(), to.getValue()));
+    }
+
+    /**
+     * Create a new FloatRange.
+     *
+     * @param from start
+     * @param to end
+     * @param step increment
+     */
+    public FloatRange(Endpoint<Float> from, Endpoint<Float> to, float step) {
+        this(from.getValue(), from.getBoundType(), to.getValue(), to.getBoundType(), step);
+    }
+
+    /**
+     * Create a new FloatRange.
+     *
+     * @param from start
+     * @param leftBoundType type of left bound
+     * @param to end
+     * @param rightBoundType type of right bound
+     */
+    public FloatRange(float from, BoundType leftBoundType, float to,
+                        BoundType rightBoundType) {
+        this(from, leftBoundType, to, rightBoundType, DEFAULT_STEP.evaluate(from, to));
+    }
+
+    /**
+     * Create a new FloatRange.
+     *
+     * @param from start
+     * @param leftBoundType type of left bound
+     * @param to end
+     * @param rightBoundType type of right bound
+     * @param step increment
+     */
+    public FloatRange(float from, BoundType leftBoundType, float to,
+                      BoundType rightBoundType, float step) {
+        this.leftEndpoint = Validate
+            .notNull(new Endpoint<Float>(from, leftBoundType),
+                     "Left Endpoint argument must not be null");
+        this.rightEndpoint = Validate
+            .notNull(new Endpoint<Float>(to, rightBoundType),
+                     "Right Endpoint argument must not be null");
+        this.step = step;
+        if (from != to && Math.signum(step) != Math.signum(to - from)) {
+            throw new IllegalArgumentException("Will never reach " + to
+                                               + " from " + from
+                                               + " using step " + step);
+        }
+        if (this.leftEndpoint.getBoundType() == BoundType.CLOSED) {
+            this.currentValue = this.leftEndpoint.getValue();
+        } else {
+            this.currentValue = this.leftEndpoint.getValue() + this.step;
+        }
+    }
+
+    // range methods
+    // ---------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public Endpoint<Float> getLeftEndpoint() {
+        return this.leftEndpoint;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Endpoint<Float> getRightEndpoint() {
+        return this.rightEndpoint;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Float getStep() {
+        return this.step;
+    }
+
+    // iterable, iterator methods
+    // ---------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext() {
+        final float to = this.rightEndpoint.getValue();
+        if (step < 0) {
+            if (this.rightEndpoint.getBoundType() == BoundType.CLOSED) {
+                return this.currentValue >= to;
+            } else {
+                return this.currentValue > to;
+            }
+        } else {
+            if (this.rightEndpoint.getBoundType() == BoundType.CLOSED) {
+                return this.currentValue <= to;
+            } else {
+                return this.currentValue < to;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Float next() {
+        final float step = this.getStep();
+        final float r = this.currentValue;
+        this.currentValue += step;
+        return r;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<Float> iterator() {
+        return this;
+    }
+
+    // object methods
+    // ---------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        return "FloatRange<" + this.leftEndpoint.toLeftString() + ", "
+                + this.rightEndpoint.toRightString() + ", " + this.step + ">";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof FloatRange)) {
+            return false;
+        }
+        FloatRange that = (FloatRange) obj;
+        return this.leftEndpoint.equals(that.leftEndpoint)
+                && this.rightEndpoint.equals(that.rightEndpoint)
+                && this.step == that.step;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int hash = "FloatRange".hashCode();
+        hash <<= 2;
+        hash ^= this.leftEndpoint.getValue().hashCode();
+        hash <<= 2;
+        hash ^= this.rightEndpoint.getValue().hashCode();
+        hash <<= 2;
+        hash ^= Float.valueOf(this.step).hashCode();
+        return hash;
+    }
+
+}