/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * This file was originally derived from the Polyglot extensible compiler framework. * * (C) Copyright 2000-2007 Polyglot project group, Cornell University * (C) Copyright IBM Corporation 2007-2012. */ package polyglot.util; import java.util.*; import polyglot.types.*; /** * Class to implement sets containing <code>polyglot.types.Type </code>. * Set membership is based on the subtype relationships. Thus, if * <code>S</code> is a supertype of <code>A</code> and <code>B</code>, then * { <code>S</code> } union { <code>A</code>,<code>B</code> } = * { <code>S</code> }. Similarily, we remove elements from the set such * that if <code>s</code> is an element of a set <code>S</code>, then a * call to remove <code>r</code> removes all <code>s</code> s.t. r is a * a supertype of s. */ public class SubtypeSet implements java.util.Set<Type> { protected List<Type> v; protected TypeSystem ts; protected Type topType; // Everything in the set must be a subtype of topType. /** * Creates an empty SubtypeSet */ public SubtypeSet(TypeSystem ts) { this(ts.Any()); } public SubtypeSet(Type top) { v = new ArrayList<Type>(); this.ts = top.typeSystem(); this.topType = top; } /** * Creates a copy of the given SubtypeSet */ public SubtypeSet(SubtypeSet s) { v = new ArrayList<Type>(s.v); ts = s.ts; topType = s.topType; } public SubtypeSet(TypeSystem ts, Collection<Type> c) { this(ts); addAll(c); } public SubtypeSet(Type top, Collection<Type> c) { this(top); addAll(c); } /** * Add an element of type <code>polyglot.types.Type</code> to the set * only if it has no supertypes already in the set. If we do add it, * remove any subtypes of <code>o</code> * * @param o The element to add. */ public boolean add(Type o) { if (o == null) { return false; } Type type = o; Context context = ts.emptyContext(); if (ts.isSubtype(type, topType, context)) { boolean haveToAdd = true; for (Iterator<Type> i = v.iterator(); i.hasNext(); ) { Type t = i.next(); if (! ts.typeEquals(t, type, context) && ts.isSubtype(t, type, context)) { i.remove(); } if (ts.isSubtype(type, t, context)) { haveToAdd = false; break; } } if (haveToAdd) { v.add(type); } return haveToAdd; } return false; } /** * Adds all elements from c into this set. */ public boolean addAll(Collection<? extends Type> c) { if (c == null) { return false; } boolean changed = false; for (Type t : c) { changed |= add(t); } return changed; } /** * Removes all elements from the set */ public void clear() { v.clear(); } /** * Check whether object <code>o</code> is in the set. Because of the * semantics of the subtype set, <code>o</code> is in the set iff * it descends from (or is equal to) one of the elements in the set. */ public boolean contains(Object o) { if (o instanceof Type) { Type type = (Type) o; Context context = ts.emptyContext(); for (Iterator<Type> i = v.iterator(); i.hasNext(); ) { Type t = (Type) i.next(); if (ts.isSubtype(type, t, context)) { return true; } } } return false; } /** * Check whether the type <code>t</code> or a subtype is in the set. * Returns true iff it descends from, is equal to, or is a super type of * one of the elements in the set. */ public boolean containsSubtype(Type type) { Context context = ts.emptyContext(); for (Iterator<Type> i = v.iterator(); i.hasNext(); ) { Type t = (Type)i.next(); if (ts.isSubtype(type, t, context) || ts.isSubtype(t, type, context)) return true; } return false; } /** * Checks whether all elements of the collection are in the set */ public boolean containsAll(Collection<?> c) { for (Object o : c) { if (! contains(o)) { return false; } } return true; } public boolean isEmpty() { return v.isEmpty(); } public Iterator<Type> iterator() { return v.iterator(); } /** * Removes all elements <code>s</code> in the set such that * <code>s</code> decends from <code>o</code> * * @return whether or not an element was removed. */ public boolean remove(Object o) { if (! (o instanceof Type)) { return false; } Type type = (Type) o; Context context = ts.emptyContext(); boolean removed = false; for (Iterator<Type> i = v.iterator(); i.hasNext(); ) { Type t = (Type) i.next(); if (ts.isSubtype(t, type, context)) { removed = true; i.remove(); } } return removed; } public boolean removeAll(Collection<?> c) { boolean changed = false; for (Object o : c) { changed |= remove(o); } return changed; } public boolean retainAll(Collection<?> c) { throw new UnsupportedOperationException("Not supported"); } public int size() { return v.size(); } public Object[] toArray() { return v.toArray(); } public <S> S[] toArray(S[] a) { return v.toArray(a); } public String toString() { return v.toString(); } }