QueryBindingSet.java
/*******************************************************************************
* Copyright (c) 2015 Eclipse RDF4J contributors, Aduna, and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.query.algebra.evaluation;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.query.AbstractBindingSet;
import org.eclipse.rdf4j.query.Binding;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.MutableBindingSet;
import org.eclipse.rdf4j.query.impl.MapBindingSet;
import org.eclipse.rdf4j.query.impl.SimpleBinding;
/**
* An implementation of the {@link BindingSet} interface that is used to evalate query object models. This
* implementations differs from {@link MapBindingSet} in that it maps variable names to Value objects and that the
* Binding objects are created lazily.
*/
public class QueryBindingSet extends AbstractBindingSet implements MutableBindingSet {
private static final long serialVersionUID = -2010715346095527301L;
private final Map<String, Value> bindings;
public QueryBindingSet() {
this(8);
}
public QueryBindingSet(int capacity) {
// Create bindings map with some extra space for new bindings and
// compensating for HashMap's load factor
bindings = new HashMap<>(capacity * 2);
}
public QueryBindingSet(BindingSet bindingSet) {
this(bindingSet.size());
addAll(bindingSet);
}
public void addAll(BindingSet bindingSet) {
if (bindingSet instanceof QueryBindingSet) {
bindings.putAll(((QueryBindingSet) bindingSet).bindings);
} else {
for (Binding binding : bindingSet) {
this.addBinding(binding);
}
}
}
/**
* Adds a new binding to the binding set. The binding's name must not already be part of this binding set.
*
* @param binding The binding to add this this BindingSet.
*/
@Override
public void addBinding(Binding binding) {
addBinding(binding.getName(), binding.getValue());
}
/**
* Adds a new binding to the binding set. The binding's name must not already be part of this binding set.
*
* @param name The binding's name, must not be bound in this binding set already.
* @param value The binding's value.
*/
@Override
public void addBinding(String name, Value value) {
assert !bindings.containsKey(name) : "variable already bound: " + name;
setBinding(name, value);
}
public void setBinding(Binding binding) {
setBinding(binding.getName(), binding.getValue());
}
public void setBinding(String name, Value value) {
bindings.put(name, value);
}
public void removeBinding(String name) {
bindings.remove(name);
}
public void removeAll(Collection<String> bindingNames) {
bindings.keySet().removeAll(bindingNames);
}
public void retainAll(Collection<String> bindingNames) {
bindings.keySet().retainAll(bindingNames);
}
@Override
public Set<String> getBindingNames() {
return bindings.keySet();
}
@Override
public Value getValue(String bindingName) {
return bindings.get(bindingName);
}
@Override
public Binding getBinding(String bindingName) {
Value value = getValue(bindingName);
if (value != null) {
return new SimpleBinding(bindingName, value);
}
return null;
}
@Override
public boolean hasBinding(String bindingName) {
return bindings.containsKey(bindingName);
}
@Override
public Iterator<Binding> iterator() {
return new BindingIterator(bindings.entrySet().iterator());
}
@Override
public int size() {
return bindings.size();
}
@Override
public boolean equals(Object other) {
if (other instanceof QueryBindingSet) {
return bindings.equals(((QueryBindingSet) other).bindings);
} else {
return super.equals(other);
}
}
private static class BindingIterator implements Iterator<Binding> {
private final Iterator<Map.Entry<String, Value>> iterator;
SimpleBinding next;
public BindingIterator(Iterator<Map.Entry<String, Value>> iterator) {
this.iterator = iterator;
}
private void calculateNext() {
while (next == null && iterator.hasNext()) {
Map.Entry<String, Value> next1 = iterator.next();
if (next1.getValue() != null) {
next = new SimpleBinding(next1.getKey(), next1.getValue());
}
}
}
@Override
public boolean hasNext() {
calculateNext();
return next != null;
}
@Override
public Binding next() {
calculateNext();
var temp = next;
next = null;
return temp;
}
}
}