View Javadoc
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  }