| // 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.tapestry5.func; |
| |
| import java.util.Collection; |
| import java.util.Comparator; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| /** |
| * Functional operations on collections with generics support. The core interface is {@link Flow} to |
| * which operations |
| * and transformations |
| * (in terms of {@link Predicate}s, {@link Mapper}s and {@link Reducer}s) to create new Flows. Flows |
| * are initially |
| * created |
| * using {@link #flow(Collection)} and {@link #flow(Object...)}. |
| * |
| * F will be used a bit, thus it has a short name (for those who don't like static imports). It provides a base set of |
| * Predicate, Mapper and Reducer factories. A good development pattern for applications is to provide a similar, |
| * application-specific, set of such factories. |
| * |
| * @since 5.2.0 |
| */ |
| @SuppressWarnings("all") |
| public class F |
| { |
| final static Flow<?> EMPTY_FLOW = new EmptyFlow(); |
| |
| @SuppressWarnings("unchecked") |
| static <T> Flow<T> emptyFlow() |
| { |
| return (Flow<T>) EMPTY_FLOW; |
| } |
| |
| /** |
| * A Predicate factory for equality of an element from a flow against a specified |
| * value. |
| */ |
| public static <T> Predicate<T> eql(final T value) |
| { |
| return new Predicate<T>() |
| { |
| @Override |
| public boolean accept(T element) |
| { |
| return element.equals(value); |
| } |
| }; |
| } |
| |
| /** |
| * Predicate that returns true if the provided string is blank (null or all whitespace). |
| */ |
| public static Predicate<String> IS_BLANK = new Predicate<String>() |
| { |
| @Override |
| public boolean accept(String element) |
| { |
| return element == null || element.trim().length() == 0; |
| } |
| }; |
| |
| /** |
| * A Predicate factory for comparison of a Comparable element from a flow against a fixed value. |
| */ |
| public static <T extends Comparable<T>> Predicate<T> eq(final T value) |
| { |
| return new Predicate<T>() |
| { |
| @Override |
| public boolean accept(T element) |
| { |
| return element.compareTo(value) == 0; |
| } |
| }; |
| } |
| |
| /** |
| * A Predicate factory for comparison of a Comparable element against a fixed value. |
| */ |
| public static <T extends Comparable<T>> Predicate<T> neq(final T value) |
| { |
| return new Predicate<T>() |
| { |
| @Override |
| public boolean accept(T object) |
| { |
| return object.compareTo(value) != 0; |
| } |
| }; |
| } |
| |
| /** |
| * A Predicate factory for comparison of a Comparable against a fixed value; true |
| * if the flow element is greater than the provided value. |
| */ |
| public static <T extends Comparable<T>> Predicate<T> gt(final T value) |
| { |
| return new Predicate<T>() |
| { |
| @Override |
| public boolean accept(T element) |
| { |
| return element.compareTo(value) > 0; |
| } |
| }; |
| } |
| |
| /** |
| * A Predicate factory for comparison of a Comparable against a fixed value; true |
| * if the flow element is greater than or equal to the value. |
| */ |
| public static <T extends Comparable<T>> Predicate<T> gteq(final T value) |
| { |
| return new Predicate<T>() |
| { |
| @Override |
| public boolean accept(T element) |
| { |
| return element.compareTo(value) >= 0; |
| } |
| }; |
| } |
| |
| /** |
| * A Predicate factory for comparison of a Comparable against a fixed value; true |
| * if the element is less than the value. |
| */ |
| public static <T extends Comparable<T>> Predicate<T> lt(T value) |
| { |
| return not(gteq(value)); |
| } |
| |
| /** |
| * A Predicate factory for comparison of a Comprable element against a fixed value; true |
| * if the element is less than or equal to the value. |
| */ |
| public static <T extends Comparable<T>> Predicate<T> lteq(T value) |
| { |
| return not(gt(value)); |
| } |
| |
| /** |
| * A Predicate factory; returns true if the value from the Flow is null. |
| */ |
| public static <T> Predicate<T> isNull() |
| { |
| return new Predicate<T>() |
| { |
| @Override |
| public boolean accept(T element) |
| { |
| return element == null; |
| } |
| }; |
| } |
| |
| /** |
| * A Predicate factory; returns true if the value from the Flow is not null. |
| */ |
| public static <T> Predicate<T> notNull() |
| { |
| return not(isNull()); |
| } |
| |
| /** |
| * A Mapper factory that gets the string value of the flow value using {@link String#valueOf(Object)}. |
| */ |
| public static <T> Mapper<T, String> stringValueOf() |
| { |
| return new Mapper<T, String>() |
| { |
| @Override |
| public String map(T value) |
| { |
| return String.valueOf(value); |
| } |
| }; |
| } |
| |
| /** |
| * A Mapper factory; the returned Mapper ignores its input value and always returns a |
| * predetermined result. |
| */ |
| public static <S, T> Mapper<S, T> always(final T fixedResult) |
| { |
| return new Mapper<S, T>() |
| { |
| @Override |
| public T map(S input) |
| { |
| return fixedResult; |
| } |
| }; |
| } |
| |
| /** |
| * A Mapper factory that combines a Predicate with two {@link Mapper}s; evaluating the predicate |
| * selects one of the two mappers. |
| * |
| * @param predicate |
| * evaluated to selected a coercion |
| * @param ifAccepted |
| * used when predicate evaluates to true |
| * @param ifRejected |
| * used when predicate evaluates to false |
| */ |
| public static <S, T> Mapper<S, T> select(final Predicate<? super S> predicate, final Mapper<S, T> ifAccepted, |
| final Mapper<S, T> ifRejected) |
| { |
| assert predicate != null; |
| assert ifAccepted != null; |
| assert ifRejected != null; |
| |
| return new Mapper<S, T>() |
| { |
| @Override |
| public T map(S input) |
| { |
| Mapper<S, T> active = predicate.accept(input) ? ifAccepted : ifRejected; |
| |
| return active.map(input); |
| } |
| }; |
| } |
| |
| /** |
| * Override of {@link #select(Predicate, Mapper, Mapper)} where rejected values are replaced |
| * with null. |
| */ |
| public static <S, T> Mapper<S, T> select(Predicate<? super S> predicate, Mapper<S, T> ifAccepted) |
| { |
| return select(predicate, ifAccepted, (T) null); |
| } |
| |
| /** |
| * Override of {@link #select(Predicate, Mapper)} where rejected values are replaced with a |
| * fixed value. |
| */ |
| public static <S, T> Mapper<S, T> select(Predicate<? super S> predicate, Mapper<S, T> ifAccepted, T ifRejectedValue) |
| { |
| Mapper<S, T> rejectedMapper = always(ifRejectedValue); |
| |
| return select(predicate, ifAccepted, rejectedMapper); |
| } |
| |
| /** |
| * A Mapper factory; the Mapper returns the the flow value unchanged. |
| */ |
| public static <S> Mapper<S, S> identity() |
| { |
| return new Mapper<S, S>() |
| { |
| @Override |
| public S map(S input) |
| { |
| return input; |
| } |
| }; |
| } |
| |
| /** |
| * Allows a Mapper that maps to boolean to be used as a Predicate. |
| */ |
| public static <S> Predicate<S> toPredicate(final Mapper<S, Boolean> mapper) |
| { |
| assert mapper != null; |
| |
| return new Predicate<S>() |
| { |
| @Override |
| public boolean accept(S object) |
| { |
| return mapper.map(object); |
| } |
| }; |
| } |
| |
| /** |
| * A Reducer that operates on a Flow of Integers and is used to sum the values. |
| */ |
| public static Reducer<Integer, Integer> SUM_INTS = new Reducer<Integer, Integer>() |
| { |
| @Override |
| public Integer reduce(Integer accumulator, Integer value) |
| { |
| return accumulator + value; |
| } |
| }; |
| |
| /** |
| * A two-input Mapper used to add the values from two Flows of Integers into a Flow of Integer |
| * sums. |
| */ |
| public static Mapper2<Integer, Integer, Integer> ADD_INTS = new Mapper2<Integer, Integer, Integer>() |
| { |
| @Override |
| public Integer map(Integer first, Integer second) |
| { |
| return first + second; |
| } |
| }; |
| |
| /** |
| * Extracts the values from the collection to form a {@link Flow}. The Collection |
| * may change after the Flow is created without affecting the Flow. |
| */ |
| public static <T> Flow<T> flow(Collection<T> values) |
| { |
| assert values != null; |
| |
| if (values.isEmpty()) |
| return emptyFlow(); |
| |
| return new ArrayFlow<T>(values); |
| } |
| |
| /** |
| * Creates a new Flow from the values. You should not change the values array |
| * after invoking this method (i.e., no defensive copy of the values is made). |
| */ |
| public static <T> Flow<T> flow(T... values) |
| { |
| if (values.length == 0) |
| return emptyFlow(); |
| |
| return new ArrayFlow<T>(values); |
| } |
| |
| /** |
| * Creates a lazy Flow from the {@link Iterator} obtained from the iterable. The Flow |
| * will be threadsafe as long as the iterable yields a new Iterator on each invocation <em>and</em> the underlying |
| * iterable object is not modified while the Flow is evaluating. |
| * In other words, not extremely threadsafe. |
| */ |
| public static <T> Flow<T> flow(Iterable<T> iterable) |
| { |
| assert iterable != null; |
| |
| return flow(iterable.iterator()); |
| } |
| |
| /** |
| * Creates a lazy Flow from the {@link Iterator}. The Flow will be threadsafe as long as the underlying iterable |
| * object is not modified while the Flow is evaluating. In other words, not extremely threadsafe. |
| * |
| * @since 5.3 |
| */ |
| public static <T> Flow<T> flow(Iterator<T> iterator) |
| { |
| return lazy(new LazyIterator<T>(iterator)); |
| } |
| |
| /** |
| * Creates a ZippedFlow from the provided map; the order of the tuples in the ZippedFlow is defined |
| * by the iteration order of the map entries. |
| * |
| * @param <A> |
| * type of key and first tuple value |
| * @param <B> |
| * type of value and second tuple value |
| * @param map |
| * source of tuples |
| * @return zipped flow created from map |
| * @since 5.3 |
| */ |
| public static <A, B> ZippedFlow<A, B> zippedFlow(Map<A, B> map) |
| { |
| assert map != null; |
| |
| Flow<Tuple<A, B>> tuples = F.flow(map.entrySet()).map(new Mapper<Map.Entry<A, B>, Tuple<A, B>>() |
| { |
| @Override |
| public Tuple<A, B> map(Entry<A, B> element) |
| { |
| return Tuple.create(element.getKey(), element.getValue()); |
| } |
| }); |
| |
| return ZippedFlowImpl.create(tuples); |
| } |
| |
| /** |
| * Creates a lazy Flow that returns integers in the given range. The range starts |
| * with the lower value and counts by 1 up to the upper range (which is not part of |
| * the Flow). If lower equals upper, the Flow is empty. If upper is less than lower, |
| * the Flow counts down instead. |
| * |
| * @param lower |
| * start of range (inclusive) |
| * @param upper |
| * end of range (exclusive) |
| */ |
| public static Flow<Integer> range(int lower, int upper) |
| { |
| if (lower == upper) |
| return F.emptyFlow(); |
| |
| if (lower < upper) |
| return lazy(new LazyRange(lower, upper, 1)); |
| |
| return lazy(new LazyRange(lower, upper, -1)); |
| } |
| |
| /** |
| * Creates a {@link Flow} from a {@linkplain LazyFunction lazy function}. |
| */ |
| public static <T> Flow<T> lazy(LazyFunction<T> function) |
| { |
| assert function != null; |
| |
| return new LazyFlow<T>(function); |
| } |
| |
| private static <T> LazyFunction<T> toLazyFunction(final T currentValue, final Mapper<T, T> function) |
| { |
| return new LazyFunction<T>() |
| { |
| @Override |
| public LazyContinuation<T> next() |
| { |
| final T nextValue = function.map(currentValue); |
| |
| return new LazyContinuation<T>(nextValue, toLazyFunction(nextValue, function)); |
| } |
| }; |
| } |
| |
| /** |
| * Creates an infinite lazy flow from an initial value and a function to map from the current value to the |
| * next value. |
| * |
| * @param initial |
| * initial value in flow |
| * @param function |
| * maps from current value in flow to next value in flow |
| * @return lazy flow |
| */ |
| public static <T> Flow<T> iterate(final T initial, final Mapper<T, T> function) |
| { |
| LazyFunction<T> head = new LazyFunction<T>() |
| { |
| @Override |
| public LazyContinuation<T> next() |
| { |
| return new LazyContinuation<T>(initial, toLazyFunction(initial, function)); |
| } |
| }; |
| |
| return lazy(head); |
| } |
| |
| /** |
| * Creates an <em>infinite</em> series of numbers. |
| * |
| * Attempting to get the {@linkplain Flow#count()} of the series will form an infinite loop. |
| */ |
| public static Flow<Integer> series(int start, final int delta) |
| { |
| return iterate(start, new Mapper<Integer, Integer>() |
| { |
| @Override |
| public Integer map(Integer element) |
| { |
| return element + delta; |
| } |
| }); |
| } |
| |
| /** |
| * A Worker factory; the returnedWorker adds the values to a provided collection. |
| */ |
| public static <T> Worker<T> addToCollection(final Collection<T> coll) |
| { |
| return new Worker<T>() |
| { |
| @Override |
| public void work(T value) |
| { |
| coll.add(value); |
| } |
| }; |
| } |
| |
| /** |
| * A Predicate factory for matching String elements with a given prefix. |
| * |
| * @since 5.3 |
| */ |
| public static Predicate<String> startsWith(String prefix) |
| { |
| return startsWith(prefix, false); |
| } |
| |
| /** |
| * As {@link #startsWith(String)}, but ignores case. |
| * |
| * @since 5.3 |
| */ |
| public static Predicate<String> startsWithIgnoringCase(String prefix) |
| { |
| return startsWith(prefix, true); |
| } |
| |
| /** |
| * @since 5.3 |
| */ |
| private static Predicate<String> startsWith(final String prefix, final boolean ignoreCase) |
| { |
| return new Predicate<String>() |
| { |
| @Override |
| public boolean accept(String element) |
| { |
| return element.regionMatches(ignoreCase, 0, prefix, 0, prefix.length()); |
| } |
| }; |
| } |
| |
| /** |
| * A Predicate factory for matching String elements with a given suffix. |
| * |
| * @since 5.3 |
| */ |
| public static Predicate<String> endsWith(String suffix) |
| { |
| return endsWith(suffix, false); |
| } |
| |
| /** |
| * As with {@link #endsWith(String)} but ignores case. |
| * |
| * @since 5.3 |
| */ |
| public static Predicate<String> endsWithIgnoringCase(String suffix) |
| { |
| return endsWith(suffix, true); |
| } |
| |
| /** |
| * @since 5.3 |
| */ |
| private static Predicate<String> endsWith(final String suffix, final boolean ignoreCase) |
| { |
| return new Predicate<String>() |
| { |
| @Override |
| public boolean accept(String element) |
| { |
| return element |
| .regionMatches(ignoreCase, element.length() - suffix.length(), suffix, 0, suffix.length()); |
| } |
| }; |
| } |
| |
| /** |
| * Creates a Comparator for the Tuples of a {@link ZippedFlow} that sorts the Tuple elements based on the first |
| * value in the Tuple. |
| * |
| * @since 5.3 |
| */ |
| public static <A extends Comparable<A>, B> Comparator<Tuple<A, B>> orderByFirst() |
| { |
| return new Comparator<Tuple<A, B>>() |
| { |
| @Override |
| public int compare(Tuple<A, B> o1, Tuple<A, B> o2) |
| { |
| return o1.first.compareTo(o2.first); |
| } |
| }; |
| } |
| |
| /** |
| * Creates a Comparator for the Tuples of a {@link ZippedFlow} that sorts the Tuple elements based on the first |
| * value in the Tuple. |
| * |
| * @since 5.3 |
| */ |
| public static <A, B extends Comparable<B>> Comparator<Tuple<A, B>> orderBySecond() |
| { |
| return new Comparator<Tuple<A, B>>() |
| { |
| @Override |
| public int compare(Tuple<A, B> o1, Tuple<A, B> o2) |
| { |
| return o1.second.compareTo(o2.second); |
| } |
| }; |
| } |
| |
| /** |
| * Inverts a predicate. |
| * |
| * @param delegate |
| * the predicate to invert |
| * @return a new predicate that is inverse to the existing predicate |
| * @since 5.3 |
| */ |
| public static <T> Predicate<T> not(final Predicate<? super T> delegate) |
| { |
| assert delegate != null; |
| |
| return new Predicate<T>() |
| { |
| @Override |
| public boolean accept(T element) |
| { |
| return !delegate.accept(element); |
| } |
| }; |
| } |
| |
| /** |
| * Combines two mappers into a composite mapping from type A to type C via type B. |
| * |
| * @param abMapper |
| * maps from A to B |
| * @param bcMapper |
| * maps from B to C |
| * @return mapper from A to C |
| */ |
| public static <A, B, C> Mapper<A, C> combine(final Mapper<A, B> abMapper, final Mapper<B, C> bcMapper) |
| { |
| assert abMapper != null; |
| assert bcMapper != null; |
| |
| return new Mapper<A, C>() |
| { |
| |
| @Override |
| public C map(A aElement) |
| { |
| B bElement = abMapper.map(aElement); |
| |
| return bcMapper.map(bElement); |
| } |
| |
| }; |
| } |
| |
| /** |
| * Combines any number of delegates as a logical and operation. Evaluation terminates |
| * with the first delegate predicate that returns false. |
| * |
| * @param delegates |
| * to evaluate |
| * @return combined delegate |
| * @since 5.3 |
| */ |
| public static <T> Predicate<T> and(final Predicate<? super T>... delegates) |
| { |
| return new Predicate<T>() |
| { |
| @Override |
| public boolean accept(T element) |
| { |
| for (Predicate<? super T> delegate : delegates) |
| { |
| if (!delegate.accept(element)) |
| return false; |
| } |
| |
| return true; |
| } |
| }; |
| } |
| |
| /** |
| * Combines any number of delegates as a logical or operation. Evaluation terminates |
| * with the first delegate predicate that returns true. |
| * |
| * @param delegates |
| * to evaluate |
| * @return combined delegate |
| * @since 5.3 |
| */ |
| public static <T> Predicate<T> or(final Predicate<? super T>... delegates) |
| { |
| return new Predicate<T>() |
| { |
| @Override |
| public boolean accept(T element) |
| { |
| for (Predicate<? super T> delegate : delegates) |
| { |
| if (delegate.accept(element)) |
| return true; |
| } |
| |
| return false; |
| } |
| }; |
| } |
| |
| /** |
| * Combines several compatible workers together into a composite. |
| * |
| * @since 5.3 |
| */ |
| public static <T> Worker<T> combine(final Worker<? super T>... delegates) |
| { |
| assert delegates.length > 0; |
| |
| return new Worker<T>() |
| { |
| @Override |
| public void work(T value) |
| { |
| for (Worker<? super T> delegate : delegates) |
| { |
| delegate.work(value); |
| } |
| } |
| }; |
| } |
| } |