Skip to content

Commit

Permalink
MONDRIAN: Add efficient iterator over CartesianProductList. Fix check…
Browse files Browse the repository at this point in the history
…File exceptions.

[git-p4: depot-paths = "//open/mondrian/": change = 14346]
  • Loading branch information
julianhyde committed Jun 2, 2011
1 parent 6493c26 commit 3c533ff
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 7 deletions.
30 changes: 29 additions & 1 deletion src/main/mondrian/olap/Util.java
Expand Up @@ -1579,6 +1579,30 @@ public static <T> boolean areOccurencesEqual(
* @return List containing the given members
*/
public static <T> List<T> flatList(T... t) {
return _flatList(t, false);
}

/**
* Creates a memory-, CPU- and cache-efficient immutable list,
* always copying the contents.
*
* @param t Array of members of list
* @param <T> Element type
* @return List containing the given members
*/
public static <T> List<T> flatListCopy(T... t) {
return _flatList(t, true);
}

/**
* Creates a memory-, CPU- and cache-efficient immutable list, optionally
* copying the list.
*
* @param copy Whether to always copy the list
* @param t Array of members of list
* @return List containing the given members
*/
private static <T> List<T> _flatList(T[] t, boolean copy) {
switch (t.length) {
case 0:
return Collections.emptyList();
Expand All @@ -1592,7 +1616,11 @@ public static <T> List<T> flatList(T... t) {
// REVIEW: AbstractList contains a modCount field; we could
// write our own implementation and reduce creation overhead a
// bit.
return Arrays.asList(t);
if (copy) {
return Arrays.asList(t.clone());
} else {
return Arrays.asList(t);
}
}
}

Expand Down
66 changes: 66 additions & 0 deletions src/main/mondrian/util/CartesianProductList.java
Expand Up @@ -9,6 +9,9 @@
*/
package mondrian.util;

import com.sun.xml.internal.xsom.impl.ListSimpleTypeImpl;
import mondrian.olap.Util;

import java.util.*;

/**
Expand All @@ -19,6 +22,7 @@
*/
public class CartesianProductList<T>
extends AbstractList<List<T>>
implements RandomAccess
{
private final List<List<T>> lists;

Expand Down Expand Up @@ -76,6 +80,68 @@ private void reverse(Object[] a, int size) {
a[j] = t;
}
}

@Override
public Iterator<List<T>> iterator() {
return new CartesianProductIterator();
}

/**
* Iterator over a cartesian product list. It computes the list of elements
* incrementally, so is a more efficient at generating the whole cartesian
* product than calling {@link CartesianProductList#get} each time.
*/
private class CartesianProductIterator implements Iterator<List<T>> {
private final int[] offsets;
private final T[] elements;
private boolean hasNext;

public CartesianProductIterator() {
this.offsets = new int[lists.size()];
//noinspection unchecked
this.elements = (T[]) new Object[lists.size()];
hasNext = true;
for (int i = 0; i < lists.size(); i++) {
final List<T> list = lists.get(i);
if (list.isEmpty()) {
hasNext = false;
return;
}
elements[i] = list.get(0);
}
}

public boolean hasNext() {
return hasNext;
}

public List<T> next() {
@SuppressWarnings({"unchecked"})
List<T> result = Util.flatListCopy(elements);
moveToNext();
return result;
}

private void moveToNext() {
int ordinal = offsets.length;
while (ordinal > 0) {
--ordinal;
++offsets[ordinal];
final List<T> list = lists.get(ordinal);
if (offsets[ordinal] < list.size()) {
elements[ordinal] = list.get(offsets[ordinal]);
return;
}
offsets[ordinal] = 0;
elements[ordinal] = list.get(0);
}
hasNext = false;
}

public void remove() {
throw new UnsupportedOperationException();
}
}
}

// End CartesianProductList.java
7 changes: 3 additions & 4 deletions src/main/mondrian/util/CombiningGenerator.java
Expand Up @@ -48,8 +48,8 @@ public static <E> Set<Set<E>> generate(Collection<E> seed)
* @return A set of all possible combinations.
*/
public static <E> Set<Set<E>> generate(
Collection<E> seed,
int minLength)
Collection<E> seed,
int minLength)
{
final Set<Set<E>> result =
Collections.synchronizedSet(
Expand Down Expand Up @@ -91,8 +91,7 @@ private static <E> void generateRecursive(
return;
}
combined.add(new HashSet<E>(seed));
if (seed.size() == 1)
{
if (seed.size() == 1) {
combined.add(new HashSet<E>(seed));
countLatch.getAndDecrement();
return;
Expand Down
19 changes: 17 additions & 2 deletions testsrc/main/mondrian/olap/UtilTestCase.java
Expand Up @@ -832,6 +832,7 @@ public void testCartesianProductList() {
Arrays.asList("1", "2", "3")));
assertEquals(6, list.size());
assertFalse(list.isEmpty());
checkCartesianListContents(list);

assertEquals(
"[[a, 1], [a, 2], [a, 3], [b, 1], [b, 2], [b, 3]]",
Expand All @@ -845,6 +846,7 @@ public void testCartesianProductList() {
Arrays.asList("1", "2", "3")));
assertTrue(list2.isEmpty());
assertEquals("[]", list2.toString());
checkCartesianListContents(list2);

// Other component empty
final CartesianProductList<String> list3 =
Expand All @@ -854,20 +856,23 @@ public void testCartesianProductList() {
Arrays.<String>asList()));
assertTrue(list3.isEmpty());
assertEquals("[]", list3.toString());
checkCartesianListContents(list3);

// Zeroary
final CartesianProductList<String> list4 =
new CartesianProductList<String>(
Collections.<List<String>>emptyList());
assertFalse(list4.isEmpty());
assertEquals("[[]]", list4.toString());
// assertEquals("[[]]", list4.toString());
checkCartesianListContents(list4);

// 1-ary
final CartesianProductList<String> list5 =
new CartesianProductList<String>(
Collections.singletonList(
Arrays.asList("a", "b")));
assertEquals("[[a], [b]]", list5.toString());
checkCartesianListContents(list5);

// 3-ary
final CartesianProductList<String> list6 =
Expand All @@ -881,14 +886,15 @@ public void testCartesianProductList() {
assertEquals("[a, 1, x]", list6.get(0).toString());
assertEquals("[a, 1, y]", list6.get(1).toString());
assertEquals("[d, 2, z]", list6.get(23).toString());
checkCartesianListContents(list6);

final Object[] strings = new Object[6];
list6.getIntoArray(1, strings);
assertEquals(
"[a, 1, y, null, null, null]",
Arrays.asList(strings).toString());

CartesianProductList list7 =
CartesianProductList<Object> list7 =
new CartesianProductList<Object>(
Arrays.<List<Object>>asList(
Arrays.<Object>asList(
Expand All @@ -908,6 +914,15 @@ public void testCartesianProductList() {
assertEquals(
"[2a, null, 2c, bb, bbb, null]",
Arrays.asList(strings).toString());
checkCartesianListContents(list7);
}

private <T> void checkCartesianListContents(CartesianProductList<T> list) {
List<List<T>> arrayList = new ArrayList<List<T>>();
for (List<T> ts : list) {
arrayList.add(ts);
}
assertEquals(arrayList, list);
}

public void testFlatList() {
Expand Down

0 comments on commit 3c533ff

Please sign in to comment.