/* * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2006. * * Licensed under the Aduna BSD-style license. */ package org.openrdf.query.algebra.evaluation; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import info.aduna.collections.iterators.ConvertingIterator; import org.openrdf.model.Value; import org.openrdf.query.Binding; import org.openrdf.query.BindingSet; import org.openrdf.query.impl.BindingImpl; import org.openrdf.query.impl.MapBindingSet; /** * 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 implements BindingSet { /*-----------* * Variables * *-----------*/ private Map<String, Value> bindings; /*--------------* * Constructors * *--------------*/ 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<String, Value>(capacity * 2); } public QueryBindingSet(BindingSet bindingSet) { this(bindingSet.size()); addAll(bindingSet); } /*---------* * Methods * *---------*/ 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 solution. The binding's name must not already be * part of this solution. * * @param binding * The binding to add this this BindingSet. */ public void addBinding(Binding binding) { addBinding(binding.getName(), binding.getValue()); } /** * Adds a new binding to the solution. The binding's name must not already be * part of this solution. * * @param name * The binding's name, must not be bound in this solution already. * @param value * The binding's value. */ 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) { assert value != null : "null value for variable " + name; 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); } public Set<String> getBindingNames() { return bindings.keySet(); } public Value getValue(String bindingName) { return bindings.get(bindingName); } public Binding getBinding(String bindingName) { Value value = getValue(bindingName); if (value != null) { return new BindingImpl(bindingName, value); } return null; } public boolean hasBinding(String bindingName) { return bindings.containsKey(bindingName); } public Iterator<Binding> iterator() { Iterator<Map.Entry<String, Value>> entries = bindings.entrySet().iterator(); return new ConvertingIterator<Map.Entry<String, Value>, Binding>(entries) { @Override protected Binding convert(Map.Entry<String, Value> entry) { return new BindingImpl(entry.getKey(), entry.getValue()); } }; } public int size() { return bindings.size(); } @Override public boolean equals(Object other) { if (this == other) { return true; } else if (other instanceof QueryBindingSet) { return bindings.equals(((QueryBindingSet)other).bindings); } else if (other instanceof BindingSet) { int otherSize = 0; // Compare other's bindings to own for (Binding binding : (BindingSet)other) { Value ownValue = getValue(binding.getName()); if (!binding.getValue().equals(ownValue)) { // Unequal bindings for this name return false; } otherSize++; } // All bindings have been matched, sets are equal if this solution // doesn't have any additional bindings. return otherSize == bindings.size(); } return false; } @Override public int hashCode() { int hashCode = 0; for (Map.Entry<String, Value> entry : bindings.entrySet()) { hashCode ^= entry.getKey().hashCode() ^ entry.getValue().hashCode(); } return hashCode; } @Override public String toString() { StringBuilder sb = new StringBuilder(32 * size()); sb.append('['); Iterator<Binding> iter = iterator(); while (iter.hasNext()) { sb.append(iter.next().toString()); if (iter.hasNext()) { sb.append(';'); } } sb.append(']'); return sb.toString(); } }