/*******************************************************************************
* Copyright (c) 2009-2013 Centrum Wiskunde en Informatica (CWI)
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Arnold Lankamp - interfaces and implementation
* Michael Steindorfer - performance improvements
*******************************************************************************/
package org.rascalmpl.value.impl.fast;
import java.util.Iterator;
import org.rascalmpl.value.ISet;
import org.rascalmpl.value.ISetRelation;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.exceptions.IllegalOperationException;
import org.rascalmpl.value.impl.AbstractValue;
import org.rascalmpl.value.impl.func.SetFunctions;
import org.rascalmpl.value.impl.util.collections.ShareableValuesHashSet;
import org.rascalmpl.value.type.Type;
import org.rascalmpl.value.type.TypeFactory;
import org.rascalmpl.value.visitors.IValueVisitor;
/**
* Implementation of ISet.
*
* @author Arnold Lankamp
*/
/*package*/ class Set extends AbstractValue implements ISet {
protected final static TypeFactory typeFactory = TypeFactory.getInstance();
protected final static Type voidType = typeFactory.voidType();
protected final Type setType;
protected final Type elementType;
protected final ShareableValuesHashSet data;
/*package*/ static ISet newSet(Type elementType, ShareableValuesHashSet data) {
return new Set(elementType, data);
}
private Set(Type elementType, ShareableValuesHashSet data) {
super();
if (data.isEmpty())
this.elementType = voidType;
else
this.elementType = elementType;
this.setType = typeFactory.setType(this.elementType);
this.data = data;
}
public Type getType(){
return setType;
}
public Type getElementType(){
return elementType;
}
public int size(){
return data.size();
}
public boolean isEmpty(){
return data.isEmpty();
}
public Iterator<IValue> iterator(){
return data.iterator();
}
public <T, E extends Throwable> T accept(IValueVisitor<T,E> v) throws E{
if (getElementType().isFixedWidth()) {
return v.visitRelation(this);
} else {
return v.visitSet(this);
}
}
public boolean contains(IValue element){
return data.contains(element);
}
public boolean isSubsetOf(ISet other){
Set otherSet = (Set) other;
Iterator<IValue> iterator = iterator();
while(iterator.hasNext()){
if(!otherSet.data.contains(iterator.next())) return false;
}
return true;
}
public ISet insert(IValue value){
if(!contains(value)) {
ShareableValuesHashSet newData = new ShareableValuesHashSet(data);
newData.add(value);
Type type = elementType.lub(value.getType());
return new SetWriter(type, newData).done();
} else {
return this;
}
}
public ISet delete(IValue value){
if (contains(value)) {
ShareableValuesHashSet newData = new ShareableValuesHashSet(data);
newData.remove(value);
Type newElementType = TypeFactory.getInstance().voidType();
for (IValue el : newData) {
newElementType = newElementType.lub(el.getType());
}
return new SetWriter(newElementType, newData).done();
} else {
return this;
}
}
public ISet intersect(ISet other){
ShareableValuesHashSet commonData = new ShareableValuesHashSet();
Iterator<IValue> setIterator;
ISet theOtherSet;
if(other.size() <= size()){
setIterator = other.iterator();
theOtherSet = this;
}else{
setIterator = iterator();
theOtherSet = other;
}
Type newElementType = TypeFactory.getInstance().voidType();
while(setIterator.hasNext()){
IValue value = setIterator.next();
if(theOtherSet.contains(value)){
newElementType = newElementType.lub(value.getType());
commonData.add(value);
}
}
return new SetWriter(newElementType, commonData).done();
}
public ISet subtract(ISet other){
ShareableValuesHashSet newData = new ShareableValuesHashSet(data);
Iterator<IValue> setIterator = other.iterator();
while(setIterator.hasNext()){
newData.remove(setIterator.next());
}
Type newElementType = TypeFactory.getInstance().voidType();
for(IValue el : newData)
newElementType = newElementType.lub(el.getType());
return new SetWriter(newElementType, newData).done();
}
public ISet union(ISet other){
ShareableValuesHashSet newData;
Iterator<IValue> setIterator;
Set otherSet = (Set) other;
if(otherSet.size() <= size()){
newData = new ShareableValuesHashSet(data);
setIterator = otherSet.iterator();
}else{
newData = new ShareableValuesHashSet(otherSet.data);
setIterator = iterator();
}
while(setIterator.hasNext()){
newData.add(setIterator.next());
}
Type newElementType = elementType.lub(otherSet.elementType);
return new SetWriter(newElementType, newData).done();
}
public ISet product(ISet other){
ShareableValuesHashSet newData = new ShareableValuesHashSet();
Type tupleType = typeFactory.tupleType(elementType, other.getElementType());
Iterator<IValue> thisIterator = data.iterator();
while(thisIterator.hasNext()){
IValue left = thisIterator.next();
Iterator<IValue> setIterator = other.iterator();
while(setIterator.hasNext()){
IValue right = setIterator.next();
IValue[] tuple = new IValue[]{left, right};
newData.add(Tuple.newTuple(tupleType, tuple));
}
}
return new SetWriter(tupleType, newData).done();
}
public int hashCode(){
return data.hashCode();
}
public boolean equals(Object o){
if(o == this) return true;
if(o == null) return false;
if(o.getClass() == getClass()){
Set otherSet = (Set) o;
if (getType() != otherSet.getType()) {
return false;
}
return data.equals(otherSet.data);
}
return false;
}
public boolean isEqual(IValue value){
if(value == this) return true;
if(value == null) return false;
if(value instanceof Set){
Set otherSet = (Set) value;
return data.isEqual(otherSet.data);
}
else if (value instanceof ISet) {
return SetFunctions.isEqual(ValueFactory.getInstance(), this, (ISet) value);
}
return false;
}
@Override
public boolean isRelation() {
return getType().isRelation();
}
@Override
public ISetRelation<ISet> asRelation() {
if (!isRelation())
throw new IllegalOperationException(
"Cannot be viewed as a relation.", getType());
return new RelationViewOnSet(this);
}
}