guava/src/com/google/common/util/concurrent/Futures.java
@Beta
  public static <T> ImmutableList<ListenableFuture<T>> inCompletionOrder(
      Iterable<? extends ListenableFuture<? extends T>> futures) {
    // Can't use Iterables.toArray because it's not gwt compatible
    final Collection<ListenableFuture<? extends T>> collection;
    if (futures instanceof Collection) {
      collection = (Collection<ListenableFuture<? extends T>>) futures;
    } else {
      collection = ImmutableList.copyOf(futures);
    }
    @SuppressWarnings("unchecked")
    ListenableFuture<? extends T>[] copy =
        (ListenableFuture<? extends T>[])
            collection.toArray(new ListenableFuture[collection.size()]);
    final InCompletionOrderState<T> state = new InCompletionOrderState<>(copy);
    ImmutableList.Builder<AbstractFuture<T>> delegatesBuilder = ImmutableList.builder();
    for (int i = 0; i < copy.length; i++) {
      delegatesBuilder.add(new InCompletionOrderFuture<T>(state));
    }

    final ImmutableList<AbstractFuture<T>> delegates = delegatesBuilder.build();
    for (int i = 0; i < copy.length; i++) {
      final int localI = i;
      copy[i].addListener(
          new Runnable() {
            @Override
            public void run() {
              state.recordInputCompletion(delegates, localI);
            }
          },
          directExecutor());
    }

    @SuppressWarnings("unchecked")
    ImmutableList<ListenableFuture<T>> delegatesCast = (ImmutableList) delegates;
    return delegatesCast;
  }
@Beta
  public static <T> ImmutableList<ListenableFuture<T>> inCompletionOrder(
      Iterable<? extends ListenableFuture<? extends T>> futures) {
    // Can't use Iterables.toArray because it's not gwt compatible
    final Collection<ListenableFuture<? extends T>> collection;
    if (futures instanceof Collection) {
      collection = (Collection<ListenableFuture<? extends T>>) futures;
    } else {
      collection = ImmutableList.copyOf(futures);
    }
    @SuppressWarnings("unchecked")
    ListenableFuture<? extends T>[] copy =
        (ListenableFuture<? extends T>[])
            collection.toArray(new ListenableFuture[collection.size()]);
    final InCompletionOrderState<T> state = new InCompletionOrderState<>(copy);
    ImmutableList.Builder<AbstractFuture<T>> delegatesBuilder = ImmutableList.builder();
    for (int i = 0; i < copy.length; i++) {
      delegatesBuilder.add(new InCompletionOrderFuture<T>(state));
    }

    final ImmutableList<AbstractFuture<T>> delegates = delegatesBuilder.build();
    for (int i = 0; i < copy.length; i++) {
      final int localI = i;
      copy[i].addListener(
          new Runnable() {
            @Override
            public void run() {
              state.recordInputCompletion(delegates, localI);
            }
          },
          directExecutor());
    }

    @SuppressWarnings("unchecked")
    ImmutableList<ListenableFuture<T>> delegatesCast = (ImmutableList) delegates;
    return delegatesCast;
  }
Returns a list of delegate futures that correspond to the futures received in the order that
they complete. Delegate futures return the same value or throw the same exception as the
corresponding input future returns/throws.

<p>"In the order that they complete" means, for practical purposes, about what you would
expect, but there are some subtleties. First, we do guarantee that, if the output future at
index n is done, the output future at index n-1 is also done. (But as usual with futures, some
listeners for future n may complete before some for future n-1.) However, it is possible, if
one input completes with result X and another later with result Y, for Y to come before X in
the output future list. (Such races are impossible to solve without global synchronization of
all future completions. And they should have little practical impact.)

<p>Cancelling a delegate future propagates to input futures once all the delegates complete,
either from cancellation or because an input future has completed. If N futures are passed in,
and M delegates are cancelled, the remaining M input futures will be cancelled once N - M of
the input futures complete. If all the delegates are cancelled, all the input futures will be
too.

@since 17.0