/* * Copyright 2014 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.errorprone.refaster; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; import com.google.errorprone.annotations.ForOverride; import java.util.Collection; import java.util.Collections; import java.util.Iterator; /** * A representation of a choice with zero or more options, which may be evaluated lazily or * strictly. * * <p>This resembles the list monad in Haskell. * * @author lowasser@google.com (Louis Wasserman) */ public abstract class Choice<T> { /* * This is currently implemented in terms of Iterators, but this may change in future, e.g. to a * Stream-based implementation. * * Special-casing operations for Choice.none and Choice.single, which are by far the most common * cases, avoids overly nested results. */ private static final Choice<Object> NONE = new Choice<Object>() { @Override protected Iterator<Object> iterator() { return Collections.emptyIterator(); } @Override public <R> Choice<R> thenChoose(Function<? super Object, Choice<R>> function) { checkNotNull(function); return none(); } @Override public <R> Choice<R> thenOption(Function<? super Object, Optional<R>> function) { checkNotNull(function); return none(); } @Override public <R> Choice<R> transform(Function<? super Object, R> function) { checkNotNull(function); return none(); } @Override public Choice<Object> or(Choice<Object> other) { return checkNotNull(other); } @Override public Choice<Object> condition(Predicate<? super Object> predicate) { checkNotNull(predicate); return this; } @Override public String toString() { return "Choice.NONE"; } }; /** * The empty {@code Choice}. */ @SuppressWarnings("unchecked") public static <T> Choice<T> none() { return (Choice) NONE; } /** * Returns a {@code Choice} with only one option, {@code t}. */ public static <T> Choice<T> of(final T t) { checkNotNull(t); return new Choice<T>() { @Override protected Iterator<T> iterator() { return Iterators.singletonIterator(t); } @Override public Optional<T> first() { return Optional.of(t); } @Override public Choice<T> condition(Predicate<? super T> predicate) { return predicate.apply(t) ? this : Choice.<T>none(); } @Override public <R> Choice<R> thenChoose(Function<? super T, Choice<R>> function) { return function.apply(t); } @Override public <R> Choice<R> thenOption(Function<? super T, Optional<R>> function) { return fromOptional(function.apply(t)); } @Override public <R> Choice<R> transform(Function<? super T, R> function) { return of(function.apply(t)); } @Override public String toString() { return String.format("Choice.of(%s)", t); } }; } /** * Returns a {@code Choice} with {@code t} as an option if {@code condition}, * and no options otherwise. */ public static <T> Choice<T> condition(boolean condition, T t) { return condition ? of(t) : Choice.<T>none(); } /** * Returns a choice of the optional value, if it is present, or the empty choice if it is absent. */ public static <T> Choice<T> fromOptional(Optional<T> optional) { return optional.isPresent() ? of(optional.get()) : Choice.<T>none(); } public static <T> Choice<T> from(final Collection<T> choices) { switch (choices.size()) { case 0: return none(); case 1: return of(Iterables.getOnlyElement(choices)); default: return new Choice<T>() { @Override protected Iterator<T> iterator() { return choices.iterator(); } @Override public String toString() { return String.format("Choice.from(%s)", choices); } }; } } /** * Returns a choice between any of the options from any of the specified choices. */ public static <T> Choice<T> any(final Collection<Choice<T>> choices) { return from(choices).thenChoose(Functions.<Choice<T>>identity()); } private Choice() {} @VisibleForTesting Iterable<T> asIterable() { return new Iterable<T>() { @Override public Iterator<T> iterator() { return Choice.this.iterator(); } }; } // Currently, this is implemented with an Iterator, but that may change in future! @ForOverride protected abstract Iterator<T> iterator(); @Override public String toString() { return Iterables.toString(asIterable()); } /** * Returns the first valid option from this {@code Choice}. */ public Optional<T> first() { Iterator<T> itr = iterator(); return itr.hasNext() ? Optional.of(itr.next()) : Optional.<T>absent(); } /** * Returns all the choices obtained by choosing from this {@code Choice} and then choosing from * the {@code Choice} yielded by this function on the result. * * <p>The function may be applied lazily or immediately, at the discretion of the implementation. * * <p>This is the monadic bind for {@code Choice}. */ public <R> Choice<R> thenChoose(final Function<? super T, Choice<R>> function) { checkNotNull(function); if (Thread.interrupted()) { throw new RuntimeException(new InterruptedException()); } final Choice<T> thisChoice = this; return new Choice<R>() { @Override protected Iterator<R> iterator() { if (Thread.interrupted()) { throw new RuntimeException(new InterruptedException()); } return Iterators.concat( Iterators.transform(thisChoice.iterator(), new Function<T, Iterator<R>>() { @Override public Iterator<R> apply(T t) { return function.apply(t).iterator(); } })); } }; } /** * Returns all the choices obtained by choosing from this {@code Choice} and yielding a present * {@code Optional}. * * <p>The function may be applied lazily or immediately, at the discretion of the implementation. */ public <R> Choice<R> thenOption(final Function<? super T, Optional<R>> function) { checkNotNull(function); final Choice<T> thisChoice = this; return new Choice<R>() { @Override protected Iterator<R> iterator() { return Optional.presentInstances(Iterables.transform(thisChoice.asIterable(), function)) .iterator(); } }; } /** * Maps the choices with the specified function. */ public <R> Choice<R> transform(final Function<? super T, R> function) { checkNotNull(function); final Choice<T> thisChoice = this; return new Choice<R>() { @Override protected Iterator<R> iterator() { return Iterators.transform(thisChoice.iterator(), function); } }; } /** * Returns a choice of the options from this {@code Choice} or from {@code other}. */ public Choice<T> or(final Choice<T> other) { checkNotNull(other); if (other == none()) { return this; } else { final Choice<T> thisChoice = this; return new Choice<T>() { @Override protected Iterator<T> iterator() { return Iterators.concat(thisChoice.iterator(), other.iterator()); } @Override public String toString() { return String.format("%s.or(%s)", thisChoice, other); } }; } } /** * Returns this choice if {@code condition}, otherwise the empty choice. */ public Choice<T> condition(boolean condition) { return condition ? this : Choice.<T>none(); } /** * Filters the choices to those that satisfy the provided {@code Predicate}. */ public Choice<T> condition(final Predicate<? super T> predicate) { checkNotNull(predicate); final Choice<T> thisChoice = this; return new Choice<T>() { @Override protected Iterator<T> iterator() { return Iterators.filter(thisChoice.iterator(), predicate); } @Override public String toString() { return String.format("%s.condition(%s)", thisChoice, predicate); } }; } }