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 }