/******************************************************************************* * Copyright (c) 2013-2014 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: * * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package org.rascalmpl.value.impl.persistent; import java.util.Comparator; import java.util.Iterator; import java.util.Objects; import org.rascalmpl.value.ISet; import org.rascalmpl.value.IValue; import org.rascalmpl.value.IValueFactory; import org.rascalmpl.value.impl.AbstractSet; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.util.AbstractTypeBag; import org.rascalmpl.value.util.EqualityUtils; import io.usethesource.capsule.DefaultTrieSet; import io.usethesource.capsule.ImmutableSet; import io.usethesource.capsule.TransientSet; public final class PDBPersistentHashSet extends AbstractSet { private static final PDBPersistentHashSet EMPTY = new PDBPersistentHashSet(); @SuppressWarnings("unchecked") private static final Comparator<Object> equivalenceComparator = EqualityUtils.getEquivalenceComparator(); private Type cachedSetType; private final AbstractTypeBag elementTypeBag; private final ImmutableSet<IValue> content; private PDBPersistentHashSet() { this.elementTypeBag = AbstractTypeBag.of(); this.content = DefaultTrieSet.of(); } public PDBPersistentHashSet(AbstractTypeBag elementTypeBag, ImmutableSet<IValue> content) { Objects.requireNonNull(elementTypeBag); Objects.requireNonNull(content); this.elementTypeBag = elementTypeBag; this.content = content; } @Override protected IValueFactory getValueFactory() { return ValueFactory.getInstance(); } @Override public Type getType() { if (cachedSetType == null) { final Type elementType = elementTypeBag.lub(); // consists collection out of tuples? if (elementType.isFixedWidth()) { cachedSetType = getTypeFactory().relTypeFromTuple(elementType); } else { cachedSetType = getTypeFactory().setType(elementType); } } return cachedSetType; } @Override public boolean isEmpty() { return content.isEmpty(); } @Override public ISet insert(IValue value) { final ImmutableSet<IValue> contentNew = content.__insertEquivalent(value, equivalenceComparator); if (content == contentNew) return this; final AbstractTypeBag bagNew = elementTypeBag.increase(value.getType()); return new PDBPersistentHashSet(bagNew, contentNew); } @Override public ISet delete(IValue value) { final ImmutableSet<IValue> contentNew = content.__removeEquivalent(value, equivalenceComparator); if (content == contentNew) return this; final AbstractTypeBag bagNew = elementTypeBag.decrease(value.getType()); return new PDBPersistentHashSet(bagNew, contentNew); } @Override public int size() { return content.size(); } @Override public boolean contains(IValue value) { return content.containsEquivalent(value, equivalenceComparator); } @Override public Iterator<IValue> iterator() { return content.iterator(); } @Override public int hashCode() { return content.hashCode(); } @Override public boolean equals(Object other) { if (other == this) return true; if (other == null) return false; if (other instanceof PDBPersistentHashSet) { PDBPersistentHashSet that = (PDBPersistentHashSet) other; if (this.getType() != that.getType()) return false; if (this.size() != that.size()) return false; return content.equals(that.content); } if (other instanceof ISet) { ISet that = (ISet) other; if (this.getType() != that.getType()) return false; if (this.size() != that.size()) return false; for (IValue e : that) if (!content.contains(e)) return false; return true; } return false; } @Override public boolean isEqual(IValue other) { if (other == this) return true; if (other == null) return false; if (other instanceof ISet) { ISet that = (ISet) other; if (this.size() != that.size()) return false; for (IValue e : that) if (!content.containsEquivalent(e, equivalenceComparator)) return false; return true; } return false; } @Override public ISet union(ISet other) { if (other == this) return this; if (other == null) return this; if (other instanceof PDBPersistentHashSet) { PDBPersistentHashSet that = (PDBPersistentHashSet) other; final ImmutableSet<IValue> one; final ImmutableSet<IValue> two; AbstractTypeBag bag; final ISet def; if (that.size() >= this.size()) { def = that; one = that.content; bag = that.elementTypeBag; two = this.content; } else { def = this; one = this.content; bag = this.elementTypeBag; two = that.content; } final TransientSet<IValue> tmp = one.asTransient(); boolean modified = false; for (IValue key : two) { if (tmp.__insertEquivalent(key, equivalenceComparator)) { modified = true; bag = bag.increase(key.getType()); } } if (modified) { return new PDBPersistentHashSet(bag, tmp.freeze()); } return def; } else { return super.union(other); } } @Override public ISet intersect(ISet other) { if (other == this) return this; if (other == null) return EMPTY; if (other instanceof PDBPersistentHashSet) { PDBPersistentHashSet that = (PDBPersistentHashSet) other; final ImmutableSet<IValue> one; final ImmutableSet<IValue> two; AbstractTypeBag bag; final ISet def; if (that.size() >= this.size()) { def = this; one = this.content; bag = this.elementTypeBag; two = that.content; } else { def = that; one = that.content; bag = that.elementTypeBag; two = this.content; } final TransientSet<IValue> tmp = one.asTransient(); boolean modified = false; for (Iterator<IValue> it = tmp.iterator(); it.hasNext();) { final IValue key = it.next(); if (!two.containsEquivalent(key, equivalenceComparator)) { it.remove(); modified = true; bag = bag.decrease(key.getType()); } } if (modified) { return new PDBPersistentHashSet(bag, tmp.freeze()); } return def; } else { return super.intersect(other); } } @Override public ISet subtract(ISet other) { if (other == this) return EMPTY; if (other == null) return this; if (other instanceof PDBPersistentHashSet) { PDBPersistentHashSet that = (PDBPersistentHashSet) other; final ImmutableSet<IValue> one; final ImmutableSet<IValue> two; AbstractTypeBag bag; final ISet def; def = this; one = this.content; bag = this.elementTypeBag; two = that.content; final TransientSet<IValue> tmp = one.asTransient(); boolean modified = false; for (IValue key : two) { if (tmp.__removeEquivalent(key, equivalenceComparator)) { modified = true; bag = bag.decrease(key.getType()); } } if (modified) { return new PDBPersistentHashSet(bag, tmp.freeze()); } return def; } else { return super.subtract(other); } } @Override public ISet product(ISet that) { // TODO Auto-generated method stub return super.product(that); } @Override public boolean isSubsetOf(ISet that) { // TODO Auto-generated method stub return super.isSubsetOf(that); } }