| /* |
| * Copyright (C) 2012 The Guava Authors |
| * |
| * 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.common.collect; |
| |
| import static com.google.common.base.Preconditions.checkElementIndex; |
| |
| import com.google.common.annotations.GwtCompatible; |
| import com.google.common.math.IntMath; |
| |
| import java.util.AbstractList; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.RandomAccess; |
| |
| import javax.annotation.Nullable; |
| |
| /** |
| * Implementation of {@link Lists#cartesianProduct(List)}. |
| * |
| * @author Louis Wasserman |
| */ |
| @GwtCompatible |
| final class CartesianList<E> extends AbstractList<List<E>> implements RandomAccess { |
| |
| private transient final ImmutableList<List<E>> axes; |
| private transient final int[] axesSizeProduct; |
| |
| static <E> List<List<E>> create(List<? extends List<? extends E>> lists) { |
| ImmutableList.Builder<List<E>> axesBuilder = |
| new ImmutableList.Builder<List<E>>(lists.size()); |
| for (List<? extends E> list : lists) { |
| List<E> copy = ImmutableList.copyOf(list); |
| if (copy.isEmpty()) { |
| return ImmutableList.of(); |
| } |
| axesBuilder.add(copy); |
| } |
| return new CartesianList<E>(axesBuilder.build()); |
| } |
| |
| CartesianList(ImmutableList<List<E>> axes) { |
| this.axes = axes; |
| int[] axesSizeProduct = new int[axes.size() + 1]; |
| axesSizeProduct[axes.size()] = 1; |
| try { |
| for (int i = axes.size() - 1; i >= 0; i--) { |
| axesSizeProduct[i] = |
| IntMath.checkedMultiply(axesSizeProduct[i + 1], axes.get(i).size()); |
| } |
| } catch (ArithmeticException e) { |
| throw new IllegalArgumentException( |
| "Cartesian product too large; must have size at most Integer.MAX_VALUE"); |
| } |
| this.axesSizeProduct = axesSizeProduct; |
| } |
| |
| private int getAxisIndexForProductIndex(int index, int axis) { |
| return (index / axesSizeProduct[axis + 1]) % axes.get(axis).size(); |
| } |
| |
| @Override |
| public ImmutableList<E> get(final int index) { |
| checkElementIndex(index, size()); |
| return new ImmutableList<E>() { |
| |
| @Override |
| public int size() { |
| return axes.size(); |
| } |
| |
| @Override |
| public E get(int axis) { |
| checkElementIndex(axis, size()); |
| int axisIndex = getAxisIndexForProductIndex(index, axis); |
| return axes.get(axis).get(axisIndex); |
| } |
| |
| @Override |
| boolean isPartialView() { |
| return true; |
| } |
| }; |
| } |
| |
| @Override |
| public int size() { |
| return axesSizeProduct[0]; |
| } |
| |
| @Override |
| public boolean contains(@Nullable Object o) { |
| if (!(o instanceof List)) { |
| return false; |
| } |
| List<?> list = (List<?>) o; |
| if (list.size() != axes.size()) { |
| return false; |
| } |
| ListIterator<?> itr = list.listIterator(); |
| while (itr.hasNext()) { |
| int index = itr.nextIndex(); |
| if (!axes.get(index).contains(itr.next())) { |
| return false; |
| } |
| } |
| return true; |
| } |
| } |