/*
* 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;
}
}