Author: tn Date: Thu May 28 09:58:09 2015 New Revision: 1682196 URL: http://svn.apache.org/r1682196 Log: Add unit test for ZippingIterator, add factory methods to IteratorUtils, add changelog entry.
Added: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/iterators/ZippingIteratorTest.java (with props) Modified: commons/proper/collections/trunk/src/changes/changes.xml commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IteratorUtils.java commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/iterators/ZippingIterator.java Modified: commons/proper/collections/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/changes/changes.xml?rev=1682196&r1=1682195&r2=1682196&view=diff ============================================================================== --- commons/proper/collections/trunk/src/changes/changes.xml (original) +++ commons/proper/collections/trunk/src/changes/changes.xml Thu May 28 09:58:09 2015 @@ -28,6 +28,9 @@ added to "IterableUtils" and "IteratorUtils". </action> <action issue="COLLECTIONS-464" dev="tn" type="add"> + Added new "ZippingIterator" and factory methods "IteratorUtils#zippingIterator(...)". + </action> + <action issue="COLLECTIONS-464" dev="tn" type="add"> Added new decorator "SkippingIterator" and factory methods "IteratorUtils#skippingIterator(...)". </action> <action issue="COLLECTIONS-556" dev="tn" type="add"> Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IteratorUtils.java URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IteratorUtils.java?rev=1682196&r1=1682195&r2=1682196&view=diff ============================================================================== --- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IteratorUtils.java (original) +++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IteratorUtils.java Thu May 28 09:58:09 2015 @@ -61,6 +61,7 @@ import org.apache.commons.collections4.i import org.apache.commons.collections4.iterators.UnmodifiableIterator; import org.apache.commons.collections4.iterators.UnmodifiableListIterator; import org.apache.commons.collections4.iterators.UnmodifiableMapIterator; +import org.apache.commons.collections4.iterators.ZippingIterator; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -489,22 +490,6 @@ public class IteratorUtils { return new BoundedIterator<E>(iterator, offset, max); } - // Skipping - //----------------------------------------------------------------------- - /** - * Decorates the specified iterator to skip the first N elements. - * - * @param <E> the element type - * @param iterator the iterator to decorate - * @param offset the first number of elements to skip - * @return a new skipping iterator - * @throws IllegalArgumentException if the iterator is null or offset is negative - * @since 4.1 - */ - public static <E> SkippingIterator<E> skippingIterator(final Iterator<E> iterator, long offset) { - return new SkippingIterator<E>(iterator, offset); - } - // Unmodifiable //----------------------------------------------------------------------- /** @@ -914,6 +899,68 @@ public class IteratorUtils { return PushbackIterator.pushbackIterator(iterator); } + // Skipping + //----------------------------------------------------------------------- + /** + * Decorates the specified iterator to skip the first N elements. + * + * @param <E> the element type + * @param iterator the iterator to decorate + * @param offset the first number of elements to skip + * @return a new skipping iterator + * @throws IllegalArgumentException if the iterator is null or offset is negative + * @since 4.1 + */ + public static <E> SkippingIterator<E> skippingIterator(final Iterator<E> iterator, long offset) { + return new SkippingIterator<E>(iterator, offset); + } + + // Zipping + //----------------------------------------------------------------------- + /** + * Returns an iterator that interleaves elements from the decorated iterators. + * + * @param <E> the element type + * @param a the first iterator to interleave + * @param b the second iterator to interleave + * @return an iterator, interleaving the decorated iterators + * @throws IllegalArgumentException if any iterator is null + * @since 4.1 + */ + public static <E> ZippingIterator<E> zippingIterator(final Iterator<? extends E> a, final Iterator<? extends E> b) { + return new ZippingIterator<E>(a, b); + } + + /** + * Returns an iterator that interleaves elements from the decorated iterators. + * + * @param <E> the element type + * @param a the first iterator to interleave + * @param b the second iterator to interleave + * @param c the third iterator to interleave + * @return an iterator, interleaving the decorated iterators + * @throws IllegalArgumentException if any iterator is null + * @since 4.1 + */ + public static <E> ZippingIterator<E> zippingIterator(final Iterator<? extends E> a, + final Iterator<? extends E> b, + final Iterator<? extends E> c) { + return new ZippingIterator<E>(a, b, c); + } + + /** + * Returns an iterator that interleaves elements from the decorated iterators. + * + * @param <E> the element type + * @param iterators the array of iterators to interleave + * @return an iterator, interleaving the decorated iterators + * @throws IllegalArgumentException if any iterator is null + * @since 4.1 + */ + public static <E> ZippingIterator<E> zippingIterator(final Iterator<? extends E>... iterators) { + return new ZippingIterator<E>(iterators); + } + // Views //----------------------------------------------------------------------- /** Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/iterators/ZippingIterator.java URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/iterators/ZippingIterator.java?rev=1682196&r1=1682195&r2=1682196&view=diff ============================================================================== --- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/iterators/ZippingIterator.java (original) +++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/iterators/ZippingIterator.java Thu May 28 09:58:09 2015 @@ -27,9 +27,9 @@ import org.apache.commons.collections4.F * Provides an interleaved iteration over the elements contained in a * collection of Iterators. * <p> - * Given two {@link Iterator} instances <code>A</code> and - * <code>B</code>, the {@link #next} method on this iterator will - * alternate between <code>A.next()</code> and <code>B.next()</code>. + * Given two {@link Iterator} instances {@code A} and {@code B}, the + * {@link #next} method on this iterator will switch between {@code A.next()} + * and {@code B.next()} until both iterators are exhausted. * * @since 4.1 * @version $Id$ @@ -38,8 +38,10 @@ public class ZippingIterator<E> implemen /** The {@link Iterator}s to evaluate. */ private final Iterator<Iterator<? extends E>> iterators; + /** The next iterator to use for next(). */ private Iterator<? extends E> nextIterator = null; + /** The last iterator which was used for next(). */ private Iterator<? extends E> lastReturned = null; @@ -50,8 +52,8 @@ public class ZippingIterator<E> implemen * Constructs a new <code>ZippingIterator</code> that will provide * interleaved iteration over the two given iterators. * - * @param a the first child iterator - * @param b the second child iterator + * @param a the first child iterator + * @param b the second child iterator * @throws NullPointerException if either iterator is null */ @SuppressWarnings("unchecked") @@ -60,19 +62,34 @@ public class ZippingIterator<E> implemen } /** - * Constructs a new <code>ZippingIterator</code> that will use the - * specified comparator to provide ordered iteration over the array of - * iterators. + * Constructs a new <code>ZippingIterator</code> that will provide + * interleaved iteration over the three given iterators. + * + * @param a the first child iterator + * @param b the second child iterator + * @param c the third child iterator + * @throws NullPointerException if either iterator is null + */ + @SuppressWarnings("unchecked") + public ZippingIterator(final Iterator<? extends E> a, + final Iterator<? extends E> b, + final Iterator<? extends E> c) { + this(new Iterator[] {a, b, c}); + } + + /** + * Constructs a new <code>ZippingIterator</code> that will provide + * interleaved iteration of the specified iterators. * - * @param iterators the array of iterators - * @throws NullPointerException if iterators array is or contains null + * @param iterators the array of iterators + * @throws NullPointerException if any iterator is null */ public ZippingIterator(final Iterator<? extends E>... iterators) { - // create a mutable list + // create a mutable list to be able to remove exhausted iterators final List<Iterator<? extends E>> list = new ArrayList<Iterator<? extends E>>(); - for (Iterator<? extends E> iterator : iterators) { + for (final Iterator<? extends E> iterator : iterators) { if (iterator == null) { - throw new NullPointerException("Iterator must not be null"); + throw new NullPointerException("Iterator must not be null."); } list.add(iterator); } @@ -83,21 +100,21 @@ public class ZippingIterator<E> implemen // ------------------------------------------------------------------- /** - * Returns <code>true</code> if any child iterator has remaining elements. + * Returns {@code true} if any child iterator has remaining elements. * * @return true if this iterator has remaining elements */ public boolean hasNext() { // the next iterator has already been determined - // this might happen if hasNext() was called multiple + // this might happen if hasNext() is called multiple if (nextIterator != null) { return true; } while(iterators.hasNext()) { - final Iterator<? extends E> iterator = iterators.next(); - if (iterator.hasNext()) { - nextIterator = iterator; + final Iterator<? extends E> childIterator = iterators.next(); + if (childIterator.hasNext()) { + nextIterator = childIterator; return true; } else { // iterator is exhausted, remove it Added: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/iterators/ZippingIteratorTest.java URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/iterators/ZippingIteratorTest.java?rev=1682196&view=auto ============================================================================== --- commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/iterators/ZippingIteratorTest.java (added) +++ commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/iterators/ZippingIteratorTest.java Thu May 28 09:58:09 2015 @@ -0,0 +1,191 @@ +/* + * 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.collections4.iterators; + +import java.util.ArrayList; + +import org.apache.commons.collections4.IteratorUtils; + +/** + * Unit test suite for {@link ZippingIterator}. + * + * @version $Id$ + */ +@SuppressWarnings("boxing") +public class ZippingIteratorTest extends AbstractIteratorTest<Integer> { + + //------------------------------------------------------------ Conventional + + public ZippingIteratorTest(final String testName) { + super(testName); + } + + //--------------------------------------------------------------- Lifecycle + + private ArrayList<Integer> evens = null; + private ArrayList<Integer> odds = null; + private ArrayList<Integer> fib = null; + + @Override + public void setUp() throws Exception { + super.setUp(); + evens = new ArrayList<Integer>(); + odds = new ArrayList<Integer>(); + for (int i = 0; i < 20; i++) { + if (0 == i % 2) { + evens.add(i); + } else { + odds.add(i); + } + } + fib = new ArrayList<Integer>(); + fib.add(1); + fib.add(1); + fib.add(2); + fib.add(3); + fib.add(5); + fib.add(8); + fib.add(13); + fib.add(21); + } + + //---------------------------------------------------- TestIterator Methods + + @Override + @SuppressWarnings("unchecked") + public ZippingIterator<Integer> makeEmptyIterator() { + return new ZippingIterator<Integer>(IteratorUtils.<Integer>emptyIterator()); + } + + @Override + public ZippingIterator<Integer> makeObject() { + return new ZippingIterator<Integer>(evens.iterator(), odds.iterator(), fib.iterator()); + } + + //------------------------------------------------------------------- Tests + + public void testIterateEven() { + @SuppressWarnings("unchecked") + final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(evens.iterator()); + for (int i = 0; i < evens.size(); i++) { + assertTrue(iter.hasNext()); + assertEquals(evens.get(i), iter.next()); + } + assertTrue(!iter.hasNext()); + } + + public void testIterateEvenOdd() { + final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(evens.iterator(), odds.iterator()); + for (int i = 0; i < 20; i++) { + assertTrue(iter.hasNext()); + assertEquals(Integer.valueOf(i), iter.next()); + } + assertTrue(!iter.hasNext()); + } + + public void testIterateOddEven() { + final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(odds.iterator(), evens.iterator()); + for (int i = 0, j = 0; i < 20; i++) { + assertTrue(iter.hasNext()); + int val = iter.next(); + if (i % 2 == 0) { + assertEquals(odds.get(j).intValue(), val); + } else { + assertEquals(evens.get(j).intValue(), val); + j++; + } + } + assertTrue(!iter.hasNext()); + } + + public void testIterateEvenEven() { + final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(evens.iterator(), evens.iterator()); + for (int i = 0; i < evens.size(); i++) { + assertTrue(iter.hasNext()); + assertEquals(evens.get(i), iter.next()); + assertTrue(iter.hasNext()); + assertEquals(evens.get(i), iter.next()); + } + assertTrue(!iter.hasNext()); + } + + public void testIterateFibEvenOdd() { + final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(fib.iterator(), evens.iterator(), odds.iterator()); + + assertEquals(Integer.valueOf(1),iter.next()); // fib 1 + assertEquals(Integer.valueOf(0),iter.next()); // even 0 + assertEquals(Integer.valueOf(1),iter.next()); // odd 1 + assertEquals(Integer.valueOf(1),iter.next()); // fib 1 + assertEquals(Integer.valueOf(2),iter.next()); // even 2 + assertEquals(Integer.valueOf(3),iter.next()); // odd 3 + assertEquals(Integer.valueOf(2),iter.next()); // fib 2 + assertEquals(Integer.valueOf(4),iter.next()); // even 4 + assertEquals(Integer.valueOf(5),iter.next()); // odd 5 + assertEquals(Integer.valueOf(3),iter.next()); // fib 3 + assertEquals(Integer.valueOf(6),iter.next()); // even 6 + assertEquals(Integer.valueOf(7),iter.next()); // odd 7 + assertEquals(Integer.valueOf(5),iter.next()); // fib 5 + assertEquals(Integer.valueOf(8),iter.next()); // even 8 + assertEquals(Integer.valueOf(9),iter.next()); // odd 9 + assertEquals(Integer.valueOf(8),iter.next()); // fib 8 + assertEquals(Integer.valueOf(10),iter.next()); // even 10 + assertEquals(Integer.valueOf(11),iter.next()); // odd 11 + assertEquals(Integer.valueOf(13),iter.next()); // fib 13 + assertEquals(Integer.valueOf(12),iter.next()); // even 12 + assertEquals(Integer.valueOf(13),iter.next()); // odd 13 + assertEquals(Integer.valueOf(21),iter.next()); // fib 21 + assertEquals(Integer.valueOf(14),iter.next()); // even 14 + assertEquals(Integer.valueOf(15),iter.next()); // odd 15 + assertEquals(Integer.valueOf(16),iter.next()); // even 16 + assertEquals(Integer.valueOf(17),iter.next()); // odd 17 + assertEquals(Integer.valueOf(18),iter.next()); // even 18 + assertEquals(Integer.valueOf(19),iter.next()); // odd 19 + + assertTrue(!iter.hasNext()); + } + + public void testRemoveFromSingle() { + @SuppressWarnings("unchecked") + final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(evens.iterator()); + int expectedSize = evens.size(); + while (iter.hasNext()) { + final Object o = iter.next(); + final Integer val = (Integer) o; + if (val.intValue() % 4 == 0) { + expectedSize--; + iter.remove(); + } + } + assertEquals(expectedSize, evens.size()); + } + + public void testRemoveFromDouble() { + final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(evens.iterator(), odds.iterator()); + int expectedSize = evens.size() + odds.size(); + while (iter.hasNext()) { + final Object o = iter.next(); + final Integer val = (Integer) o; + if (val.intValue() % 4 == 0 || val.intValue() % 3 == 0) { + expectedSize--; + iter.remove(); + } + } + assertEquals(expectedSize, evens.size() + odds.size()); + } + +} + Propchange: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/iterators/ZippingIteratorTest.java ------------------------------------------------------------------------------ svn:keywords = Id Revision HeadURL