341 lines
10 KiB
Java
341 lines
10 KiB
Java
/*
|
|
* Copyright (C) 2007 The Guava Authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.google.common.collect;
|
|
|
|
import static com.google.common.base.Preconditions.checkNotNull;
|
|
|
|
import java.util.Collection;
|
|
import java.util.List;
|
|
import java.util.ListIterator;
|
|
import java.util.RandomAccess;
|
|
import java.util.Set;
|
|
import java.util.SortedSet;
|
|
|
|
import com.google.common.annotations.GwtCompatible;
|
|
|
|
/**
|
|
* Factories and utilities pertaining to the {@link Constraint} interface.
|
|
*
|
|
* @author Mike Bostock
|
|
* @author Jared Levy
|
|
*/
|
|
@GwtCompatible
|
|
final class Constraints {
|
|
private Constraints() {
|
|
}
|
|
|
|
/**
|
|
* Returns a constrained view of the specified collection, using the specified
|
|
* constraint. Any operations that add new elements to the collection will call
|
|
* the provided constraint. However, this method does not verify that existing
|
|
* elements satisfy the constraint.
|
|
*
|
|
* <p>
|
|
* The returned collection is not serializable.
|
|
*
|
|
* @param collection the collection to constrain
|
|
* @param constraint the constraint that validates added elements
|
|
* @return a constrained view of the collection
|
|
*/
|
|
public static <E> Collection<E> constrainedCollection(Collection<E> collection, Constraint<? super E> constraint) {
|
|
return new ConstrainedCollection<E>(collection, constraint);
|
|
}
|
|
|
|
/** @see Constraints#constrainedCollection */
|
|
static class ConstrainedCollection<E> extends ForwardingCollection<E> {
|
|
private final Collection<E> delegate;
|
|
private final Constraint<? super E> constraint;
|
|
|
|
public ConstrainedCollection(Collection<E> delegate, Constraint<? super E> constraint) {
|
|
this.delegate = checkNotNull(delegate);
|
|
this.constraint = checkNotNull(constraint);
|
|
}
|
|
|
|
@Override
|
|
protected Collection<E> delegate() {
|
|
return delegate;
|
|
}
|
|
|
|
@Override
|
|
public boolean add(E element) {
|
|
constraint.checkElement(element);
|
|
return delegate.add(element);
|
|
}
|
|
|
|
@Override
|
|
public boolean addAll(Collection<? extends E> elements) {
|
|
return delegate.addAll(checkElements(elements, constraint));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a constrained view of the specified set, using the specified
|
|
* constraint. Any operations that add new elements to the set will call the
|
|
* provided constraint. However, this method does not verify that existing
|
|
* elements satisfy the constraint.
|
|
*
|
|
* <p>
|
|
* The returned set is not serializable.
|
|
*
|
|
* @param set the set to constrain
|
|
* @param constraint the constraint that validates added elements
|
|
* @return a constrained view of the set
|
|
*/
|
|
public static <E> Set<E> constrainedSet(Set<E> set, Constraint<? super E> constraint) {
|
|
return new ConstrainedSet<E>(set, constraint);
|
|
}
|
|
|
|
/** @see Constraints#constrainedSet */
|
|
static class ConstrainedSet<E> extends ForwardingSet<E> {
|
|
private final Set<E> delegate;
|
|
private final Constraint<? super E> constraint;
|
|
|
|
public ConstrainedSet(Set<E> delegate, Constraint<? super E> constraint) {
|
|
this.delegate = checkNotNull(delegate);
|
|
this.constraint = checkNotNull(constraint);
|
|
}
|
|
|
|
@Override
|
|
protected Set<E> delegate() {
|
|
return delegate;
|
|
}
|
|
|
|
@Override
|
|
public boolean add(E element) {
|
|
constraint.checkElement(element);
|
|
return delegate.add(element);
|
|
}
|
|
|
|
@Override
|
|
public boolean addAll(Collection<? extends E> elements) {
|
|
return delegate.addAll(checkElements(elements, constraint));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a constrained view of the specified sorted set, using the specified
|
|
* constraint. Any operations that add new elements to the sorted set will call
|
|
* the provided constraint. However, this method does not verify that existing
|
|
* elements satisfy the constraint.
|
|
*
|
|
* <p>
|
|
* The returned set is not serializable.
|
|
*
|
|
* @param sortedSet the sorted set to constrain
|
|
* @param constraint the constraint that validates added elements
|
|
* @return a constrained view of the sorted set
|
|
*/
|
|
public static <E> SortedSet<E> constrainedSortedSet(SortedSet<E> sortedSet, Constraint<? super E> constraint) {
|
|
return new ConstrainedSortedSet<E>(sortedSet, constraint);
|
|
}
|
|
|
|
/** @see Constraints#constrainedSortedSet */
|
|
private static class ConstrainedSortedSet<E> extends ForwardingSortedSet<E> {
|
|
final SortedSet<E> delegate;
|
|
final Constraint<? super E> constraint;
|
|
|
|
ConstrainedSortedSet(SortedSet<E> delegate, Constraint<? super E> constraint) {
|
|
this.delegate = checkNotNull(delegate);
|
|
this.constraint = checkNotNull(constraint);
|
|
}
|
|
|
|
@Override
|
|
protected SortedSet<E> delegate() {
|
|
return delegate;
|
|
}
|
|
|
|
@Override
|
|
public SortedSet<E> headSet(E toElement) {
|
|
return constrainedSortedSet(delegate.headSet(toElement), constraint);
|
|
}
|
|
|
|
@Override
|
|
public SortedSet<E> subSet(E fromElement, E toElement) {
|
|
return constrainedSortedSet(delegate.subSet(fromElement, toElement), constraint);
|
|
}
|
|
|
|
@Override
|
|
public SortedSet<E> tailSet(E fromElement) {
|
|
return constrainedSortedSet(delegate.tailSet(fromElement), constraint);
|
|
}
|
|
|
|
@Override
|
|
public boolean add(E element) {
|
|
constraint.checkElement(element);
|
|
return delegate.add(element);
|
|
}
|
|
|
|
@Override
|
|
public boolean addAll(Collection<? extends E> elements) {
|
|
return delegate.addAll(checkElements(elements, constraint));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a constrained view of the specified list, using the specified
|
|
* constraint. Any operations that add new elements to the list will call the
|
|
* provided constraint. However, this method does not verify that existing
|
|
* elements satisfy the constraint.
|
|
*
|
|
* <p>
|
|
* If {@code list} implements {@link RandomAccess}, so will the returned list.
|
|
* The returned list is not serializable.
|
|
*
|
|
* @param list the list to constrain
|
|
* @param constraint the constraint that validates added elements
|
|
* @return a constrained view of the list
|
|
*/
|
|
public static <E> List<E> constrainedList(List<E> list, Constraint<? super E> constraint) {
|
|
return (list instanceof RandomAccess) ? new ConstrainedRandomAccessList<E>(list, constraint)
|
|
: new ConstrainedList<E>(list, constraint);
|
|
}
|
|
|
|
/** @see Constraints#constrainedList */
|
|
@GwtCompatible
|
|
private static class ConstrainedList<E> extends ForwardingList<E> {
|
|
final List<E> delegate;
|
|
final Constraint<? super E> constraint;
|
|
|
|
ConstrainedList(List<E> delegate, Constraint<? super E> constraint) {
|
|
this.delegate = checkNotNull(delegate);
|
|
this.constraint = checkNotNull(constraint);
|
|
}
|
|
|
|
@Override
|
|
protected List<E> delegate() {
|
|
return delegate;
|
|
}
|
|
|
|
@Override
|
|
public boolean add(E element) {
|
|
constraint.checkElement(element);
|
|
return delegate.add(element);
|
|
}
|
|
|
|
@Override
|
|
public void add(int index, E element) {
|
|
constraint.checkElement(element);
|
|
delegate.add(index, element);
|
|
}
|
|
|
|
@Override
|
|
public boolean addAll(Collection<? extends E> elements) {
|
|
return delegate.addAll(checkElements(elements, constraint));
|
|
}
|
|
|
|
@Override
|
|
public boolean addAll(int index, Collection<? extends E> elements) {
|
|
return delegate.addAll(index, checkElements(elements, constraint));
|
|
}
|
|
|
|
@Override
|
|
public ListIterator<E> listIterator() {
|
|
return constrainedListIterator(delegate.listIterator(), constraint);
|
|
}
|
|
|
|
@Override
|
|
public ListIterator<E> listIterator(int index) {
|
|
return constrainedListIterator(delegate.listIterator(index), constraint);
|
|
}
|
|
|
|
@Override
|
|
public E set(int index, E element) {
|
|
constraint.checkElement(element);
|
|
return delegate.set(index, element);
|
|
}
|
|
|
|
@Override
|
|
public List<E> subList(int fromIndex, int toIndex) {
|
|
return constrainedList(delegate.subList(fromIndex, toIndex), constraint);
|
|
}
|
|
}
|
|
|
|
/** @see Constraints#constrainedList */
|
|
static class ConstrainedRandomAccessList<E> extends ConstrainedList<E> implements RandomAccess {
|
|
ConstrainedRandomAccessList(List<E> delegate, Constraint<? super E> constraint) {
|
|
super(delegate, constraint);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a constrained view of the specified list iterator, using the
|
|
* specified constraint. Any operations that would add new elements to the
|
|
* underlying list will be verified by the constraint.
|
|
*
|
|
* @param listIterator the iterator for which to return a constrained view
|
|
* @param constraint the constraint for elements in the list
|
|
* @return a constrained view of the specified iterator
|
|
*/
|
|
private static <E> ListIterator<E> constrainedListIterator(ListIterator<E> listIterator,
|
|
Constraint<? super E> constraint) {
|
|
return new ConstrainedListIterator<E>(listIterator, constraint);
|
|
}
|
|
|
|
/** @see Constraints#constrainedListIterator */
|
|
static class ConstrainedListIterator<E> extends ForwardingListIterator<E> {
|
|
private final ListIterator<E> delegate;
|
|
private final Constraint<? super E> constraint;
|
|
|
|
public ConstrainedListIterator(ListIterator<E> delegate, Constraint<? super E> constraint) {
|
|
this.delegate = delegate;
|
|
this.constraint = constraint;
|
|
}
|
|
|
|
@Override
|
|
protected ListIterator<E> delegate() {
|
|
return delegate;
|
|
}
|
|
|
|
@Override
|
|
public void add(E element) {
|
|
constraint.checkElement(element);
|
|
delegate.add(element);
|
|
}
|
|
|
|
@Override
|
|
public void set(E element) {
|
|
constraint.checkElement(element);
|
|
delegate.set(element);
|
|
}
|
|
}
|
|
|
|
static <E> Collection<E> constrainedTypePreservingCollection(Collection<E> collection, Constraint<E> constraint) {
|
|
if (collection instanceof SortedSet) {
|
|
return constrainedSortedSet((SortedSet<E>) collection, constraint);
|
|
} else if (collection instanceof Set) {
|
|
return constrainedSet((Set<E>) collection, constraint);
|
|
} else if (collection instanceof List) {
|
|
return constrainedList((List<E>) collection, constraint);
|
|
} else {
|
|
return constrainedCollection(collection, constraint);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* TODO(kevinb): For better performance, avoid making a copy of the elements by
|
|
* having addAll() call add() repeatedly instead.
|
|
*/
|
|
|
|
private static <E> Collection<E> checkElements(Collection<E> elements, Constraint<? super E> constraint) {
|
|
Collection<E> copy = Lists.newArrayList(elements);
|
|
for (E element : copy) {
|
|
constraint.checkElement(element);
|
|
}
|
|
return copy;
|
|
}
|
|
}
|