/* * Copyright (C) 2009-2012 University of Freiburg * * This file is part of SMTInterpol. * * SMTInterpol is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * SMTInterpol is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with SMTInterpol. If not, see <http://www.gnu.org/licenses/>. */ package de.uni_freiburg.informatik.ultimate.smtinterpol.util; import java.util.AbstractSet; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class SharingSet<E> extends AbstractSet<E> { private static final class SharingSetData<E> { SharingSetData() { mRep = new HashSet<E>(); mSharing = 0; } SharingSetData(SharingSetData<E> other) { mRep = new HashSet<E>(other.mRep); mSharing = 0; } SharingSetData(E obj) { mRep = Collections.singleton(obj); // HACK: The first write modification has to copy the map since it // is immutable... mSharing = 1; } Set<E> mRep; // XXX Should this be atomic for multi threading support // Currently, we do not support multiple threads!!! int mSharing; SharingSetData<E> share() { ++mSharing; return this; } SharingSetData<E> detach() { if (mSharing != 0) { // one shared access less --mSharing; return new SharingSetData<E>(this); } return this; } } private SharingSetData<E> mData; public SharingSet() { mData = new SharingSetData<E>(); } public SharingSet(SharingSet<E> other) { mData = other.mData.share(); } // UNMODIFIABLE sharing set... public SharingSet(E obj) { mData = new SharingSetData<E>(obj); } @Override public Iterator<E> iterator() { return new Iterator<E>() { Iterator<E> mSink = mData.mRep.iterator(); @Override public boolean hasNext() { return mSink.hasNext(); } @Override public E next() { return mSink.next(); } @Override public void remove() { throw new UnsupportedOperationException( "remove not allowed on SharingSet iterator"); } }; } @Override public int size() { return mData.mRep.size(); } @Override public boolean removeAll(Collection<?> c) { final SharingSetData<E> data = mData.detach(); final boolean res = data.mRep.removeAll(c); if (res) { mData = data; } return res; } @Override public boolean add(E e) { if (mData.mRep.contains(e)) { return false; } mData = mData.detach(); return mData.mRep.add(e); } @Override public boolean addAll(Collection<? extends E> c) { if (mData.mRep.containsAll(c)) { return false; } mData = mData.detach(); return mData.mRep.addAll(c); } // Optimization for sharing sets... public boolean addShared(SharingSet<E> other) { if (other == null) { return false; } if (mData.mRep.isEmpty() && mData.mSharing == 0) { mData = other.mData.share(); return true; } return addAll(other.mData.mRep); } @Override public boolean contains(Object o) { return mData.mRep.contains(o); } @Override public boolean containsAll(Collection<?> c) { return mData.mRep.containsAll(c); } @Override public boolean remove(Object o) { if (mData.mRep.contains(o)) { mData = mData.detach(); return mData.mRep.remove(o); } return false; } }