com.google.common.collect.Constraints Maven / Gradle / Ivy
/*
* 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.
*
* 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 Collection constrainedCollection(
Collection collection, Constraint super E> constraint) {
return new ConstrainedCollection(collection, constraint);
}
/** @see Constraints#constrainedCollection */
static class ConstrainedCollection extends ForwardingCollection {
private final Collection delegate;
private final Constraint super E> constraint;
public ConstrainedCollection(
Collection delegate, Constraint super E> constraint) {
this.delegate = checkNotNull(delegate);
this.constraint = checkNotNull(constraint);
}
@Override protected Collection 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.
*
* 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 Set constrainedSet(
Set set, Constraint super E> constraint) {
return new ConstrainedSet(set, constraint);
}
/** @see Constraints#constrainedSet */
static class ConstrainedSet extends ForwardingSet {
private final Set delegate;
private final Constraint super E> constraint;
public ConstrainedSet(Set delegate, Constraint super E> constraint) {
this.delegate = checkNotNull(delegate);
this.constraint = checkNotNull(constraint);
}
@Override protected Set 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.
*
* 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 SortedSet constrainedSortedSet(
SortedSet sortedSet, Constraint super E> constraint) {
return new ConstrainedSortedSet(sortedSet, constraint);
}
/** @see Constraints#constrainedSortedSet */
private static class ConstrainedSortedSet extends ForwardingSortedSet {
final SortedSet delegate;
final Constraint super E> constraint;
ConstrainedSortedSet(
SortedSet delegate, Constraint super E> constraint) {
this.delegate = checkNotNull(delegate);
this.constraint = checkNotNull(constraint);
}
@Override protected SortedSet delegate() {
return delegate;
}
@Override public SortedSet headSet(E toElement) {
return constrainedSortedSet(delegate.headSet(toElement), constraint);
}
@Override public SortedSet subSet(E fromElement, E toElement) {
return constrainedSortedSet(
delegate.subSet(fromElement, toElement), constraint);
}
@Override public SortedSet 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.
*
* 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 List constrainedList(
List list, Constraint super E> constraint) {
return (list instanceof RandomAccess)
? new ConstrainedRandomAccessList(list, constraint)
: new ConstrainedList(list, constraint);
}
/** @see Constraints#constrainedList */
@GwtCompatible
private static class ConstrainedList extends ForwardingList {
final List delegate;
final Constraint super E> constraint;
ConstrainedList(List delegate, Constraint super E> constraint) {
this.delegate = checkNotNull(delegate);
this.constraint = checkNotNull(constraint);
}
@Override protected List 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 listIterator() {
return constrainedListIterator(delegate.listIterator(), constraint);
}
@Override public ListIterator 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 subList(int fromIndex, int toIndex) {
return constrainedList(
delegate.subList(fromIndex, toIndex), constraint);
}
}
/** @see Constraints#constrainedList */
static class ConstrainedRandomAccessList extends ConstrainedList
implements RandomAccess {
ConstrainedRandomAccessList(
List 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 ListIterator constrainedListIterator(
ListIterator listIterator, Constraint super E> constraint) {
return new ConstrainedListIterator(listIterator, constraint);
}
/** @see Constraints#constrainedListIterator */
static class ConstrainedListIterator extends ForwardingListIterator {
private final ListIterator delegate;
private final Constraint super E> constraint;
public ConstrainedListIterator(
ListIterator delegate, Constraint super E> constraint) {
this.delegate = delegate;
this.constraint = constraint;
}
@Override protected ListIterator 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 Collection constrainedTypePreservingCollection(
Collection collection, Constraint constraint) {
if (collection instanceof SortedSet) {
return constrainedSortedSet((SortedSet) collection, constraint);
} else if (collection instanceof Set) {
return constrainedSet((Set) collection, constraint);
} else if (collection instanceof List) {
return constrainedList((List) 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 Collection checkElements(
Collection elements, Constraint super E> constraint) {
Collection copy = Lists.newArrayList(elements);
for (E element : copy) {
constraint.checkElement(element);
}
return copy;
}
}