package com.github.davidmoten.rtree;
import com.github.davidmoten.rtree.geometry.Geometry;
import com.github.davidmoten.rtree.internal.util.ImmutableStack;
import rx.Subscriber;
import rx.functions.Func1;
/**
* Utility methods for controlling backpressure of the tree search.
*/
final class Backpressure {
private Backpressure() {
// prevent instantiation
}
static <T, S extends Geometry> ImmutableStack<NodePosition<T, S>> search(
final Func1<? super Geometry, Boolean> condition,
final Subscriber<? super Entry<T, S>> subscriber,
final ImmutableStack<NodePosition<T, S>> stack, final long request) {
StackAndRequest<NodePosition<T, S>> state = StackAndRequest.create(stack, request);
return searchAndReturnStack(condition, subscriber, state);
}
private static <S extends Geometry, T> ImmutableStack<NodePosition<T, S>> searchAndReturnStack(
final Func1<? super Geometry, Boolean> condition,
final Subscriber<? super Entry<T, S>> subscriber,
StackAndRequest<NodePosition<T, S>> state) {
while (!state.stack.isEmpty()) {
NodePosition<T, S> np = state.stack.peek();
if (subscriber.isUnsubscribed())
return ImmutableStack.empty();
else if (state.request <= 0)
return state.stack;
else if (np.position() == np.node().count()) {
// handle after last in node
state = StackAndRequest.create(searchAfterLastInNode(state.stack), state.request);
} else if (np.node() instanceof NonLeaf) {
// handle non-leaf
state = StackAndRequest.create(searchNonLeaf(condition, state.stack, np),
state.request);
} else {
// handle leaf
state = searchLeaf(condition, subscriber, state, np);
}
}
return state.stack;
}
private static class StackAndRequest<T> {
private final ImmutableStack<T> stack;
private final long request;
StackAndRequest(ImmutableStack<T> stack, long request) {
this.stack = stack;
this.request = request;
}
static <T> StackAndRequest<T> create(ImmutableStack<T> stack, long request) {
return new StackAndRequest<T>(stack, request);
}
}
private static <T, S extends Geometry> StackAndRequest<NodePosition<T, S>> searchLeaf(
final Func1<? super Geometry, Boolean> condition,
final Subscriber<? super Entry<T, S>> subscriber,
StackAndRequest<NodePosition<T, S>> state, NodePosition<T, S> np) {
final long nextRequest;
Entry<T, S> entry = ((Leaf<T, S>) np.node()).entry(np.position());
if (condition.call(entry.geometry())) {
subscriber.onNext(entry);
nextRequest = state.request - 1;
} else
nextRequest = state.request;
return StackAndRequest.create(state.stack.pop().push(np.nextPosition()), nextRequest);
}
private static <S extends Geometry, T> ImmutableStack<NodePosition<T, S>> searchNonLeaf(
final Func1<? super Geometry, Boolean> condition,
ImmutableStack<NodePosition<T, S>> stack, NodePosition<T, S> np) {
Node<T, S> child = ((NonLeaf<T, S>) np.node()).child(np.position());
if (condition.call(child.geometry())) {
stack = stack.push(new NodePosition<T, S>(child, 0));
} else {
stack = stack.pop().push(np.nextPosition());
}
return stack;
}
private static <S extends Geometry, T> ImmutableStack<NodePosition<T, S>> searchAfterLastInNode(
ImmutableStack<NodePosition<T, S>> stack) {
ImmutableStack<NodePosition<T, S>> stack2 = stack.pop();
if (stack2.isEmpty())
stack = stack2;
else {
NodePosition<T, S> previous = stack2.peek();
stack = stack2.pop().push(previous.nextPosition());
}
return stack;
}
}