+public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
+ implements StatementDefinition, StatementFactory<A, D, E> {
+ /**
+ * A baseline class for implementing the {@link StatementFactory#canReuseCurrent(Current, Current, Collection)}
+ * contract in a manner which is consistent with a statement's {@link CopyPolicy}.
+ *
+ * @param <A> Argument type
+ * @param <D> Declared Statement representation
+ */
+ public abstract static class StatementPolicy<A, D extends DeclaredStatement<A>> implements Immutable {
+ final @NonNull CopyPolicy copyPolicy;
+
+ StatementPolicy(final CopyPolicy copyPolicy) {
+ this.copyPolicy = requireNonNull(copyPolicy);
+ }
+
+ /**
+ * Return a {@link StatementPolicy} for {@link CopyPolicy#CONTEXT_INDEPENDENT}.
+ *
+ * @param <A> Argument type
+ * @param <D> Declared Statement representation
+ * @return Context-independent policy
+ */
+ @SuppressWarnings("unchecked")
+ public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> contextIndependent() {
+ return (StatementPolicy<A, D>) EqualSemantics.CONTEXT_INDEPENDENT;
+ }
+
+ /**
+ * Return a {@link StatementPolicy} for {@link CopyPolicy#EXACT_REPLICA}.
+ *
+ * @param <A> Argument type
+ * @param <D> Declared Statement representation
+ * @return Exact-replica policy
+ */
+ @SuppressWarnings("unchecked")
+ public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> exactReplica() {
+ return (StatementPolicy<A, D>) EqualSemantics.EXACT_REPLICA;
+ }
+
+ /**
+ * Return a {@link StatementPolicy} for {@link CopyPolicy#IGNORE}.
+ *
+ * @param <A> Argument type
+ * @param <D> Declared Statement representation
+ * @return Ignoring policy
+ */
+ @SuppressWarnings("unchecked")
+ public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> ignore() {
+ return (StatementPolicy<A, D>) AlwaysFail.IGNORE;
+ }
+
+ /**
+ * Return a {@link StatementPolicy} for {@link CopyPolicy#REJECT}.
+ *
+ * @param <A> Argument type
+ * @param <D> Declared Statement representation
+ * @return Rejecting statement policy
+ */
+ @SuppressWarnings("unchecked")
+ public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> reject() {
+ return (StatementPolicy<A, D>) AlwaysFail.REJECT;
+ }
+
+ /**
+ * Return a {@link StatementPolicy} for {@link CopyPolicy#DECLARED_COPY}, deferring to a
+ * {@link StatementEquality} for individual decisions.
+ *
+ * @param <A> Argument type
+ * @param <D> Declared Statement representation
+ * @param equality {@link StatementEquality} to apply to effective statements
+ * @return Equality-based statement policy
+ */
+ public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> copyDeclared(
+ final @NonNull StatementEquality<A, D> equality) {
+ return new EqualSemantics<>(equality);
+ }
+
+ /**
+ * Return a {@link StatementPolicy} for {@link CopyPolicy#DECLARED_COPY}, always performing a copy operation.
+ *
+ * @param <A> Argument type
+ * @param <D> Declared Statement representation
+ * @return Rejecting statement policy
+ */
+ @SuppressWarnings("unchecked")
+ public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> alwaysCopyDeclared() {
+ return (StatementPolicy<A, D>) EqualSemantics.ALWAYS_COPY;
+ }
+
+ @Deprecated(forRemoval = true)
+ // FIXME: 7.0.0: remove this method
+ public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> legacyDeclaredCopy() {
+ return alwaysCopyDeclared();
+ }
+
+ abstract boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
+ @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
+
+ private static final class AlwaysFail<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
+ static final @NonNull AlwaysFail<?, ?> IGNORE = new AlwaysFail<>(CopyPolicy.IGNORE);
+ static final @NonNull AlwaysFail<?, ?> REJECT = new AlwaysFail<>(CopyPolicy.REJECT);
+
+ private AlwaysFail(final CopyPolicy copyPolicy) {
+ super(copyPolicy);
+ }
+
+ @Override
+ boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
+ final Collection<? extends EffectiveStatement<?, ?>> substatements) {
+ throw new VerifyException("This implementation should never be invoked");
+ }
+ }
+
+ private static final class EqualSemantics<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
+ static final @NonNull EqualSemantics<?, ?> ALWAYS_COPY =
+ new EqualSemantics<>((copy, stmt, substatements) -> false);
+ static final @NonNull EqualSemantics<?, ?> CONTEXT_INDEPENDENT =
+ new EqualSemantics<>(CopyPolicy.CONTEXT_INDEPENDENT, (copy, stmt, substatements) -> true);
+ static final @NonNull EqualSemantics<?, ?> EXACT_REPLICA =
+ new EqualSemantics<>(CopyPolicy.EXACT_REPLICA, (copy, stmt, substatements) -> true);
+
+ private final @NonNull StatementEquality<A, D> equality;
+
+ private EqualSemantics(final CopyPolicy copyPolicy, final StatementEquality<A, D> equality) {
+ super(copyPolicy);
+ this.equality = requireNonNull(equality);
+ }
+
+ EqualSemantics(final StatementEquality<A, D> equality) {
+ this(CopyPolicy.DECLARED_COPY, equality);
+ }
+
+ @Override
+ boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
+ final Collection<? extends EffectiveStatement<?, ?>> substatements) {
+ return equality.canReuseCurrent(copy, current, substatements);
+ }
+ }
+ }
+
+ /**
+ * Abstract base class for comparators associated with statements with a {@link CopyPolicy#DECLARED_COPY} copy
+ * policy.
+ *
+ * @param <A> Argument type
+ * @param <D> Declared Statement representation
+ */
+ @FunctionalInterface
+ public interface StatementEquality<A, D extends DeclaredStatement<A>> {
+ /**
+ * Determine whether {@code current} statement has the same semantics as the provided copy. See the contract
+ * specification of {@link StatementFactory#canReuseCurrent(Current, Current, Collection)}.
+ *
+ * @param copy Copy of current effective context
+ * @param current Current effective context
+ * @param substatements Current effective substatements
+ * @return True if {@code current} can be reused in place of {@code copy}, false if the copy needs to be used.
+ */
+ boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
+ @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
+ }
+
+ private final @NonNull StatementPolicy<A, D> policy;
+ private final @NonNull StatementDefinition def;
+ private final @NonNull CopyPolicy copyPolicy;
+
+ @Beta
+ protected StatementSupport(final StatementSupport<A, D, E> delegate) {
+ checkArgument(delegate != this);
+ this.def = delegate.def;
+ this.policy = delegate.policy;
+ this.copyPolicy = delegate.copyPolicy;
+ }
+
+ @Beta
+ protected StatementSupport(final StatementDefinition publicDefinition, final StatementPolicy<A, D> policy) {
+ checkArgument(publicDefinition != this);
+ this.def = requireNonNull(publicDefinition);
+ this.policy = requireNonNull(policy);
+ this.copyPolicy = policy.copyPolicy;
+ }
+