Author: mbenson
Date: Wed Mar 2 22:55:02 2011
New Revision: 1076446
URL: http://svn.apache.org/viewvc?rev=1076446&view=rev
Log:
add FilteredIterable
Added:
commons/sandbox/functor/trunk/src/main/java/org/apache/commons/functor/core/collection/FilteredIterable.java
(with props)
commons/sandbox/functor/trunk/src/test/java/org/apache/commons/functor/core/collection/TestFilteredIterable.java
(with props)
Added:
commons/sandbox/functor/trunk/src/main/java/org/apache/commons/functor/core/collection/FilteredIterable.java
URL:
http://svn.apache.org/viewvc/commons/sandbox/functor/trunk/src/main/java/org/apache/commons/functor/core/collection/FilteredIterable.java?rev=1076446&view=auto
==============================================================================
---
commons/sandbox/functor/trunk/src/main/java/org/apache/commons/functor/core/collection/FilteredIterable.java
(added)
+++
commons/sandbox/functor/trunk/src/main/java/org/apache/commons/functor/core/collection/FilteredIterable.java
Wed Mar 2 22:55:02 2011
@@ -0,0 +1,172 @@
+/*
+ * 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.core.collection;
+
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.apache.commons.functor.UnaryFunction;
+import org.apache.commons.functor.UnaryPredicate;
+import org.apache.commons.functor.core.IsInstance;
+import org.apache.commons.functor.core.composite.UnaryAnd;
+
+/**
+ * Adds a fluent filtering API to any {@link Iterable}.
+ *
+ * @version $Revision$ $Date$
+ *
+ * @param <T>
+ */
+public class FilteredIterable<T> implements Iterable<T> {
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ // type irrelevant for empty instance
+ private static final FilteredIterable EMPTY = new
FilteredIterable(Collections.EMPTY_LIST) {
+ @Override
+ public FilteredIterable retain(Class type) {
+ return this;
+ }
+
+ @Override
+ public synchronized FilteredIterable retain(UnaryPredicate predicate) {
+ return this;
+ }
+
+ @Override
+ public FilteredIterable retain(Class... ofType) {
+ return this;
+ }
+ };
+
+ private final Iterable<? extends T> iterable;
+ private UnaryAnd<T> predicate;
+
+ /**
+ * Create a new FilteredIterable.
+ * @param iterable wrapped
+ */
+ private FilteredIterable(Iterable<? extends T> iterable) {
+ super();
+ this.iterable = iterable;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator<T> iterator() {
+ return FilteredIterator.filter(iterable.iterator(), predicate);
+ }
+
+ @Override
+ public String toString() {
+ return "FilteredIterable<" + iterable + ">";
+ }
+
+ /**
+ * Retain only elements matching <code>predicate</code>.
+ * @param predicate filter, non-<code>null</code>
+ * @return <code>this</code>, fluently
+ */
+ public synchronized FilteredIterable<T> retain(UnaryPredicate<? super T>
predicate) {
+ if (predicate == null) {
+ throw new NullPointerException("filtering predicate was null");
+ }
+ if (this.predicate == null) {
+ this.predicate = new UnaryAnd<T>();
+ }
+ this.predicate.and(predicate);
+ return this;
+ }
+
+ /**
+ * Retain elements of a given type with type-safety.
+ * @param <U>
+ * @param type filter, non-<code>null</code>
+ * @return new FilteredIterable instance that delegates to
<code>this</code>
+ */
+ public <U> FilteredIterable<U> retain(final Class<U> type) {
+ if (type == null) {
+ throw new NullPointerException("filtered type was null");
+ }
+ return new FilteredIterable<U>(new Iterable<U>() {
+
+ public Iterator<U> iterator() {
+ return TransformedIterator.transform(
+
FilteredIterator.filter(FilteredIterable.this.iterator(), IsInstance.of(type)),
+ new UnaryFunction<T, U>() {
+
+ @SuppressWarnings("unchecked")
+ // this is okay because of the isinstance check
+ public U evaluate(T obj) {
+ return (U) obj;
+ }
+ });
+ }
+
+ });
+ }
+
+ /**
+ * Retain elements of any of specified types.
+ * @param ofType filter, non-<code>null</code>
+ * @return <code>this</code>, fluently
+ */
+ public FilteredIterable<T> retain(final Class<?>... ofType) {
+ if (ofType == null) {
+ throw new NullPointerException("array of filtered types was null");
+ }
+ return retain(new UnaryPredicate<T>() {
+
+ public boolean test(T obj) {
+ for (Class<?> type : ofType) {
+ if (type.isInstance(obj)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ });
+ }
+
+ /**
+ * Get a {@link FilteredIterable} of <code>iterable</code>. If
<code>wrapped</code> is <code>null</code>,
+ * result will also be <code>null</code>. A {@link FilteredIterable}
argument will be passed back
+ * directly; any other argument will be wrapped in a new {@link
FilteredIterable} object.
+ * @param <T>
+ * @param iterable wrapped
+ * @return FilteredIterable
+ */
+ public static <T> FilteredIterable<T> of(Iterable<T> iterable) {
+ if (iterable == null) {
+ return null;
+ }
+ if (iterable instanceof FilteredIterable<?>) {
+ return (FilteredIterable<T>) iterable;
+ }
+ return new FilteredIterable<T>(iterable);
+ }
+
+ /**
+ * Get an empty FilteredIterable.
+ * @param <T>
+ * @return FilteredIterable<T>
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> FilteredIterable<T> empty() {
+ return EMPTY;
+ }
+}
Propchange:
commons/sandbox/functor/trunk/src/main/java/org/apache/commons/functor/core/collection/FilteredIterable.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
commons/sandbox/functor/trunk/src/main/java/org/apache/commons/functor/core/collection/FilteredIterable.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added:
commons/sandbox/functor/trunk/src/test/java/org/apache/commons/functor/core/collection/TestFilteredIterable.java
URL:
http://svn.apache.org/viewvc/commons/sandbox/functor/trunk/src/test/java/org/apache/commons/functor/core/collection/TestFilteredIterable.java?rev=1076446&view=auto
==============================================================================
---
commons/sandbox/functor/trunk/src/test/java/org/apache/commons/functor/core/collection/TestFilteredIterable.java
(added)
+++
commons/sandbox/functor/trunk/src/test/java/org/apache/commons/functor/core/collection/TestFilteredIterable.java
Wed Mar 2 22:55:02 2011
@@ -0,0 +1,262 @@
+/*
+ * 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.core.collection;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.commons.functor.BaseFunctorTest;
+import org.apache.commons.functor.UnaryPredicate;
+import org.apache.commons.functor.core.Constant;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@SuppressWarnings("unchecked")
+public class TestFilteredIterable extends BaseFunctorTest {
+
+ // Attributes
+ // ------------------------------------------------------------------------
+ private List<Integer> list = null;
+ private List<Integer> evens = null;
+
+ private UnaryPredicate<Integer> isEven = new UnaryPredicate<Integer>() {
+ public boolean test(Integer obj) {
+ return obj != null && obj % 2 == 0;
+ }
+ };
+
+ // Conventional
+ // ------------------------------------------------------------------------
+
+ public TestFilteredIterable(String testName) {
+ super(testName);
+ }
+
+ public static Test suite() {
+ return new TestSuite(TestFilteredIterable.class);
+ }
+
+ public Object makeFunctor() {
+ List<String> list = new ArrayList<String>();
+ list.add("xyzzy");
+ return FilteredIterable.of(list);
+ }
+
+ // Lifecycle
+ // ------------------------------------------------------------------------
+
+ public void setUp() throws Exception {
+ super.setUp();
+ list = new ArrayList<Integer>();
+ evens = new ArrayList<Integer>();
+ for (int i = 0; i < 10; i++) {
+ list.add(i);
+ if (i % 2 == 0) {
+ evens.add(i);
+ }
+ }
+ }
+
+ public void tearDown() throws Exception {
+ super.tearDown();
+ list = null;
+ evens = null;
+ }
+
+ // Tests
+ // ------------------------------------------------------------------------
+
+ public void testSomePass() {
+ Iterator<Integer> expected = evens.iterator();
+
+ for (Integer i : FilteredIterable.of(list).retain(isEven)) {
+ assertTrue(expected.hasNext());
+ assertEquals(expected.next(), i);
+ }
+ assertFalse(expected.hasNext());
+ }
+
+ public void testAllPass() {
+ Iterator<Integer> expected = evens.iterator();
+
+ for (Integer i : FilteredIterable.of(evens)) {
+ assertTrue(expected.hasNext());
+ assertEquals(expected.next(), i);
+ }
+ assertFalse(expected.hasNext());
+ }
+
+ public void testAllPass2() {
+ Iterator<Integer> expected = list.iterator();
+ for (Integer i : FilteredIterable.of(list)) {
+ assertTrue(expected.hasNext());
+ assertEquals(expected.next(), i);
+ }
+ assertFalse(expected.hasNext());
+ }
+
+ public void testEmptyFilteredIterable() {
+ assertFalse(FilteredIterable.empty().iterator().hasNext());
+ }
+
+ public void testEmptyList() {
+
assertFalse(FilteredIterable.of(Collections.EMPTY_LIST).iterator().hasNext());
+ }
+
+ public void testNonePass() {
+
assertFalse(FilteredIterable.of(list).retain(Constant.falsePredicate()).iterator().hasNext());
+ }
+
+ public void testNextWithoutHasNext() {
+ Iterator<Integer> testing =
FilteredIterable.of(list).retain(isEven).iterator();
+ Iterator<Integer> expected = evens.iterator();
+ while (expected.hasNext()) {
+ assertEquals(expected.next(), testing.next());
+ }
+ assertFalse(testing.hasNext());
+ }
+
+ public void testNextAfterEndOfList() {
+ Iterator<Integer> testing =
FilteredIterable.of(list).retain(isEven).iterator();
+ Iterator<Integer> expected = evens.iterator();
+ while (expected.hasNext()) {
+ assertEquals(expected.next(), testing.next());
+ }
+ try {
+ testing.next();
+ fail("Expected NoSuchElementException");
+ } catch (NoSuchElementException e) {
+ // expected
+ }
+ }
+
+ public void testNextOnEmptyList() {
+ try {
+ FilteredIterable.empty().iterator().next();
+ fail("Expected NoSuchElementException");
+ } catch (NoSuchElementException e) {
+ // expected
+ }
+ }
+
+ public void testRemoveBeforeNext() {
+ Iterator<Integer> testing =
FilteredIterable.of(list).retain(isEven).iterator();
+ try {
+ testing.remove();
+ fail("Expected IllegalStateException");
+ } catch (IllegalStateException e) {
+ // expected
+ }
+ }
+
+ public void testRemoveAfterNext() {
+ Iterator<Integer> testing =
FilteredIterable.of(list).retain(isEven).iterator();
+ testing.next();
+ testing.remove();
+ try {
+ testing.remove();
+ fail("Expected IllegalStateException");
+ } catch (IllegalStateException e) {
+ // expected
+ }
+ }
+
+ public void testRemoveSome() {
+ Iterator<Integer> testing =
FilteredIterable.of(list).retain(isEven).iterator();
+ while (testing.hasNext()) {
+ testing.next();
+ testing.remove();
+ }
+ assertTrue(Collections.disjoint(list, evens));
+ }
+
+ public void testRemoveAll() {
+ Iterator<Integer> testing = FilteredIterable.of(list).iterator();
+ while (testing.hasNext()) {
+ testing.next();
+ testing.remove();
+ }
+ assertTrue(list.isEmpty());
+ }
+
+ public void testRemoveWithoutHasNext() {
+ Iterator<Integer> testing = FilteredIterable.of(list).iterator();
+ for (int i = 0, m = list.size(); i < m; i++) {
+ testing.next();
+ testing.remove();
+ }
+ assertTrue(list.isEmpty());
+ }
+
+ public void testFilterWithNullIteratorReturnsNull() {
+ assertNull(FilteredIterable.of(null));
+ }
+
+ public void testRetainOneType() {
+ Iterable<Object> objects = Arrays.asList((Object) "foo", "bar", "baz",
2L, BigInteger.ZERO);
+ Iterable<String> strings =
FilteredIterable.of(objects).retain(String.class);
+ for (String s : strings) {
+ assertTrue(s instanceof String);
+ }
+ Iterator<Number> iterator =
FilteredIterable.of(objects).retain(Number.class).iterator();
+ assertEquals(2L, iterator.next());
+ assertEquals(BigInteger.ZERO, iterator.next());
+ }
+
+ public void testRetainMultipleTypes() {
+ Iterable<Object> objects = Arrays.asList((Object) "foo", "bar", "baz",
2L, BigInteger.ZERO);
+ Iterator<Object> iterator =
FilteredIterable.of(objects).retain(Long.class, BigInteger.class).iterator();
+ assertEquals(2L, iterator.next());
+ assertEquals(BigInteger.ZERO, iterator.next());
+ }
+
+ public void testRetainNullType() {
+ try {
+
FilteredIterable.of(Collections.singleton("foo")).retain((Class<?>) null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException e) {
+ // okay
+ }
+ }
+
+ public void testRetainNullTypes() {
+ try {
+
FilteredIterable.of(Collections.singleton("foo")).retain((Class<?>[]) null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException e) {
+ // okay
+ }
+ }
+
+ public void testRetainNullPredicate() {
+ try {
+
FilteredIterable.of(Collections.singleton("foo")).retain((UnaryPredicate<String>)
null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException e) {
+ // okay
+ }
+ }
+}
Propchange:
commons/sandbox/functor/trunk/src/test/java/org/apache/commons/functor/core/collection/TestFilteredIterable.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
commons/sandbox/functor/trunk/src/test/java/org/apache/commons/functor/core/collection/TestFilteredIterable.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL