text: /*
   * Copyright (c) 2018 Goldman Sachs.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * and Eclipse Distribution License v. 1.0 which accompany this distribution.
   * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
   * and the Eclipse Distribution License is available at
   * http://www.eclipse.org/org/documents/edl-v10.php.
   */
  
  package org.eclipse.collections.impl.block.factory;
  
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.Set;
  
  import org.eclipse.collections.api.block.function.Function;
  import org.eclipse.collections.api.block.function.Function2;
  import org.eclipse.collections.api.block.predicate.Predicate;
  import org.eclipse.collections.api.block.predicate.Predicate2;
  import org.eclipse.collections.api.set.SetIterable;
  import org.eclipse.collections.impl.block.predicate.checked.CheckedPredicate;
  import org.eclipse.collections.impl.block.predicate.checked.ThrowingPredicate;
  import org.eclipse.collections.impl.set.mutable.UnifiedSet;
  import org.eclipse.collections.impl.utility.Iterate;
  
  /**
   * The Predicates class can be used to build common Predicates to be used by methods such
   * as detect:, select: and reject: on the Iterate, MapIterate, and ArrayIterate classes. Predicates supports
   * equals, not equals, less than, greater than, less than or equal to, greater than or equal to, in, not in
   * and, or, and several other Predicate type operations.
   */
  public abstract class Predicates<T>
          implements Predicate<T>
  {
      private static final long serialVersionUID = 1L;
      private static final Predicates<Object> ALWAYS_TRUE = new AlwaysTrue();
      private static final Predicates<Object> ALWAYS_FALSE = new AlwaysFalse();
      private static final Predicates<Object> IS_NULL = new IsNull();
      private static final Predicates<Object> NOT_NULL = new NotNull();
      private static final int SMALL_COLLECTION_THRESHOLD = 6;
  
      public static <T> Predicates<T> adapt(Predicate<T> predicate)
      {
          return new PredicateAdapter<>(predicate);
      }
  
      /**
       * Allows a Java 8 lambda or method reference to be used in a method taking a predicate without requiring an actual cast.
       * This method can be used in places where two or more method overloads could apply when used with a lambda or method
       * reference (e.g. removeIf).
       */
      public static <T> Predicate<T> cast(Predicate<T> predicate)
      {
          return predicate;
      }
  
      /**
       * Allows a lambda or anonymous inner class that needs to throw a checked exception to be safely wrapped as a
       * Predicate that will throw a RuntimeException, wrapping the checked exception that is the cause.
       */
      public static <T> Predicate<T> throwing(ThrowingPredicate<T> throwingPredicate)
      {
          return new ThrowingPredicateAdapter<>(throwingPredicate);
      }
  
      /**
       * Allows a lambda or anonymous inner class that needs to throw a checked exception to be safely wrapped as a
       * Predicate that will throw a user specified RuntimeException based on the provided function. The function
       * is passed the current element and the checked exception that was thrown as context arguments.
       */
      public static <T> Predicate<T> throwing(
              ThrowingPredicate<T> throwingPredicate,
              Function2<T, ? super Throwable, ? extends RuntimeException> rethrow)
      {
          return each ->
          {
              try
              {
                  return throwingPredicate.safeAccept(each);
              }
              catch (RuntimeException e)
              {
                  throw e;
              }
              catch (Throwable t)
              {
                  throw rethrow.value(each, t);
              }
          };
      }
  
      public static <P, T> Predicate<T> bind(Predicate2<? super T, ? super P> predicate, P parameter)
      {
          return new BindPredicate2<>(predicate, parameter);
      }
  
      public static <T> Predicate<T> synchronizedEach(Predicate<T> predicate)
      {
          return new SynchronizedPredicate<>(predicate);
      }
  
      public static <T> Predicates<T> or(Iterable<? extends Predicate<? super T>> predicates)
      {
          return new OrIterablePredicate<>(predicates);
      }
  
      public static <T> Predicates<T> or(Predicate<? super T> predicate1, Predicate<? super T> predicate2)
      {
          return new OrPredicate<>(predicate1, predicate2);
      }
  
      public static <T> Predicates<T> or(Predicate<? super T>... predicates)
      {
          return new OrIterablePredicate<T>(Arrays.asList(predicates));
      }
  
      public static <T> Predicates<T> and(Iterable<? extends Predicate<? super T>> predicates)
      {
          return new AndIterablePredicate<>(predicates);
      }
  
      public static <T> Predicates<T> and(Predicate<? super T> predicate1, Predicate<? super T> predicate2)
      {
          return new AndPredicate<>(predicate1, predicate2);
      }
  
      public static <T> Predicates<T> and(Predicate<? super T>... predicates)
      {
          return new AndIterablePredicate<T>(Arrays.asList(predicates));
      }
  
      public static <T> Predicates<T> not(Predicate<T> predicate)
      {
          return new NotPredicate<>(predicate);
      }
  
      public Predicates<T> not()
      {
          return Predicates.not(this);
      }
  
      public static <T> Predicates<T> neither(Predicate<? super T> operation1, Predicate<? super T> operation2)
      {
          return new NeitherPredicate<>(operation1, operation2);
      }
  
      public static <T> Predicates<T> noneOf(Predicate<? super T>... operations)
      {
          return new NoneOfIterablePredicate<T>(Arrays.asList(operations));
      }
  
      public static <T> Predicates<T> noneOf(Iterable<? extends Predicate<? super T>> operations)
      {
          return new NoneOfIterablePredicate<>(operations);
      }
  
      /**
       * Tests for equality.
       */
      public static Predicates<Object> equal(Object object)
      {
          if (object == null)
          {
              return Predicates.isNull();
          }
          return new EqualPredicate(object);
      }
  
      /**
       * Creates a predicate which returns true if an object passed to accept method is within the range, inclusive
       * of the from and to values.
       */
      public static <T extends Comparable<? super T>> Predicates<T> betweenInclusive(T from, T to)
      {
          Predicates.failIfDifferentTypes(from, to);
          return new BetweenInclusive<>(from, to);
      }
  
      private static void failIfDifferentTypes(Object from, Object to)
      {
          if (!from.getClass().equals(to.getClass()))
          {
              throw new IllegalArgumentException("Trying to do a between comparison with two different types "
                      + from.getClass()
                      + ':'
                      + to.getClass());
          }
      }
  
      /**
       * Creates a predicate which returns true if an object passed to accept method is within the range, exclusive
       * of the from and to values.
       */
      public static <T extends Comparable<? super T>> Predicates<T> betweenExclusive(T from, T to)
      {
          Predicates.failIfDifferentTypes(from, to);
          return new BetweenExclusive<>(from, to);
      }
  
      /**
       * Creates a predicate which returns true if an object passed to accept method is within the range, inclusive
       * of the from and exclusive from the to value.
       */
      public static <T extends Comparable<? super T>> Predicates<T> betweenInclusiveFrom(T from, T to)
      {
          Predicates.failIfDifferentTypes(from, to);
          return new BetweenInclusiveFrom<>(from, to);
      }
  
      /**
       * Creates a predicate which returns true if an object passed to accept method is within the range, exclusive
       * of the from and inclusive of the to value.
       */
      public static <T extends Comparable<? super T>> Predicates<T> betweenInclusiveTo(T from, T to)
      {
          Predicates.failIfDifferentTypes(from, to);
          return new BetweenInclusiveTo<>(from, to);
      }
  
      /**
       * Creates a predicate which returns true if an object passed to accept method is contained in the iterable.
       */
      public static Predicates<Object> in(Iterable<?> iterable)
      {
          if (iterable instanceof SetIterable<?>)
          {
              return new InSetIterablePredicate((SetIterable<?>) iterable);
          }
          if (iterable instanceof Set<?>)
          {
              return new InSetPredicate((Set<?>) iterable);
          }
          if (iterable instanceof Collection<?> && ((Collection<?>) iterable).size() <= SMALL_COLLECTION_THRESHOLD)
          {
              return new InCollectionPredicate((Collection<?>) iterable);
          }
          return new InSetIterablePredicate(UnifiedSet.newSet(iterable));
      }
  
      public static Predicates<Object> in(Object... array)
      {
          if (array.length <= SMALL_COLLECTION_THRESHOLD)
          {
              return new InCollectionPredicate(Arrays.asList(array));
          }
          return new InSetIterablePredicate(UnifiedSet.newSetWith(array));
      }
  
      /**
       * Creates a predicate which returns true if an attribute selected from an object passed to accept method
       * is contained in the iterable.
       */
      public static <T> Predicates<T> attributeIn(
              Function<? super T, ?> function,
              Iterable<?> iterable)
      {
          return new AttributePredicate<>(function, Predicates.in(iterable));
      }
  
      public static <T, V extends Comparable<? super V>> Predicates<T> attributeBetweenInclusive(
              Function<? super T, ? extends V> function,
              V from,
              V to)
      {
          return new AttributePredicate<>(function, Predicates.betweenInclusive(from, to));
      }
  
      public static <T, V extends Comparable<? super V>> Predicates<T> attributeBetweenExclusive(
              Function<? super T, ? extends V> function,
              V from,
              V to)
      {
          return new AttributePredicate<>(function, Predicates.betweenExclusive(from, to));
      }
  
      public static <T, V extends Comparable<? super V>> Predicates<T> attributeBetweenInclusiveFrom(
              Function<? super T, ? extends V> function,
              V from,
              V to)
      {
          return new AttributePredicate<>(function, Predicates.betweenInclusiveFrom(from, to));
      }
  
      public static <T, V extends Comparable<? super V>> Predicates<T> attributeBetweenInclusiveTo(
              Function<? super T, ? extends V> function,
              V from,
              V to)
      {
          return new AttributePredicate<>(function, Predicates.betweenInclusiveTo(from, to));
      }
  
      /**
       * Creates a predicate which returns true if an object passed to accept method is not contained in
       * the iterable.
       */
      public static Predicates<Object> notIn(Iterable<?> iterable)
      {
          if (iterable instanceof SetIterable<?>)
          {
              return new NotInSetIterablePredicate((SetIterable<?>) iterable);
          }
          if (iterable instanceof Set<?>)
          {
              return new NotInSetPredicate((Set<?>) iterable);
          }
          if (iterable instanceof Collection<?> && ((Collection<?>) iterable).size() <= SMALL_COLLECTION_THRESHOLD)
          {
              return new NotInCollectionPredicate((Collection<?>) iterable);
          }
          return new NotInSetIterablePredicate(UnifiedSet.newSet(iterable));
      }
  
      public static Predicates<Object> notIn(Object... array)
      {
          if (array.length <= SMALL_COLLECTION_THRESHOLD)
          {
              return new NotInCollectionPredicate(Arrays.asList(array));
          }
          return new NotInSetIterablePredicate(UnifiedSet.newSetWith(array));
      }
  
      /**
       * Creates a predicate which returns true if an attribute selected from an object passed to accept method
       * is not contained in the iterable.
       */
      public static <T> Predicates<T> attributeNotIn(
              Function<? super T, ?> function,
              Iterable<?> iterable)
      {
          return new AttributePredicate<>(function, Predicates.notIn(iterable));
      }
  
      public static <T extends Comparable<? super T>> Predicates<T> lessThan(T object)
      {
          return new LessThanPredicate<>(object);
      }
  
      public static <T, V extends Comparable<? super V>> Predicates<T> attributeLessThan(
              Function<? super T, ? extends V> function,
              V object)
      {
          return new AttributePredicate<>(function, new LessThanPredicate<>(object));
      }
  
      public static <T extends Comparable<? super T>> Predicates<T> lessThanOrEqualTo(T object)
      {
          return new LessThanOrEqualPredicate<>(object);
      }
  
      public static <T, V extends Comparable<? super V>> Predicates<T> attributeLessThanOrEqualTo(
              Function<? super T, ? extends V> function,
              V object)
      {
          return new AttributePredicate<>(function, new LessThanOrEqualPredicate<>(object));
      }
  
      public static <T extends Comparable<? super T>> Predicates<T> greaterThan(T object)
      {
          return new GreaterThanPredicate<>(object);
      }
  
      public static <T, V extends Comparable<? super V>> Predicates<T> attributeGreaterThan(
              Function<? super T, ? extends V> function,
              V object)
      {
          return new AttributePredicate<>(function, new GreaterThanPredicate<>(object));
      }
  
      public static <T extends Comparable<? super T>> Predicates<T> greaterThanOrEqualTo(T object)
      {
          return new GreaterThanOrEqualPredicate<>(object);
      }
  
      public static <T, V extends Comparable<? super V>> Predicates<T> attributeGreaterThanOrEqualTo(
              Function<? super T, ? extends V> function,
              V object)
      {
          return new AttributePredicate<>(function, new GreaterThanOrEqualPredicate<>(object));
      }
  
      public static <T, V> Predicates<T> attributePredicate(
              Function<? super T, ? extends V> function,
              Predicate<? super V> predicate)
      {
          return new AttributePredicate<>(function, predicate);
      }
  
      public static <T> Predicates<T> attributeEqual(
              Function<? super T, ?> function,
              Object object)
      {
          return new AttributePredicate<>(function, Predicates.equal(object));
      }
  
      public static <T> Predicates<Iterable<T>> anySatisfy(Predicate<? super T> predicate)
      {
          return new AnySatisfy<>(predicate);
      }
  
      public static <T> Predicates<Iterable<T>> allSatisfy(Predicate<? super T> predicate)
      {
          return new AllSatisfy<>(predicate);
      }
  
      public static <T> Predicates<Iterable<T>> noneSatisfy(Predicate<? super T> predicate)
      {
          return new NoneSatisfy<>(predicate);
      }
  
      public static <T, V> Predicates<T> attributeAnySatisfy(
              Function<? super T, ? extends Iterable<V>> function,
              Predicate<? super V> predicate)
      {
          return Predicates.attributePredicate(function, Predicates.anySatisfy(predicate));
      }
  
      public static <T, V> Predicates<T> attributeAllSatisfy(
              Function<? super T, ? extends Iterable<V>> function,
              Predicate<? super V> predicate)
      {
          return Predicates.attributePredicate(function, Predicates.allSatisfy(predicate));
      }
  
      public static <T, V> Predicates<T> attributeNoneSatisfy(
              Function<? super T, ? extends Iterable<V>> function,
              Predicate<? super V> predicate)
      {
          return Predicates.attributePredicate(function, Predicates.noneSatisfy(predicate));
      }
  
      public static Predicates<Object> notEqual(Object object)
      {
          if (object == null)
          {
              return Predicates.notNull();
          }
          return new NotEqualPredicate(object);
      }
  
      public static <T> Predicates<T> ifTrue(Function<? super T, Boolean> function)
      {
          return new AttributeTrue<>(function);
      }
  
      public static <T> Predicates<T> ifFalse(Function<? super T, Boolean> function)
      {
          return new AttributeFalse<>(function);
      }
  
      public static <T> Predicates<T> attributeNotEqual(
              Function<? super T, ?> function,
              Object object)
      {
          return new AttributePredicate<>(function, Predicates.notEqual(object));
      }
  
      public static Predicates<Object> isNull()
      {
          return IS_NULL;
      }
  
      public static <T> Predicates<T> attributeIsNull(Function<? super T, ?> function)
      {
          return new AttributePredicate<>(function, Predicates.isNull());
      }
  
      public static Predicates<Object> notNull()
      {
          return NOT_NULL;
      }
  
      public static <T> Predicates<T> attributeNotNull(Function<? super T, ?> function)
      {
          return new AttributePredicate<>(function, Predicates.notNull());
      }
  
      public static Predicates<Object> sameAs(Object object)
      {
          return new IdentityPredicate(object);
      }
  
      public static Predicates<Object> notSameAs(Object object)
      {
          return new NotIdentityPredicate(object);
      }
  
      public static Predicates<Object> instanceOf(Class<?> clazz)
      {
          return new InstanceOfPredicate(clazz);
      }
  
      public static Predicates<Object> assignableFrom(Class<?> clazz)
      {
          return new AssignableFromPredicate(clazz);
      }
  
      public static Predicates<Object> notInstanceOf(Class<?> clazz)
      {
          return new NotInstanceOfPredicate(clazz);
      }
  
      public static Predicates<Object> alwaysTrue()
      {
          return ALWAYS_TRUE;
      }
  
      public static Predicates<Object> alwaysFalse()
      {
          return ALWAYS_FALSE;
      }
  
      public Predicates<T> and(Predicate<? super T> op)
      {
          return Predicates.and(this, op);
      }
  
      public Predicates<T> or(Predicate<? super T> op)
      {
          return Predicates.or(this, op);
      }
  
      public static Predicates<Class<?>> subClass(Class<?> aClass)
      {
          return new SubclassPredicate(aClass);
      }
  
      public static Predicates<Class<?>> superClass(Class<?> aClass)
      {
          return new SuperclassPredicate(aClass);
      }
  
      private static final class PredicateAdapter<T>
              extends Predicates<T>
      {
          private static final long serialVersionUID = 1L;
          private final Predicate<T> predicate;
  
          private PredicateAdapter(Predicate<T> newPredicate)
          {
              this.predicate = newPredicate;
          }
  
          @Override
          public boolean accept(T o)
          {
              return this.predicate.accept(o);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.adapt(" + this.predicate + ')';
          }
      }
  
      protected static class AttributePredicate<T, V> extends Predicates<T>
      {
          private static final long serialVersionUID = 1L;
          protected final Function<? super T, ? extends V> function;
          protected final Predicate<? super V> predicate;
  
          protected AttributePredicate(
                  Function<? super T, ? extends V> newFunction,
                  Predicate<? super V> newPredicate)
          {
              this.function = newFunction;
              this.predicate = newPredicate;
          }
  
          @Override
          public boolean accept(T anObject)
          {
              return this.predicate.accept(this.function.valueOf(anObject));
          }
  
          @Override
          public String toString()
          {
              return "Predicates.attributePredicate("
                      + this.function
                      + ", "
                      + this.predicate
                      + ')';
          }
      }
  
      private static class FalseEquals implements Predicate<Boolean>
      {
          private static final long serialVersionUID = 1L;
  
          @Override
          public boolean accept(Boolean anObject)
          {
              return Boolean.FALSE.equals(anObject);
          }
      }
  
      private static class TrueEquals implements Predicate<Boolean>
      {
          private static final long serialVersionUID = 1L;
  
          @Override
          public boolean accept(Boolean anObject)
          {
              return Boolean.TRUE.equals(anObject);
          }
      }
  
      private static final class AttributeFalse<T> extends AttributePredicate<T, Boolean>
      {
          private static final long serialVersionUID = 1L;
          private static final FalseEquals FALSE_EQUALS = new FalseEquals();
  
          private AttributeFalse(Function<? super T, Boolean> newFunction)
          {
              super(newFunction, FALSE_EQUALS);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.ifFalse(" + this.function + ')';
          }
      }
  
      private static final class AttributeTrue<T> extends AttributePredicate<T, Boolean>
      {
          private static final long serialVersionUID = 1L;
          private static final TrueEquals TRUE_EQUALS = new TrueEquals();
  
          private AttributeTrue(Function<? super T, Boolean> newFunction)
          {
              super(newFunction, TRUE_EQUALS);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.ifTrue(" + this.function + ')';
          }
      }
  
      public static class AnySatisfy<T> extends Predicates<Iterable<T>>
      {
          private static final long serialVersionUID = 1L;
          private final Predicate<? super T> predicate;
  
          public AnySatisfy(Predicate<? super T> predicate)
          {
              this.predicate = predicate;
          }
  
          @Override
          public boolean accept(Iterable<T> iterable)
          {
              return Iterate.anySatisfy(iterable, this.predicate);
          }
      }
  
      public static class AllSatisfy<T> extends Predicates<Iterable<T>>
      {
          private static final long serialVersionUID = 1L;
          private final Predicate<? super T> predicate;
  
          public AllSatisfy(Predicate<? super T> predicate)
          {
              this.predicate = predicate;
          }
  
          @Override
          public boolean accept(Iterable<T> iterable)
          {
              return Iterate.allSatisfy(iterable, this.predicate);
          }
      }
  
      public static class NoneSatisfy<T> extends Predicates<Iterable<T>>
      {
          private static final long serialVersionUID = 1L;
          private final Predicate<? super T> predicate;
  
          public NoneSatisfy(Predicate<? super T> predicate)
          {
              this.predicate = predicate;
          }
  
          @Override
          public boolean accept(Iterable<T> iterable)
          {
              return Iterate.noneSatisfy(iterable, this.predicate);
          }
      }
  
      private abstract static class CompareToPredicate<T extends Comparable<? super T>>
              extends Predicates<T>
      {
          private static final long serialVersionUID = 1L;
          protected final T compareTo;
  
          private CompareToPredicate(T newCompareTo)
          {
              this.compareTo = newCompareTo;
          }
      }
  
      protected static class LessThanPredicate<T extends Comparable<? super T>>
              extends CompareToPredicate<T>
      {
          private static final long serialVersionUID = 1L;
  
          protected LessThanPredicate(T newCompareTo)
          {
              super(newCompareTo);
          }
  
          @Override
          public boolean accept(T o)
          {
              return o.compareTo(this.compareTo) < 0;
          }
  
          @Override
          public String toString()
          {
              return "Predicates.lessThan(" + this.compareTo + ')';
          }
      }
  
      protected abstract static class RangePredicate<T extends Comparable<? super T>>
              extends CompareToPredicate<T>
      {
          private static final long serialVersionUID = 1L;
          protected final T compareFrom;
  
          protected RangePredicate(T newCompareFrom, T newCompareTo)
          {
              super(newCompareTo);
              this.compareFrom = newCompareFrom;
          }
      }
  
      private static final class BetweenInclusive<T extends Comparable<? super T>>
              extends RangePredicate<T>
      {
          private static final long serialVersionUID = 1L;
  
          private BetweenInclusive(T newCompareFrom, T newCompareTo)
          {
              super(newCompareFrom, newCompareTo);
          }
  
          @Override
          public boolean accept(T o)
          {
              return o.compareTo(this.compareFrom) >= 0 && o.compareTo(this.compareTo) <= 0;
          }
      }
  
      private static final class BetweenInclusiveTo<T extends Comparable<? super T>>
              extends RangePredicate<T>
      {
          private static final long serialVersionUID = 1L;
  
          private BetweenInclusiveTo(T newCompareFrom, T newCompareTo)
          {
              super(newCompareFrom, newCompareTo);
          }
  
          @Override
          public boolean accept(T o)
          {
              return o.compareTo(this.compareFrom) > 0 && o.compareTo(this.compareTo) <= 0;
          }
      }
  
      private static final class BetweenInclusiveFrom<T extends Comparable<? super T>>
              extends RangePredicate<T>
      {
          private static final long serialVersionUID = 1L;
  
          private BetweenInclusiveFrom(T newCompareFrom, T newCompareTo)
          {
              super(newCompareFrom, newCompareTo);
          }
  
          @Override
          public boolean accept(T o)
          {
              return o.compareTo(this.compareFrom) >= 0 && o.compareTo(this.compareTo) < 0;
          }
      }
  
      private static final class BetweenExclusive<T extends Comparable<? super T>>
              extends RangePredicate<T>
      {
          private static final long serialVersionUID = 1L;
  
          private BetweenExclusive(T newCompareFrom, T newCompareTo)
          {
              super(newCompareFrom, newCompareTo);
          }
  
          @Override
          public boolean accept(T o)
          {
              return o.compareTo(this.compareFrom) > 0 && o.compareTo(this.compareTo) < 0;
          }
      }
  
      protected static class LessThanOrEqualPredicate<T extends Comparable<? super T>>
              extends CompareToPredicate<T>
      {
          private static final long serialVersionUID = 1L;
  
          protected LessThanOrEqualPredicate(T newCompareTo)
          {
              super(newCompareTo);
          }
  
          @Override
          public boolean accept(T o)
          {
              return o.compareTo(this.compareTo) <= 0;
          }
  
          @Override
          public String toString()
          {
              return "Predicates.lessThanOrEqualTo(" + this.compareTo + ')';
          }
      }
  
      protected static class GreaterThanPredicate<T extends Comparable<? super T>>
              extends CompareToPredicate<T>
      {
          private static final long serialVersionUID = 1L;
  
          protected GreaterThanPredicate(T newCompareTo)
          {
              super(newCompareTo);
          }
  
          @Override
          public boolean accept(T o)
          {
              return o.compareTo(this.compareTo) > 0;
          }
  
          @Override
          public String toString()
          {
              return "Predicates.greaterThan(" + this.compareTo + ')';
          }
      }
  
      protected static class GreaterThanOrEqualPredicate<T extends Comparable<? super T>>
              extends CompareToPredicate<T>
      {
          private static final long serialVersionUID = 1L;
  
          protected GreaterThanOrEqualPredicate(T newCompareTo)
          {
              super(newCompareTo);
          }
  
          @Override
          public boolean accept(T o)
          {
              return o.compareTo(this.compareTo) >= 0;
          }
  
          @Override
          public String toString()
          {
              return "Predicates.greaterThanOrEqualTo(" + this.compareTo + ')';
          }
      }
  
      private static final class AndIterablePredicate<T>
              extends AbstractIterablePredicate<T>
      {
          private static final long serialVersionUID = 1L;
  
          private AndIterablePredicate(Iterable<? extends Predicate<? super T>> predicates)
          {
              super(predicates);
          }
  
          @Override
          protected String getTypeName()
          {
              return "and";
          }
  
          @Override
          public boolean accept(T anObject)
          {
              Predicate<Predicate<? super T>> predicate = aPredicate -> aPredicate.accept(anObject);
              return Iterate.allSatisfy(this.predicates, predicate);
          }
      }
  
      private static final class OrIterablePredicate<T>
              extends AbstractIterablePredicate<T>
      {
          private static final long serialVersionUID = 1L;
  
          private OrIterablePredicate(Iterable<? extends Predicate<? super T>> predicates)
          {
              super(predicates);
          }
  
          @Override
          protected String getTypeName()
          {
              return "or";
          }
  
          @Override
          public boolean accept(T anObject)
          {
              Predicate<Predicate<? super T>> predicate = aPredicate -> aPredicate.accept(anObject);
              return Iterate.anySatisfy(this.predicates, predicate);
          }
      }
  
      private static final class NoneOfIterablePredicate<T>
              extends AbstractIterablePredicate<T>
      {
          private static final long serialVersionUID = 1L;
  
          private NoneOfIterablePredicate(Iterable<? extends Predicate<? super T>> predicates)
          {
              super(predicates);
          }
  
          @Override
          protected String getTypeName()
          {
              return "noneOf";
          }
  
          @Override
          public boolean accept(T anObject)
          {
              Predicate<Predicate<? super T>> predicate = aPredicate -> !aPredicate.accept(anObject);
              return Iterate.allSatisfy(this.predicates, predicate);
          }
      }
  
      private abstract static class AbstractIterablePredicate<T>
              extends Predicates<T>
      {
          private static final long serialVersionUID = 1L;
          protected final Iterable<? extends Predicate<? super T>> predicates;
  
          private AbstractIterablePredicate(Iterable<? extends Predicate<? super T>> predicates)
          {
              this.predicates = predicates;
          }
  
          protected abstract String getTypeName();
  
          @Override
          public String toString()
          {
              return "Predicates." + this.getTypeName() + '(' + this.predicates + ')';
          }
      }
  
      private static final class AndPredicate<T>
              extends Predicates<T>
      {
          private static final long serialVersionUID = 1L;
          private final Predicate<? super T> left;
          private final Predicate<? super T> right;
  
          private AndPredicate(Predicate<? super T> one, Predicate<? super T> two)
          {
              this.left = one;
              this.right = two;
          }
  
          @Override
          public boolean accept(T anObject)
          {
              return this.left.accept(anObject) && this.right.accept(anObject);
          }
  
          @Override
          public String toString()
          {
              return this.left + ".and(" + this.right + ')';
          }
      }
  
      private static final class NeitherPredicate<T>
              extends Predicates<T>
      {
          private static final long serialVersionUID = 1L;
          private final Predicate<? super T> left;
          private final Predicate<? super T> right;
  
          private NeitherPredicate(Predicate<? super T> one, Predicate<? super T> two)
          {
              this.left = one;
              this.right = two;
          }
  
          @Override
          public boolean accept(T anObject)
          {
              return !this.left.accept(anObject) && !this.right.accept(anObject);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.neither(" + this.left + ", " + this.right + ')';
          }
      }
  
      private static final class OrPredicate<T>
              extends Predicates<T>
      {
          private static final long serialVersionUID = 1L;
          private final Predicate<? super T> left;
          private final Predicate<? super T> right;
  
          private OrPredicate(Predicate<? super T> one, Predicate<? super T> two)
          {
              this.left = one;
              this.right = two;
          }
  
          @Override
          public boolean accept(T anObject)
          {
              return this.left.accept(anObject) || this.right.accept(anObject);
          }
  
          @Override
          public String toString()
          {
              return this.left + ".or(" + this.right + ')';
          }
      }
  
      private static final class NotPredicate<T>
              extends Predicates<T>
      {
          private static final long serialVersionUID = 1L;
          private final Predicate<T> predicate;
  
          private NotPredicate(Predicate<T> newPredicate)
          {
              this.predicate = newPredicate;
          }
  
          @Override
          public boolean accept(T anObject)
          {
              return !this.predicate.accept(anObject);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.not(" + this.predicate + ')';
          }
      }
  
      private static final class EqualPredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final Object compareObject;
  
          private EqualPredicate(Object newCompareObject)
          {
              this.compareObject = newCompareObject;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return this.compareObject.equals(anObject);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.equal(" + this.compareObject + ')';
          }
      }
  
      private static final class InCollectionPredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final Collection<?> collection;
  
          private InCollectionPredicate(Collection<?> collection)
          {
              this.collection = collection;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return this.collection.contains(anObject);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.in(" + this.collection + ')';
          }
      }
  
      private static final class NotInCollectionPredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final Collection<?> collection;
  
          private NotInCollectionPredicate(Collection<?> collection)
          {
              this.collection = collection;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return !this.collection.contains(anObject);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.notIn(" + this.collection + ')';
          }
      }
  
      private static final class InSetIterablePredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final SetIterable<?> setIterable;
  
          private InSetIterablePredicate(SetIterable<?> setIterable)
          {
              this.setIterable = setIterable;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return this.setIterable.contains(anObject);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.in(" + this.setIterable + ')';
          }
      }
  
      private static final class NotInSetIterablePredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final SetIterable<?> setIterable;
  
          private NotInSetIterablePredicate(SetIterable<?> setIterable)
          {
              this.setIterable = setIterable;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return !this.setIterable.contains(anObject);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.notIn(" + this.setIterable + ')';
          }
      }
  
      private static final class InSetPredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final Set<?> set;
  
          private InSetPredicate(Set<?> set)
          {
              this.set = set;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return this.set.contains(anObject);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.in(" + this.set + ')';
          }
      }
  
      private static final class NotInSetPredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final Set<?> set;
  
          private NotInSetPredicate(Set<?> set)
          {
              this.set = set;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return !this.set.contains(anObject);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.notIn(" + this.set + ')';
          }
      }
  
      private static final class NotEqualPredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final Object compareObject;
  
          private NotEqualPredicate(Object newCompareObject)
          {
              this.compareObject = newCompareObject;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return !this.compareObject.equals(anObject);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.notEqual(" + this.compareObject + ')';
          }
      }
  
      private static final class IsNull
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
  
          @Override
          public boolean accept(Object anObject)
          {
              return anObject == null;
          }
  
          @Override
          public String toString()
          {
              return "Predicates.isNull()";
          }
      }
  
      private static final class NotNull
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
  
          @Override
          public boolean accept(Object anObject)
          {
              return anObject != null;
          }
  
          @Override
          public String toString()
          {
              return "Predicates.notNull()";
          }
      }
  
      private static final class AssignableFromPredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final Class<?> clazz;
  
          private AssignableFromPredicate(Class<?> newClass)
          {
              this.clazz = newClass;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return this.clazz.isAssignableFrom(anObject.getClass());
          }
  
          @Override
          public String toString()
          {
              return "Predicates.assignableFrom(" + this.clazz.getName() + ".class)";
          }
      }
  
      private static final class InstanceOfPredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final Class<?> clazz;
  
          private InstanceOfPredicate(Class<?> newClass)
          {
              this.clazz = newClass;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return this.clazz.isInstance(anObject);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.instanceOf(" + this.clazz.getName() + ".class)";
          }
      }
  
      private static final class NotInstanceOfPredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final Class<?> clazz;
  
          private NotInstanceOfPredicate(Class<?> newClass)
          {
              this.clazz = newClass;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return !this.clazz.isInstance(anObject);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.notInstanceOf(" + this.clazz.getName() + ".class)";
          }
      }
  
      private static final class AlwaysTrue
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
  
          @Override
          public boolean accept(Object anObject)
          {
              return true;
          }
  
          @Override
          public String toString()
          {
              return "Predicates.alwaysTrue()";
          }
      }
  
      private static final class AlwaysFalse
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
  
          @Override
          public boolean accept(Object anObject)
          {
              return false;
          }
  
          @Override
          public String toString()
          {
              return "Predicates.alwaysFalse()";
          }
      }
  
      private static final class IdentityPredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final Object twin;
  
          private IdentityPredicate(Object object)
          {
              this.twin = object;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return this.twin == anObject;
          }
  
          @Override
          public String toString()
          {
              return "Predicates.sameAs(" + this.twin + ')';
          }
      }
  
      private static final class NotIdentityPredicate
              extends Predicates<Object>
      {
          private static final long serialVersionUID = 1L;
          private final Object twin;
  
          private NotIdentityPredicate(Object object)
          {
              this.twin = object;
          }
  
          @Override
          public boolean accept(Object anObject)
          {
              return this.twin != anObject;
          }
  
          @Override
          public String toString()
          {
              return "Predicates.notSameAs(" + this.twin + ')';
          }
      }
  
      private static final class SynchronizedPredicate<T> implements Predicate<T>
      {
          private static final long serialVersionUID = 1L;
          private final Predicate<T> predicate;
  
          private SynchronizedPredicate(Predicate<T> predicate)
          {
              this.predicate = predicate;
          }
  
          @Override
          public boolean accept(T each)
          {
              synchronized (each)
              {
                  return this.predicate.accept(each);
              }
          }
      }
  
      private static final class SubclassPredicate extends Predicates<Class<?>>
      {
          private static final long serialVersionUID = 1L;
  
          private final Class<?> aClass;
  
          private SubclassPredicate(Class<?> aClass)
          {
              this.aClass = aClass;
          }
  
          @Override
          public boolean accept(Class<?> each)
          {
              return this.aClass.isAssignableFrom(each);
          }
      }
  
      private static final class SuperclassPredicate extends Predicates<Class<?>>
      {
          private static final long serialVersionUID = 1L;
  
          private final Class<?> aClass;
  
          private SuperclassPredicate(Class<?> aClass)
          {
              this.aClass = aClass;
          }
  
          @Override
          public boolean accept(Class<?> each)
          {
              return each.isAssignableFrom(this.aClass);
          }
      }
  
      private static final class BindPredicate2<T, P> implements Predicate<T>
      {
          private static final long serialVersionUID = 1L;
  
          private final Predicate2<? super T, ? super P> predicate;
          private final P parameter;
  
          private BindPredicate2(Predicate2<? super T, ? super P> predicate, P parameter)
          {
              this.predicate = predicate;
              this.parameter = parameter;
          }
  
          @Override
          public boolean accept(T each)
          {
              return this.predicate.accept(each, this.parameter);
          }
  
          @Override
          public String toString()
          {
              return "Predicates.bind(" + this.predicate + ", " + this.parameter + ")";
          }
      }
  
      private static final class ThrowingPredicateAdapter<T> extends CheckedPredicate<T>
      {
          private static final long serialVersionUID = 1L;
          private final ThrowingPredicate<T> throwingPredicate;
  
          private ThrowingPredicateAdapter(ThrowingPredicate<T> throwingPredicate)
          {
              this.throwingPredicate = throwingPredicate;
          }
  
          @Override
          public boolean safeAccept(T object) throws Exception
          {
              return this.throwingPredicate.safeAccept(object);
          }
      }
  }
  