blob: 84bf1d35d80cd7439d19157962fe7a3511576535 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you 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 org.apache.calcite.linq4j;
import java.util.List;
/**
* Enumerator over the cartesian product of enumerators.
*
* @param <T> Input element type
* @param <E> Element type
*/
public abstract class CartesianProductEnumerator<T, E> implements Enumerator<E> {
private final List<Enumerator<T>> enumerators;
protected final T[] elements;
private boolean first = true;
protected CartesianProductEnumerator(List<Enumerator<T>> enumerators) {
this.enumerators = enumerators;
//noinspection unchecked
this.elements = (T[]) new Object[enumerators.size()];
}
public boolean moveNext() {
if (first) {
int i = 0;
for (Enumerator<T> enumerator : enumerators) {
if (!enumerator.moveNext()) {
return false;
}
elements[i++] = enumerator.current();
}
first = false;
return true;
}
for (int ordinal = enumerators.size() - 1; ordinal >= 0; --ordinal) {
final Enumerator<T> enumerator = enumerators.get(ordinal);
if (enumerator.moveNext()) {
elements[ordinal] = enumerator.current();
return true;
}
// Move back to first element.
enumerator.reset();
if (!enumerator.moveNext()) {
// Very strange... this was empty all along.
return false;
}
elements[ordinal] = enumerator.current();
}
return false;
}
public void reset() {
first = true;
for (Enumerator<T> enumerator : enumerators) {
enumerator.reset();
}
}
public void close() {
// If there is one or more exceptions, carry on and close all enumerators,
// then throw the first.
Throwable rte = null;
for (Enumerator<T> enumerator : enumerators) {
try {
enumerator.close();
} catch (Throwable e) {
if (rte == null) {
rte = e;
} else {
rte.addSuppressed(e);
}
}
}
if (rte != null) {
if (rte instanceof Error) {
throw (Error) rte;
} else {
throw (RuntimeException) rte;
}
}
}
}