• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.collect;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 
21 import com.google.common.annotations.GwtCompatible;
22 
23 import java.util.Collection;
24 import java.util.List;
25 import java.util.ListIterator;
26 import java.util.RandomAccess;
27 import java.util.Set;
28 import java.util.SortedSet;
29 
30 /**
31  * Factories and utilities pertaining to the {@link Constraint} interface.
32  *
33  * @author Mike Bostock
34  * @author Jared Levy
35  */
36 @GwtCompatible
37 final class Constraints {
Constraints()38   private Constraints() {}
39 
40   /**
41    * Returns a constrained view of the specified collection, using the specified
42    * constraint. Any operations that add new elements to the collection will
43    * call the provided constraint. However, this method does not verify that
44    * existing elements satisfy the constraint.
45    *
46    * <p>The returned collection is not serializable.
47    *
48    * @param collection the collection to constrain
49    * @param constraint the constraint that validates added elements
50    * @return a constrained view of the collection
51    */
constrainedCollection( Collection<E> collection, Constraint<? super E> constraint)52   public static <E> Collection<E> constrainedCollection(
53       Collection<E> collection, Constraint<? super E> constraint) {
54     return new ConstrainedCollection<E>(collection, constraint);
55   }
56 
57   /** @see Constraints#constrainedCollection */
58   static class ConstrainedCollection<E> extends ForwardingCollection<E> {
59     private final Collection<E> delegate;
60     private final Constraint<? super E> constraint;
61 
ConstrainedCollection( Collection<E> delegate, Constraint<? super E> constraint)62     public ConstrainedCollection(
63         Collection<E> delegate, Constraint<? super E> constraint) {
64       this.delegate = checkNotNull(delegate);
65       this.constraint = checkNotNull(constraint);
66     }
delegate()67     @Override protected Collection<E> delegate() {
68       return delegate;
69     }
add(E element)70     @Override public boolean add(E element) {
71       constraint.checkElement(element);
72       return delegate.add(element);
73     }
addAll(Collection<? extends E> elements)74     @Override public boolean addAll(Collection<? extends E> elements) {
75       return delegate.addAll(checkElements(elements, constraint));
76     }
77   }
78 
79   /**
80    * Returns a constrained view of the specified set, using the specified
81    * constraint. Any operations that add new elements to the set will call the
82    * provided constraint. However, this method does not verify that existing
83    * elements satisfy the constraint.
84    *
85    * <p>The returned set is not serializable.
86    *
87    * @param set the set to constrain
88    * @param constraint the constraint that validates added elements
89    * @return a constrained view of the set
90    */
constrainedSet( Set<E> set, Constraint<? super E> constraint)91   public static <E> Set<E> constrainedSet(
92       Set<E> set, Constraint<? super E> constraint) {
93     return new ConstrainedSet<E>(set, constraint);
94   }
95 
96   /** @see Constraints#constrainedSet */
97   static class ConstrainedSet<E> extends ForwardingSet<E> {
98     private final Set<E> delegate;
99     private final Constraint<? super E> constraint;
100 
ConstrainedSet(Set<E> delegate, Constraint<? super E> constraint)101     public ConstrainedSet(Set<E> delegate, Constraint<? super E> constraint) {
102       this.delegate = checkNotNull(delegate);
103       this.constraint = checkNotNull(constraint);
104     }
delegate()105     @Override protected Set<E> delegate() {
106       return delegate;
107     }
add(E element)108     @Override public boolean add(E element) {
109       constraint.checkElement(element);
110       return delegate.add(element);
111     }
addAll(Collection<? extends E> elements)112     @Override public boolean addAll(Collection<? extends E> elements) {
113       return delegate.addAll(checkElements(elements, constraint));
114     }
115   }
116 
117   /**
118    * Returns a constrained view of the specified sorted set, using the specified
119    * constraint. Any operations that add new elements to the sorted set will
120    * call the provided constraint. However, this method does not verify that
121    * existing elements satisfy the constraint.
122    *
123    * <p>The returned set is not serializable.
124    *
125    * @param sortedSet the sorted set to constrain
126    * @param constraint the constraint that validates added elements
127    * @return a constrained view of the sorted set
128    */
constrainedSortedSet( SortedSet<E> sortedSet, Constraint<? super E> constraint)129   public static <E> SortedSet<E> constrainedSortedSet(
130       SortedSet<E> sortedSet, Constraint<? super E> constraint) {
131     return new ConstrainedSortedSet<E>(sortedSet, constraint);
132   }
133 
134   /** @see Constraints#constrainedSortedSet */
135   private static class ConstrainedSortedSet<E> extends ForwardingSortedSet<E> {
136     final SortedSet<E> delegate;
137     final Constraint<? super E> constraint;
138 
ConstrainedSortedSet( SortedSet<E> delegate, Constraint<? super E> constraint)139     ConstrainedSortedSet(
140         SortedSet<E> delegate, Constraint<? super E> constraint) {
141       this.delegate = checkNotNull(delegate);
142       this.constraint = checkNotNull(constraint);
143     }
delegate()144     @Override protected SortedSet<E> delegate() {
145       return delegate;
146     }
headSet(E toElement)147     @Override public SortedSet<E> headSet(E toElement) {
148       return constrainedSortedSet(delegate.headSet(toElement), constraint);
149     }
subSet(E fromElement, E toElement)150     @Override public SortedSet<E> subSet(E fromElement, E toElement) {
151       return constrainedSortedSet(
152           delegate.subSet(fromElement, toElement), constraint);
153     }
tailSet(E fromElement)154     @Override public SortedSet<E> tailSet(E fromElement) {
155       return constrainedSortedSet(delegate.tailSet(fromElement), constraint);
156     }
add(E element)157     @Override public boolean add(E element) {
158       constraint.checkElement(element);
159       return delegate.add(element);
160     }
addAll(Collection<? extends E> elements)161     @Override public boolean addAll(Collection<? extends E> elements) {
162       return delegate.addAll(checkElements(elements, constraint));
163     }
164   }
165 
166   /**
167    * Returns a constrained view of the specified list, using the specified
168    * constraint. Any operations that add new elements to the list will call the
169    * provided constraint. However, this method does not verify that existing
170    * elements satisfy the constraint.
171    *
172    * <p>If {@code list} implements {@link RandomAccess}, so will the returned
173    * list. The returned list is not serializable.
174    *
175    * @param list the list to constrain
176    * @param constraint the constraint that validates added elements
177    * @return a constrained view of the list
178    */
constrainedList( List<E> list, Constraint<? super E> constraint)179   public static <E> List<E> constrainedList(
180       List<E> list, Constraint<? super E> constraint) {
181     return (list instanceof RandomAccess)
182         ? new ConstrainedRandomAccessList<E>(list, constraint)
183         : new ConstrainedList<E>(list, constraint);
184   }
185 
186   /** @see Constraints#constrainedList */
187   @GwtCompatible
188   private static class ConstrainedList<E> extends ForwardingList<E> {
189     final List<E> delegate;
190     final Constraint<? super E> constraint;
191 
ConstrainedList(List<E> delegate, Constraint<? super E> constraint)192     ConstrainedList(List<E> delegate, Constraint<? super E> constraint) {
193       this.delegate = checkNotNull(delegate);
194       this.constraint = checkNotNull(constraint);
195     }
delegate()196     @Override protected List<E> delegate() {
197       return delegate;
198     }
199 
add(E element)200     @Override public boolean add(E element) {
201       constraint.checkElement(element);
202       return delegate.add(element);
203     }
add(int index, E element)204     @Override public void add(int index, E element) {
205       constraint.checkElement(element);
206       delegate.add(index, element);
207     }
addAll(Collection<? extends E> elements)208     @Override public boolean addAll(Collection<? extends E> elements) {
209       return delegate.addAll(checkElements(elements, constraint));
210     }
addAll(int index, Collection<? extends E> elements)211     @Override public boolean addAll(int index, Collection<? extends E> elements)
212     {
213       return delegate.addAll(index, checkElements(elements, constraint));
214     }
listIterator()215     @Override public ListIterator<E> listIterator() {
216       return constrainedListIterator(delegate.listIterator(), constraint);
217     }
listIterator(int index)218     @Override public ListIterator<E> listIterator(int index) {
219       return constrainedListIterator(delegate.listIterator(index), constraint);
220     }
set(int index, E element)221     @Override public E set(int index, E element) {
222       constraint.checkElement(element);
223       return delegate.set(index, element);
224     }
subList(int fromIndex, int toIndex)225     @Override public List<E> subList(int fromIndex, int toIndex) {
226       return constrainedList(
227           delegate.subList(fromIndex, toIndex), constraint);
228     }
229   }
230 
231   /** @see Constraints#constrainedList */
232   static class ConstrainedRandomAccessList<E> extends ConstrainedList<E>
233       implements RandomAccess {
ConstrainedRandomAccessList( List<E> delegate, Constraint<? super E> constraint)234     ConstrainedRandomAccessList(
235         List<E> delegate, Constraint<? super E> constraint) {
236       super(delegate, constraint);
237     }
238   }
239 
240   /**
241    * Returns a constrained view of the specified list iterator, using the
242    * specified constraint. Any operations that would add new elements to the
243    * underlying list will be verified by the constraint.
244    *
245    * @param listIterator the iterator for which to return a constrained view
246    * @param constraint the constraint for elements in the list
247    * @return a constrained view of the specified iterator
248    */
constrainedListIterator( ListIterator<E> listIterator, Constraint<? super E> constraint)249   private static <E> ListIterator<E> constrainedListIterator(
250       ListIterator<E> listIterator, Constraint<? super E> constraint) {
251     return new ConstrainedListIterator<E>(listIterator, constraint);
252   }
253 
254   /** @see Constraints#constrainedListIterator */
255   static class ConstrainedListIterator<E> extends ForwardingListIterator<E> {
256     private final ListIterator<E> delegate;
257     private final Constraint<? super E> constraint;
258 
ConstrainedListIterator( ListIterator<E> delegate, Constraint<? super E> constraint)259     public ConstrainedListIterator(
260         ListIterator<E> delegate, Constraint<? super E> constraint) {
261       this.delegate = delegate;
262       this.constraint = constraint;
263     }
delegate()264     @Override protected ListIterator<E> delegate() {
265       return delegate;
266     }
267 
add(E element)268     @Override public void add(E element) {
269       constraint.checkElement(element);
270       delegate.add(element);
271     }
set(E element)272     @Override public void set(E element) {
273       constraint.checkElement(element);
274       delegate.set(element);
275     }
276   }
277 
constrainedTypePreservingCollection( Collection<E> collection, Constraint<E> constraint)278   static <E> Collection<E> constrainedTypePreservingCollection(
279       Collection<E> collection, Constraint<E> constraint) {
280     if (collection instanceof SortedSet) {
281       return constrainedSortedSet((SortedSet<E>) collection, constraint);
282     } else if (collection instanceof Set) {
283       return constrainedSet((Set<E>) collection, constraint);
284     } else if (collection instanceof List) {
285       return constrainedList((List<E>) collection, constraint);
286     } else {
287       return constrainedCollection(collection, constraint);
288     }
289   }
290 
291   /*
292    * TODO(kevinb): For better performance, avoid making a copy of the elements
293    * by having addAll() call add() repeatedly instead.
294    */
295 
checkElements( Collection<E> elements, Constraint<? super E> constraint)296   private static <E> Collection<E> checkElements(
297       Collection<E> elements, Constraint<? super E> constraint) {
298     Collection<E> copy = Lists.newArrayList(elements);
299     for (E element : copy) {
300       constraint.checkElement(element);
301     }
302     return copy;
303   }
304 }
305