1 package epam.flipflop;
2
3 import java.util.function.Predicate;
4
5 import static java.util.Objects.requireNonNull;
6
7 /**
8 * A predicate that emulates flip-flop logic similar to the two-dots flip-flop in Perl or Ruby.
9 * The predicate takes two input predicates, a start condition, and an end condition.
10 * When the start condition is met, the predicate returns true for all subsequent inputs
11 * until the end condition is met, at which point it returns true and resets its internal state.
12 *
13 * @param <T> The type of the input to the predicate
14 */
15 public class FlipFlopPredicate<T> implements Predicate<T> {
16 private final Predicate<? super T> startPredicate;
17 private final Predicate<? super T> endPredicate;
18 private boolean state;
19
20 /**
21 * Constructs a new FlipFlopPredicate with the given start and end conditions.
22 *
23 * @param startCondition The predicate that represents the start condition
24 * @param endCondition The predicate that represents the end condition
25 */
26 public FlipFlopPredicate(Predicate<T> startCondition, Predicate<T> endCondition) {
27 this.startPredicate = requireNonNull(startCondition);
28 this.endPredicate = requireNonNull(endCondition);
29 }
30
31 /**
32 * Evaluates this predicate on the given argument.
33 *
34 * @param value The input argument
35 * @return {@code true} if the input matches the flip-flop logic, otherwise {@code false}
36 */
37 @Override
38 public boolean test(final T value) {
39 var result = state || startPredicate.test(value);
40 state = result && !endPredicate.test(value);
41 return result;
42 }
43 }