@Override public <T> void eval( QueryEnvironment<T> env, VariableContext<T> context, QueryExpression expression, List<Argument> args, final Callback<T> callback) throws QueryException, InterruptedException { final AtomicBoolean someFound = new AtomicBoolean(false); env.eval( args.get(0).getExpression(), context, new Callback<T>() { @Override public void process(Iterable<T> partialResult) throws QueryException, InterruptedException { if (someFound.get() || Iterables.isEmpty(partialResult)) { return; } callback.process(ImmutableSet.of(partialResult.iterator().next())); someFound.set(true); } }); if (!someFound.get()) { throw new QueryException(expression, "argument set is empty"); } }
@Override public <T> void eval(QueryEnvironment<T> env, VariableContext<T> context, Callback<T> callback) throws QueryException, InterruptedException { for (TargetLiteral expr : words) { env.eval(expr, context, callback); } }
/** * Compute the transitive closure of the universe, then breadth-first search from the argument * towards the universe while staying within the transitive closure. */ @Override public <T> Set<T> eval(QueryEnvironment<T> env, QueryExpression expression, List<Argument> args) throws QueryException { Set<T> universeValue = args.get(0).getExpression().eval(env); Set<T> argumentValue = args.get(1).getExpression().eval(env); int depthBound = args.size() > 2 ? args.get(2).getInteger() : Integer.MAX_VALUE; env.buildTransitiveClosure(expression, universeValue, Integer.MAX_VALUE); Set<T> visited = new LinkedHashSet<>(); Set<T> reachableFromUniverse = env.getTransitiveClosure(universeValue); Collection<T> current = argumentValue; // We need to iterate depthBound + 1 times. for (int i = 0; i <= depthBound; i++) { List<T> next = new ArrayList<>(); for (T node : current) { if (!reachableFromUniverse.contains(node)) { // Traversed outside the transitive closure of the universe. continue; } if (!visited.add(node)) { // Already visited; if we see a node in a later round, then we don't need to visit it // again, because the depth at which we see it at must be greater than or equal to the // last visit. continue; } next.addAll(env.getReverseDeps(node)); } if (next.isEmpty()) { // Exit when there are no more nodes to visit. break; } current = next; } return visited; }