1
2
3
4
5
6
7
8
9
10
11
12
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
31
32
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 }