/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.qp.operator;
import java.util.ArrayList;
import java.util.List;
/**
* A generator of {@link QueryBindingsCursor}s from a common source.
*/
public class MultipleQueryBindingsCursor implements QueryBindingsCursor
{
private final QueryBindingsCursor input;
private final List<QueryBindings> buffer = new ArrayList<QueryBindings>();
private final List<SubCursor> cursors = new ArrayList<SubCursor>();
private boolean exhausted;
private int offset;
public MultipleQueryBindingsCursor(QueryBindingsCursor input) {
this.input = input;
newCursor();
}
@Override
public void openBindings() {
input.openBindings();
exhausted = false;
buffer.clear();
offset = 0;
cursors.get(0).openBindings();
for (int i = 1; i < cursors.size(); i++) {
cursors.get(i).closeBindings();
}
}
@Override
public QueryBindings nextBindings() {
return cursors.get(0).nextBindings();
}
@Override
public void closeBindings() {
cursors.get(0).closeBindings();
}
@Override
public void cancelBindings(QueryBindings bindings) {
cursors.get(0).cancelBindings(bindings);
input.cancelBindings(bindings);
}
public QueryBindingsCursor newCursor() {
assert (offset == 0);
SubCursor cursor = new SubCursor();
cursors.add(cursor);
return cursor;
}
protected void shrink() {
int minIndex = cursors.get(0).index;
for (int i = 1; i < cursors.size(); i++) {
SubCursor cursor = cursors.get(i);
if (!cursor.open) continue;
if (minIndex > cursor.index) {
minIndex = cursor.index;
}
}
while (offset < minIndex) {
buffer.remove(0);
offset++;
}
}
class SubCursor implements QueryBindingsCursor {
boolean open;
int index;
@Override
public void openBindings() {
assert (offset == 0);
open = true;
index = 0;
}
@Override
public QueryBindings nextBindings() {
assert (open);
assert (index >= offset);
while (index - offset >= buffer.size()) {
if (exhausted) {
return null;
}
else {
QueryBindings bindings = input.nextBindings();
if (bindings == null) {
exhausted = true;
return null;
}
buffer.add(bindings);
}
}
QueryBindings bindings = buffer.get(index - offset);
index++;
shrink();
return bindings;
}
@Override
public void closeBindings() {
open = false;
}
@Override
public void cancelBindings(QueryBindings ancestor) {
while (index - offset < buffer.size()) {
QueryBindings bindings = buffer.get(index - offset);
if (bindings.isAncestor(ancestor)) {
index++;
}
else {
break;
}
}
shrink();
}
}
}