com.google.errorprone.refaster.Choice.java Source code

Java tutorial

Introduction

Here is the source code for com.google.errorprone.refaster.Choice.java

Source

/*
 * 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);
            }
        };
    }
}