package com.googlecode.totallylazy.predicates; import com.googlecode.totallylazy.functions.Function1; import com.googlecode.totallylazy.Sequence; import com.googlecode.totallylazy.Sequences; import com.googlecode.totallylazy.Unchecked; import com.googlecode.totallylazy.annotations.multimethod; import static com.googlecode.totallylazy.predicates.Predicates.instanceOf; import static com.googlecode.totallylazy.Sequences.one; public class OrPredicate<T> extends LogicalPredicate<T> { private final Sequence<Predicate<T>> predicates; private OrPredicate(Sequence<Predicate<T>> predicates) { this.predicates = predicates; } public static <T> LogicalPredicate<T> or(Iterable<? extends Predicate<? super T>> predicates) { Sequence<Predicate<T>> sequence = Sequences.sequence(predicates).<Predicate<T>>unsafeCast(). flatMap(OrPredicate.<T>asPredicates()); if (sequence.exists(instanceOf(AlwaysTrue.class))) return Predicates.alwaysTrue(); Sequence<Predicate<T>> collapsed = sequence. filter(instanceOf(AlwaysFalse.class).not()); if (collapsed.isEmpty()) return Predicates.alwaysFalse(); if (collapsed.size() == 1) return logicalPredicate(collapsed.head()); if (collapsed.forAll(instanceOf(Not.class))) return Predicates.not(Predicates.<T>and(sequence.<Not<T>>unsafeCast().map(Not.functions.<T>predicate()))); return new OrPredicate<T>(sequence); } public boolean matches(T value) { for (Predicate<? super T> predicate : predicates) { if (predicate.matches(value)) return true; } return false; } public Sequence<Predicate<T>> predicates() { return predicates; } @Override public int hashCode() { return 31 * predicates.hashCode(); } @multimethod public boolean equals(OrPredicate other) { return predicates.equals(other.predicates()); } @Override public String toString() { return predicates.toString("(", " or ", ")"); } private static <T> Function1<Predicate<T>, Iterable<Predicate<T>>> asPredicates() { return predicate -> predicate instanceof OrPredicate ? Unchecked.<OrPredicate<T>>cast(predicate).predicates() : one(predicate); } }