Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2012 The Guava Authors
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
      5  * in compliance with the License. You may obtain a copy of the License at
      6  *
      7  * http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the License
     10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     11  * or implied. See the License for the specific language governing permissions and limitations under
     12  * the License.
     13  */
     14 
     15 package com.google.common.collect;
     16 
     17 import static com.google.common.base.Preconditions.checkElementIndex;
     18 
     19 import com.google.common.annotations.GwtCompatible;
     20 import com.google.common.math.IntMath;
     21 
     22 import java.util.AbstractList;
     23 import java.util.List;
     24 import java.util.ListIterator;
     25 import java.util.RandomAccess;
     26 
     27 import javax.annotation.Nullable;
     28 
     29 /**
     30  * Implementation of {@link Lists#cartesianProduct(List)}.
     31  *
     32  * @author Louis Wasserman
     33  */
     34 @GwtCompatible
     35 final class CartesianList<E> extends AbstractList<List<E>> implements RandomAccess {
     36 
     37   private transient final ImmutableList<List<E>> axes;
     38   private transient final int[] axesSizeProduct;
     39 
     40   static <E> List<List<E>> create(List<? extends List<? extends E>> lists) {
     41     ImmutableList.Builder<List<E>> axesBuilder =
     42         new ImmutableList.Builder<List<E>>(lists.size());
     43     for (List<? extends E> list : lists) {
     44       List<E> copy = ImmutableList.copyOf(list);
     45       if (copy.isEmpty()) {
     46         return ImmutableList.of();
     47       }
     48       axesBuilder.add(copy);
     49     }
     50     return new CartesianList<E>(axesBuilder.build());
     51   }
     52 
     53   CartesianList(ImmutableList<List<E>> axes) {
     54     this.axes = axes;
     55     int[] axesSizeProduct = new int[axes.size() + 1];
     56     axesSizeProduct[axes.size()] = 1;
     57     try {
     58       for (int i = axes.size() - 1; i >= 0; i--) {
     59         axesSizeProduct[i] =
     60             IntMath.checkedMultiply(axesSizeProduct[i + 1], axes.get(i).size());
     61       }
     62     } catch (ArithmeticException e) {
     63       throw new IllegalArgumentException(
     64           "Cartesian product too large; must have size at most Integer.MAX_VALUE");
     65     }
     66     this.axesSizeProduct = axesSizeProduct;
     67   }
     68 
     69   private int getAxisIndexForProductIndex(int index, int axis) {
     70     return (index / axesSizeProduct[axis + 1]) % axes.get(axis).size();
     71   }
     72 
     73   @Override
     74   public ImmutableList<E> get(final int index) {
     75     checkElementIndex(index, size());
     76     return new ImmutableList<E>() {
     77 
     78       @Override
     79       public int size() {
     80         return axes.size();
     81       }
     82 
     83       @Override
     84       public E get(int axis) {
     85         checkElementIndex(axis, size());
     86         int axisIndex = getAxisIndexForProductIndex(index, axis);
     87         return axes.get(axis).get(axisIndex);
     88       }
     89 
     90       @Override
     91       boolean isPartialView() {
     92         return true;
     93       }
     94     };
     95   }
     96 
     97   @Override
     98   public int size() {
     99     return axesSizeProduct[0];
    100   }
    101 
    102   @Override
    103   public boolean contains(@Nullable Object o) {
    104     if (!(o instanceof List)) {
    105       return false;
    106     }
    107     List<?> list = (List<?>) o;
    108     if (list.size() != axes.size()) {
    109       return false;
    110     }
    111     ListIterator<?> itr = list.listIterator();
    112     while (itr.hasNext()) {
    113       int index = itr.nextIndex();
    114       if (!axes.get(index).contains(itr.next())) {
    115         return false;
    116       }
    117     }
    118     return true;
    119   }
    120 }
    121