001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005// http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5.func;
014
015import java.util.Collection;
016import java.util.Comparator;
017import java.util.Iterator;
018import java.util.Map;
019import java.util.Map.Entry;
020
021/**
022 * Functional operations on collections with generics support. The core interface is {@link Flow} to
023 * which operations
024 * and transformations
025 * (in terms of {@link Predicate}s, {@link Mapper}s and {@link Reducer}s) to create new Flows. Flows
026 * are initially
027 * created
028 * using {@link #flow(Collection)} and {@link #flow(Object...)}.
029 *
030 * 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
031 * Predicate, Mapper and Reducer factories. A good development pattern for applications is to provide a similar,
032 * application-specific, set of such factories.
033 *
034 * @since 5.2.0
035 */
036@SuppressWarnings("all")
037public class F
038{
039    final static Flow<?> EMPTY_FLOW = new EmptyFlow();
040
041    @SuppressWarnings("unchecked")
042    static <T> Flow<T> emptyFlow()
043    {
044        return (Flow<T>) EMPTY_FLOW;
045    }
046
047    /**
048     * A Predicate factory for equality of an element from a flow against a specified
049     * value.
050     */
051    public static <T> Predicate<T> eql(final T value)
052    {
053        return new Predicate<T>()
054        {
055            @Override
056            public boolean accept(T element)
057            {
058                return element.equals(value);
059            }
060        };
061    }
062
063    /**
064     * Predicate that returns true if the provided string is blank (null or all whitespace).
065     */
066    public static Predicate<String> IS_BLANK = new Predicate<String>()
067    {
068        @Override
069        public boolean accept(String element)
070        {
071            return element == null || element.trim().length() == 0;
072        }
073    };
074
075    /**
076     * A Predicate factory for comparison of a Comparable element from a flow against a fixed value.
077     */
078    public static <T extends Comparable<T>> Predicate<T> eq(final T value)
079    {
080        return new Predicate<T>()
081        {
082            @Override
083            public boolean accept(T element)
084            {
085                return element.compareTo(value) == 0;
086            }
087        };
088    }
089
090    /**
091     * A Predicate factory for comparison of a Comparable element against a fixed value.
092     */
093    public static <T extends Comparable<T>> Predicate<T> neq(final T value)
094    {
095        return new Predicate<T>()
096        {
097            @Override
098            public boolean accept(T object)
099            {
100                return object.compareTo(value) != 0;
101            }
102        };
103    }
104
105    /**
106     * A Predicate factory for comparison of a Comparable against a fixed value; true
107     * if the flow element is greater than the provided value.
108     */
109    public static <T extends Comparable<T>> Predicate<T> gt(final T value)
110    {
111        return new Predicate<T>()
112        {
113            @Override
114            public boolean accept(T element)
115            {
116                return element.compareTo(value) > 0;
117            }
118        };
119    }
120
121    /**
122     * A Predicate factory for comparison of a Comparable against a fixed value; true
123     * if the flow element is greater than or equal to the value.
124     */
125    public static <T extends Comparable<T>> Predicate<T> gteq(final T value)
126    {
127        return new Predicate<T>()
128        {
129            @Override
130            public boolean accept(T element)
131            {
132                return element.compareTo(value) >= 0;
133            }
134        };
135    }
136
137    /**
138     * A Predicate factory for comparison of a Comparable against a fixed value; true
139     * if the element is less than the value.
140     */
141    public static <T extends Comparable<T>> Predicate<T> lt(T value)
142    {
143        return not(gteq(value));
144    }
145
146    /**
147     * A Predicate factory for comparison of a Comprable element against a fixed value; true
148     * if the element is less than or equal to the value.
149     */
150    public static <T extends Comparable<T>> Predicate<T> lteq(T value)
151    {
152        return not(gt(value));
153    }
154
155    /**
156     * A Predicate factory; returns true if the value from the Flow is null.
157     */
158    public static <T> Predicate<T> isNull()
159    {
160        return new Predicate<T>()
161        {
162            @Override
163            public boolean accept(T element)
164            {
165                return element == null;
166            }
167        };
168    }
169
170    /**
171     * A Predicate factory; returns true if the value from the Flow is not null.
172     */
173    public static <T> Predicate<T> notNull()
174    {
175        return not(isNull());
176    }
177
178    /**
179     * A Mapper factory that gets the string value of the flow value using {@link String#valueOf(Object)}.
180     */
181    public static <T> Mapper<T, String> stringValueOf()
182    {
183        return new Mapper<T, String>()
184        {
185            @Override
186            public String map(T value)
187            {
188                return String.valueOf(value);
189            }
190        };
191    }
192
193    /**
194     * A Mapper factory; the returned Mapper ignores its input value and always returns a
195     * predetermined result.
196     */
197    public static <S, T> Mapper<S, T> always(final T fixedResult)
198    {
199        return new Mapper<S, T>()
200        {
201            @Override
202            public T map(S input)
203            {
204                return fixedResult;
205            }
206        };
207    }
208
209    /**
210     * A Mapper factory that combines a Predicate with two {@link Mapper}s; evaluating the predicate
211     * selects one of the two mappers.
212     *
213     * @param predicate
214     *         evaluated to selected a coercion
215     * @param ifAccepted
216     *         used when predicate evaluates to true
217     * @param ifRejected
218     *         used when predicate evaluates to false
219     */
220    public static <S, T> Mapper<S, T> select(final Predicate<? super S> predicate, final Mapper<S, T> ifAccepted,
221                                             final Mapper<S, T> ifRejected)
222    {
223        assert predicate != null;
224        assert ifAccepted != null;
225        assert ifRejected != null;
226
227        return new Mapper<S, T>()
228        {
229            @Override
230            public T map(S input)
231            {
232                Mapper<S, T> active = predicate.accept(input) ? ifAccepted : ifRejected;
233
234                return active.map(input);
235            }
236        };
237    }
238
239    /**
240     * Override of {@link #select(Predicate, Mapper, Mapper)} where rejected values are replaced
241     * with null.
242     */
243    public static <S, T> Mapper<S, T> select(Predicate<? super S> predicate, Mapper<S, T> ifAccepted)
244    {
245        return select(predicate, ifAccepted, (T) null);
246    }
247
248    /**
249     * Override of {@link #select(Predicate, Mapper)} where rejected values are replaced with a
250     * fixed value.
251     */
252    public static <S, T> Mapper<S, T> select(Predicate<? super S> predicate, Mapper<S, T> ifAccepted, T ifRejectedValue)
253    {
254        Mapper<S, T> rejectedMapper = always(ifRejectedValue);
255
256        return select(predicate, ifAccepted, rejectedMapper);
257    }
258
259    /**
260     * A Mapper factory; the Mapper returns the the flow value unchanged.
261     */
262    public static <S> Mapper<S, S> identity()
263    {
264        return new Mapper<S, S>()
265        {
266            @Override
267            public S map(S input)
268            {
269                return input;
270            }
271        };
272    }
273
274    /**
275     * Allows a Mapper that maps to boolean to be used as a Predicate.
276     */
277    public static <S> Predicate<S> toPredicate(final Mapper<S, Boolean> mapper)
278    {
279        assert mapper != null;
280
281        return new Predicate<S>()
282        {
283            @Override
284            public boolean accept(S object)
285            {
286                return mapper.map(object);
287            }
288        };
289    }
290
291    /**
292     * A Reducer that operates on a Flow of Integers and is used to sum the values.
293     */
294    public static Reducer<Integer, Integer> SUM_INTS = new Reducer<Integer, Integer>()
295    {
296        @Override
297        public Integer reduce(Integer accumulator, Integer value)
298        {
299            return accumulator + value;
300        }
301    };
302
303    /**
304     * A two-input Mapper used to add the values from two Flows of Integers into a Flow of Integer
305     * sums.
306     */
307    public static Mapper2<Integer, Integer, Integer> ADD_INTS = new Mapper2<Integer, Integer, Integer>()
308    {
309        @Override
310        public Integer map(Integer first, Integer second)
311        {
312            return first + second;
313        }
314    };
315
316    /**
317     * Extracts the values from the collection to form a {@link Flow}. The Collection
318     * may change after the Flow is created without affecting the Flow.
319     */
320    public static <T> Flow<T> flow(Collection<T> values)
321    {
322        assert values != null;
323
324        if (values.isEmpty())
325            return emptyFlow();
326
327        return new ArrayFlow<T>(values);
328    }
329
330    /**
331     * Creates a new Flow from the values. You should not change the values array
332     * after invoking this method (i.e., no defensive copy of the values is made).
333     */
334    public static <T> Flow<T> flow(T... values)
335    {
336        if (values.length == 0)
337            return emptyFlow();
338
339        return new ArrayFlow<T>(values);
340    }
341
342    /**
343     * Creates a lazy Flow from the {@link Iterator} obtained from the iterable. The Flow
344     * will be threadsafe as long as the iterable yields a new Iterator on each invocation <em>and</em> the underlying
345     * iterable object is not modified while the Flow is evaluating.
346     * In other words, not extremely threadsafe.
347     */
348    public static <T> Flow<T> flow(Iterable<T> iterable)
349    {
350        assert iterable != null;
351
352        return flow(iterable.iterator());
353    }
354
355    /**
356     * Creates a lazy Flow from the {@link Iterator}. The Flow will be threadsafe as long as the underlying iterable
357     * object is not modified while the Flow is evaluating. In other words, not extremely threadsafe.
358     *
359     * @since 5.3
360     */
361    public static <T> Flow<T> flow(Iterator<T> iterator)
362    {
363        return lazy(new LazyIterator<T>(iterator));
364    }
365
366    /**
367     * Creates a ZippedFlow from the provided map; the order of the tuples in the ZippedFlow is defined
368     * by the iteration order of the map entries.
369     *
370     * @param <A>
371     *         type of key and first tuple value
372     * @param <B>
373     *         type of value and second tuple value
374     * @param map
375     *         source of tuples
376     * @return zipped flow created from map
377     * @since 5.3
378     */
379    public static <A, B> ZippedFlow<A, B> zippedFlow(Map<A, B> map)
380    {
381        assert map != null;
382
383        Flow<Tuple<A, B>> tuples = F.flow(map.entrySet()).map(new Mapper<Map.Entry<A, B>, Tuple<A, B>>()
384        {
385            @Override
386            public Tuple<A, B> map(Entry<A, B> element)
387            {
388                return Tuple.create(element.getKey(), element.getValue());
389            }
390        });
391
392        return ZippedFlowImpl.create(tuples);
393    }
394
395    /**
396     * Creates a lazy Flow that returns integers in the given range. The range starts
397     * with the lower value and counts by 1 up to the upper range (which is not part of
398     * the Flow). If lower equals upper, the Flow is empty. If upper is less than lower,
399     * the Flow counts down instead.
400     *
401     * @param lower
402     *         start of range (inclusive)
403     * @param upper
404     *         end of range (exclusive)
405     */
406    public static Flow<Integer> range(int lower, int upper)
407    {
408        if (lower == upper)
409            return F.emptyFlow();
410
411        if (lower < upper)
412            return lazy(new LazyRange(lower, upper, 1));
413
414        return lazy(new LazyRange(lower, upper, -1));
415    }
416
417    /**
418     * Creates a {@link Flow} from a {@linkplain LazyFunction lazy function}.
419     */
420    public static <T> Flow<T> lazy(LazyFunction<T> function)
421    {
422        assert function != null;
423
424        return new LazyFlow<T>(function);
425    }
426
427    private static <T> LazyFunction<T> toLazyFunction(final T currentValue, final Mapper<T, T> function)
428    {
429        return new LazyFunction<T>()
430        {
431            @Override
432            public LazyContinuation<T> next()
433            {
434                final T nextValue = function.map(currentValue);
435
436                return new LazyContinuation<T>(nextValue, toLazyFunction(nextValue, function));
437            }
438        };
439    }
440
441    /**
442     * Creates an infinite lazy flow from an initial value and a function to map from the current value to the
443     * next value.
444     *
445     * @param initial
446     *         initial value in flow
447     * @param function
448     *         maps from current value in flow to next value in flow
449     * @return lazy flow
450     */
451    public static <T> Flow<T> iterate(final T initial, final Mapper<T, T> function)
452    {
453        LazyFunction<T> head = new LazyFunction<T>()
454        {
455            @Override
456            public LazyContinuation<T> next()
457            {
458                return new LazyContinuation<T>(initial, toLazyFunction(initial, function));
459            }
460        };
461
462        return lazy(head);
463    }
464
465    /**
466     * Creates an <em>infinite</em> series of numbers.
467     *
468     * Attempting to get the {@linkplain Flow#count()} of the series will form an infinite loop.
469     */
470    public static Flow<Integer> series(int start, final int delta)
471    {
472        return iterate(start, new Mapper<Integer, Integer>()
473        {
474            @Override
475            public Integer map(Integer element)
476            {
477                return element + delta;
478            }
479        });
480    }
481
482    /**
483     * A Worker factory; the returnedWorker adds the values to a provided collection.
484     */
485    public static <T> Worker<T> addToCollection(final Collection<T> coll)
486    {
487        return new Worker<T>()
488        {
489            @Override
490            public void work(T value)
491            {
492                coll.add(value);
493            }
494        };
495    }
496
497    /**
498     * A Predicate factory for matching String elements with a given prefix.
499     *
500     * @since 5.3
501     */
502    public static Predicate<String> startsWith(String prefix)
503    {
504        return startsWith(prefix, false);
505    }
506
507    /**
508     * As {@link #startsWith(String)}, but ignores case.
509     *
510     * @since 5.3
511     */
512    public static Predicate<String> startsWithIgnoringCase(String prefix)
513    {
514        return startsWith(prefix, true);
515    }
516
517    /**
518     * @since 5.3
519     */
520    private static Predicate<String> startsWith(final String prefix, final boolean ignoreCase)
521    {
522        return new Predicate<String>()
523        {
524            @Override
525            public boolean accept(String element)
526            {
527                return element.regionMatches(ignoreCase, 0, prefix, 0, prefix.length());
528            }
529        };
530    }
531
532    /**
533     * A Predicate factory for matching String elements with a given suffix.
534     *
535     * @since 5.3
536     */
537    public static Predicate<String> endsWith(String suffix)
538    {
539        return endsWith(suffix, false);
540    }
541
542    /**
543     * As with {@link #endsWith(String)} but ignores case.
544     *
545     * @since 5.3
546     */
547    public static Predicate<String> endsWithIgnoringCase(String suffix)
548    {
549        return endsWith(suffix, true);
550    }
551
552    /**
553     * @since 5.3
554     */
555    private static Predicate<String> endsWith(final String suffix, final boolean ignoreCase)
556    {
557        return new Predicate<String>()
558        {
559            @Override
560            public boolean accept(String element)
561            {
562                return element
563                        .regionMatches(ignoreCase, element.length() - suffix.length(), suffix, 0, suffix.length());
564            }
565        };
566    }
567
568    /**
569     * Creates a Comparator for the Tuples of a {@link ZippedFlow} that sorts the Tuple elements based on the first
570     * value in the Tuple.
571     *
572     * @since 5.3
573     */
574    public static <A extends Comparable<A>, B> Comparator<Tuple<A, B>> orderByFirst()
575    {
576        return new Comparator<Tuple<A, B>>()
577        {
578            @Override
579            public int compare(Tuple<A, B> o1, Tuple<A, B> o2)
580            {
581                return o1.first.compareTo(o2.first);
582            }
583        };
584    }
585
586    /**
587     * Creates a Comparator for the Tuples of a {@link ZippedFlow} that sorts the Tuple elements based on the first
588     * value in the Tuple.
589     *
590     * @since 5.3
591     */
592    public static <A, B extends Comparable<B>> Comparator<Tuple<A, B>> orderBySecond()
593    {
594        return new Comparator<Tuple<A, B>>()
595        {
596            @Override
597            public int compare(Tuple<A, B> o1, Tuple<A, B> o2)
598            {
599                return o1.second.compareTo(o2.second);
600            }
601        };
602    }
603
604    /**
605     * Inverts a predicate.
606     *
607     * @param delegate
608     *         the predicate to invert
609     * @return a new predicate that is inverse to the existing predicate
610     * @since 5.3
611     */
612    public static <T> Predicate<T> not(final Predicate<? super T> delegate)
613    {
614        assert delegate != null;
615
616        return new Predicate<T>()
617        {
618            @Override
619            public boolean accept(T element)
620            {
621                return !delegate.accept(element);
622            }
623        };
624    }
625
626    /**
627     * Combines two mappers into a composite mapping from type A to type C via type B.
628     *
629     * @param abMapper
630     *         maps from A to B
631     * @param bcMapper
632     *         maps from B to C
633     * @return mapper from A to C
634     */
635    public static <A, B, C> Mapper<A, C> combine(final Mapper<A, B> abMapper, final Mapper<B, C> bcMapper)
636    {
637        assert abMapper != null;
638        assert bcMapper != null;
639
640        return new Mapper<A, C>()
641        {
642
643            @Override
644            public C map(A aElement)
645            {
646                B bElement = abMapper.map(aElement);
647
648                return bcMapper.map(bElement);
649            }
650
651        };
652    }
653
654    /**
655     * Combines any number of delegates as a logical and operation. Evaluation terminates
656     * with the first delegate predicate that returns false.
657     *
658     * @param delegates
659     *         to evaluate
660     * @return combined delegate
661     * @since 5.3
662     */
663    public static <T> Predicate<T> and(final Predicate<? super T>... delegates)
664    {
665        return new Predicate<T>()
666        {
667            @Override
668            public boolean accept(T element)
669            {
670                for (Predicate<? super T> delegate : delegates)
671                {
672                    if (!delegate.accept(element))
673                        return false;
674                }
675
676                return true;
677            }
678        };
679    }
680
681    /**
682     * Combines any number of delegates as a logical or operation. Evaluation terminates
683     * with the first delegate predicate that returns true.
684     *
685     * @param delegates
686     *         to evaluate
687     * @return combined delegate
688     * @since 5.3
689     */
690    public static <T> Predicate<T> or(final Predicate<? super T>... delegates)
691    {
692        return new Predicate<T>()
693        {
694            @Override
695            public boolean accept(T element)
696            {
697                for (Predicate<? super T> delegate : delegates)
698                {
699                    if (delegate.accept(element))
700                        return true;
701                }
702
703                return false;
704            }
705        };
706    }
707
708    /**
709     * Combines several compatible workers together into a composite.
710     *
711     * @since 5.3
712     */
713    public static <T> Worker<T> combine(final Worker<? super T>... delegates)
714    {
715        assert delegates.length > 0;
716
717        return new Worker<T>()
718        {
719            @Override
720            public void work(T value)
721            {
722                for (Worker<? super T> delegate : delegates)
723                {
724                    delegate.work(value);
725                }
726            }
727        };
728    }
729}