/*
* 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.*;
/**
* A TypedList is an List which will not allow members not belonging
* to a given type to be added to a collection. Optionally, it may
* also present an immutable view.
*
* If an attempt is made to change an immutable list, or if an attempt
* is made to insert an improperly-typed element, an
* UnsupportedOperationException is thrown.
*
* This class is given so that we can present a List for a given class
* without worrying about outsiders breaking the rep.
*
* This is a poor substitute for PolyJ.
**/
public class TypedList<T> implements List<T>, java.io.Serializable, Cloneable
{
static final long serialVersionUID = -1390984392613203018L;
/**
* Requires: <list> not null, and every element of <list> may be
* cast to class <c>.
* Creates a new TypedList, containing all the elements of <list>,
* which restricts all members to belong to class <c>. If <c> is
* null, no typing restriction is made. If <immutable> is true, no
* modifications are allowed.
**/
public static <T> TypedList<T> copy(List<? extends T> list, Class<? super T> c, boolean immutable) {
if (list == null)
return null;
return new TypedList<T>(new ArrayList<T>(list), c, immutable);
}
/**
* Creates a new TypedList, containing all the elements of <list>,
* which restricts all members to belong to class <c>. If <c> is
* null, no typing restriction is made. If <immutable> is true, no
* modifications are allowed.
*
* Throws an UnsupportedOperationException if any member of <list>
* may not be cast to class <c>.
**/
public static <T> TypedList<T> copyAndCheck(List<? extends T> list, Class<? super T> c, boolean immutable) {
if (c != null)
check(list,c);
return copy(list,c,immutable);
}
/**
* Throws an UnsupportedOperationException if any member of <list>
* may not be cast to class <c>. Otherwise does nothing.
**/
public static <T> void check(List<? extends T> list, Class<? super T> c) {
if (list == null)
return;
for (T o : list) {
if (o != null && !c.isAssignableFrom(o.getClass())) {
throw new UnsupportedOperationException(
"Tried to add a " + o.getClass().getName() +
" to a list of type " + c.getName());
}
}
}
/**
* Requires: <list> not null, and every element of <list> may be
* cast to class <c>.
* Effects:
* Creates a new TypedList around <list> which restricts all
* members to belong to class <c>. If <c> is null, no typing
* restriction is made. If <immutable> is true, no modifications
* are allowed.
**/
public TypedList(List<T> list, Class<? super T> c, boolean immutable) {
this.immutable = immutable;
this.allowed_type = c;
this.backing_list = list;
}
/**
* Gets the allowed type for this list.
**/
public Class<? super T> getAllowedType(){
return allowed_type;
}
/**
* Copies this list.
**/
@SuppressWarnings("unchecked") // Casting to a generic type
public TypedList<T> copy() {
return (TypedList<T>) clone();
}
@SuppressWarnings("unchecked") // Casting to a generic type
public Object clone() {
try {
TypedList<T> l = (TypedList<T>) super.clone();
l.backing_list = new ArrayList<T>(backing_list);
return l;
}
catch (CloneNotSupportedException e) {
throw new InternalCompilerError("Java clone weirdness.");
}
}
public void add(int idx, T o) {
tryIns(o);
backing_list.add(idx,o);
}
public boolean add(T o) {
tryIns(o);
return backing_list.add(o);
}
public boolean addAll(int idx, Collection<? extends T> coll) {
tryIns(coll);
return backing_list.addAll(idx, coll);
}
public boolean addAll(Collection<? extends T> coll) {
tryIns(coll);
return backing_list.addAll(coll);
}
public ListIterator<T> listIterator() {
return new TypedListIterator<T>(backing_list.listIterator(),
allowed_type,
immutable);
}
public ListIterator<T> listIterator(int idx) {
return new TypedListIterator<T>(backing_list.listIterator(idx),
allowed_type,
immutable);
}
public T set(int idx, T o) {
tryIns(o);
return backing_list.set(idx, o);
}
public List<T> subList(int from, int to) {
return new TypedList<T>(backing_list.subList(from, to),
allowed_type,
immutable);
}
public boolean equals(Object o) {
if (this == o)
return true;
if (backing_list == o)
return true;
if (! (o instanceof List<?>))
return false;
if (((List<?>) o).size() != backing_list.size())
return false;
if (o instanceof TypedList<?>)
return backing_list.equals(((TypedList<?>) o).backing_list);
else
return backing_list.equals(o);
}
public void clear()
{ tryMod(); backing_list.clear(); }
public boolean contains(Object o)
{ return backing_list.contains(o); }
public boolean containsAll(Collection<?> coll)
{ return backing_list.containsAll(coll); }
public T get(int idx)
{ return backing_list.get(idx); }
public int hashCode()
{ return backing_list.hashCode(); }
public int indexOf(Object o)
{ return backing_list.indexOf(o); }
public boolean isEmpty()
{ return backing_list.isEmpty(); }
public Iterator<T> iterator()
{ return listIterator(); }
public int lastIndexOf(Object o)
{ return backing_list.lastIndexOf(o); }
public T remove(int idx)
{ tryMod(); return backing_list.remove(idx); }
public boolean remove(Object o)
{ tryMod(); return backing_list.remove(o); }
public boolean removeAll(Collection<?> coll)
{ tryMod(); return backing_list.removeAll(coll); }
public boolean retainAll(Collection<?> coll)
{ tryMod(); return backing_list.retainAll(coll); }
public int size()
{ return backing_list.size(); }
public Object[] toArray()
{ return backing_list.toArray(); }
public <S> S[] toArray(S[] oa)
{ return backing_list.toArray(oa); }
public String toString()
{ return backing_list.toString(); }
private final void tryIns(T o) {
if (immutable)
throw new UnsupportedOperationException(
"Add to an immutable TypedListIterator");
if (allowed_type != null && o != null &&
!allowed_type.isAssignableFrom(o.getClass())) {
String why = "Tried to add a " + o.getClass().getName() +
" to a list of type " + allowed_type.getName();
throw new UnsupportedOperationException(why);
}
}
private final void tryIns(Collection<? extends T> coll) {
if (immutable)
throw new UnsupportedOperationException(
"Add to an immutable TypedListIterator");
for (Iterator<? extends T> it = coll.iterator(); it.hasNext(); ) {
T o = it.next();
tryIns(o);
}
}
private final void tryMod() {
if (immutable)
throw new UnsupportedOperationException(
"Change to an immutable TypedListIterator");
}
// RI: allowed_type may be null.
private Class<? super T> allowed_type;
private boolean immutable;
private List<T> backing_list;
}