| /* |
| * 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 com.google.common.annotations.GwtCompatible; |
| |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.RandomAccess; |
| import java.util.Set; |
| import java.util.SortedSet; |
| |
| /** |
| * 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; |
| } |
| } |