001/*
002 * Copyright (C) 2007 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect;
018
019import static com.google.common.base.Preconditions.checkNotNull;
020
021import com.google.common.annotations.Beta;
022import com.google.common.annotations.GwtCompatible;
023import com.google.common.base.Preconditions;
024
025import java.util.Collection;
026import java.util.List;
027import java.util.ListIterator;
028import java.util.RandomAccess;
029import java.util.Set;
030import java.util.SortedSet;
031
032/**
033 * Factories and utilities pertaining to the {@link Constraint} interface.
034 *
035 * @see MapConstraints
036 * @author Mike Bostock
037 * @author Jared Levy
038 * @since 3.0
039 * @deprecated Use {@link Preconditions} for basic checks. In place of
040 *     constrained collections, we encourage you to check your preconditions
041 *     explicitly instead of leaving that work to the collection implementation.
042 *     For the specific case of rejecting null, consider the immutable
043 *     collections.
044 *     This class is scheduled for removal in Guava 16.0.
045 */
046@Beta
047@Deprecated
048@GwtCompatible
049public final class Constraints {
050  private Constraints() {}
051
052  // enum singleton pattern
053  private enum NotNullConstraint implements Constraint<Object> {
054    INSTANCE;
055
056    @Override
057    public Object checkElement(Object element) {
058      return checkNotNull(element);
059    }
060
061    @Override public String toString() {
062      return "Not null";
063    }
064  }
065
066  /**
067   * Returns a constraint that verifies that the element is not null. If the
068   * element is null, a {@link NullPointerException} is thrown.
069   */
070  // safe to narrow the type since checkElement returns its argument directly
071  @SuppressWarnings("unchecked")
072  public static <E> Constraint<E> notNull() {
073    return (Constraint<E>) NotNullConstraint.INSTANCE;
074  }
075
076  /**
077   * Returns a constrained view of the specified collection, using the specified
078   * constraint. Any operations that add new elements to the collection will
079   * call the provided constraint. However, this method does not verify that
080   * existing elements satisfy the constraint.
081   *
082   * <p>The returned collection is not serializable.
083   *
084   * @param collection the collection to constrain
085   * @param constraint the constraint that validates added elements
086   * @return a constrained view of the collection
087   */
088  public static <E> Collection<E> constrainedCollection(
089      Collection<E> collection, Constraint<? super E> constraint) {
090    return new ConstrainedCollection<E>(collection, constraint);
091  }
092
093  /** @see Constraints#constrainedCollection */
094  static class ConstrainedCollection<E> extends ForwardingCollection<E> {
095    private final Collection<E> delegate;
096    private final Constraint<? super E> constraint;
097
098    public ConstrainedCollection(
099        Collection<E> delegate, Constraint<? super E> constraint) {
100      this.delegate = checkNotNull(delegate);
101      this.constraint = checkNotNull(constraint);
102    }
103    @Override protected Collection<E> delegate() {
104      return delegate;
105    }
106    @Override public boolean add(E element) {
107      constraint.checkElement(element);
108      return delegate.add(element);
109    }
110    @Override public boolean addAll(Collection<? extends E> elements) {
111      return delegate.addAll(checkElements(elements, constraint));
112    }
113  }
114
115  /**
116   * Returns a constrained view of the specified set, using the specified
117   * constraint. Any operations that add new elements to the set will call the
118   * provided constraint. However, this method does not verify that existing
119   * elements satisfy the constraint.
120   *
121   * <p>The returned set is not serializable.
122   *
123   * @param set the set to constrain
124   * @param constraint the constraint that validates added elements
125   * @return a constrained view of the set
126   */
127  public static <E> Set<E> constrainedSet(
128      Set<E> set, Constraint<? super E> constraint) {
129    return new ConstrainedSet<E>(set, constraint);
130  }
131
132  /** @see Constraints#constrainedSet */
133  static class ConstrainedSet<E> extends ForwardingSet<E> {
134    private final Set<E> delegate;
135    private final Constraint<? super E> constraint;
136
137    public ConstrainedSet(Set<E> delegate, Constraint<? super E> constraint) {
138      this.delegate = checkNotNull(delegate);
139      this.constraint = checkNotNull(constraint);
140    }
141    @Override protected Set<E> delegate() {
142      return delegate;
143    }
144    @Override public boolean add(E element) {
145      constraint.checkElement(element);
146      return delegate.add(element);
147    }
148    @Override public boolean addAll(Collection<? extends E> elements) {
149      return delegate.addAll(checkElements(elements, constraint));
150    }
151  }
152
153  /**
154   * Returns a constrained view of the specified sorted set, using the specified
155   * constraint. Any operations that add new elements to the sorted set will
156   * call the provided constraint. However, this method does not verify that
157   * existing elements satisfy the constraint.
158   *
159   * <p>The returned set is not serializable.
160   *
161   * @param sortedSet the sorted set to constrain
162   * @param constraint the constraint that validates added elements
163   * @return a constrained view of the sorted set
164   */
165  public static <E> SortedSet<E> constrainedSortedSet(
166      SortedSet<E> sortedSet, Constraint<? super E> constraint) {
167    return new ConstrainedSortedSet<E>(sortedSet, constraint);
168  }
169
170  /** @see Constraints#constrainedSortedSet */
171  private static class ConstrainedSortedSet<E> extends ForwardingSortedSet<E> {
172    final SortedSet<E> delegate;
173    final Constraint<? super E> constraint;
174
175    ConstrainedSortedSet(
176        SortedSet<E> delegate, Constraint<? super E> constraint) {
177      this.delegate = checkNotNull(delegate);
178      this.constraint = checkNotNull(constraint);
179    }
180    @Override protected SortedSet<E> delegate() {
181      return delegate;
182    }
183    @Override public SortedSet<E> headSet(E toElement) {
184      return constrainedSortedSet(delegate.headSet(toElement), constraint);
185    }
186    @Override public SortedSet<E> subSet(E fromElement, E toElement) {
187      return constrainedSortedSet(
188          delegate.subSet(fromElement, toElement), constraint);
189    }
190    @Override public SortedSet<E> tailSet(E fromElement) {
191      return constrainedSortedSet(delegate.tailSet(fromElement), constraint);
192    }
193    @Override public boolean add(E element) {
194      constraint.checkElement(element);
195      return delegate.add(element);
196    }
197    @Override public boolean addAll(Collection<? extends E> elements) {
198      return delegate.addAll(checkElements(elements, constraint));
199    }
200  }
201
202  /**
203   * Returns a constrained view of the specified list, using the specified
204   * constraint. Any operations that add new elements to the list will call the
205   * provided constraint. However, this method does not verify that existing
206   * elements satisfy the constraint.
207   *
208   * <p>If {@code list} implements {@link RandomAccess}, so will the returned
209   * list. The returned list is not serializable.
210   *
211   * @param list the list to constrain
212   * @param constraint the constraint that validates added elements
213   * @return a constrained view of the list
214   */
215  public static <E> List<E> constrainedList(
216      List<E> list, Constraint<? super E> constraint) {
217    return (list instanceof RandomAccess)
218        ? new ConstrainedRandomAccessList<E>(list, constraint)
219        : new ConstrainedList<E>(list, constraint);
220  }
221
222  /** @see Constraints#constrainedList */
223  @GwtCompatible
224  private static class ConstrainedList<E> extends ForwardingList<E> {
225    final List<E> delegate;
226    final Constraint<? super E> constraint;
227
228    ConstrainedList(List<E> delegate, Constraint<? super E> constraint) {
229      this.delegate = checkNotNull(delegate);
230      this.constraint = checkNotNull(constraint);
231    }
232    @Override protected List<E> delegate() {
233      return delegate;
234    }
235
236    @Override public boolean add(E element) {
237      constraint.checkElement(element);
238      return delegate.add(element);
239    }
240    @Override public void add(int index, E element) {
241      constraint.checkElement(element);
242      delegate.add(index, element);
243    }
244    @Override public boolean addAll(Collection<? extends E> elements) {
245      return delegate.addAll(checkElements(elements, constraint));
246    }
247    @Override public boolean addAll(int index, Collection<? extends E> elements)
248    {
249      return delegate.addAll(index, checkElements(elements, constraint));
250    }
251    @Override public ListIterator<E> listIterator() {
252      return constrainedListIterator(delegate.listIterator(), constraint);
253    }
254    @Override public ListIterator<E> listIterator(int index) {
255      return constrainedListIterator(delegate.listIterator(index), constraint);
256    }
257    @Override public E set(int index, E element) {
258      constraint.checkElement(element);
259      return delegate.set(index, element);
260    }
261    @Override public List<E> subList(int fromIndex, int toIndex) {
262      return constrainedList(
263          delegate.subList(fromIndex, toIndex), constraint);
264    }
265  }
266
267  /** @see Constraints#constrainedList */
268  static class ConstrainedRandomAccessList<E> extends ConstrainedList<E>
269      implements RandomAccess {
270    ConstrainedRandomAccessList(
271        List<E> delegate, Constraint<? super E> constraint) {
272      super(delegate, constraint);
273    }
274  }
275
276  /**
277   * Returns a constrained view of the specified list iterator, using the
278   * specified constraint. Any operations that would add new elements to the
279   * underlying list will be verified by the constraint.
280   *
281   * @param listIterator the iterator for which to return a constrained view
282   * @param constraint the constraint for elements in the list
283   * @return a constrained view of the specified iterator
284   */
285  private static <E> ListIterator<E> constrainedListIterator(
286      ListIterator<E> listIterator, Constraint<? super E> constraint) {
287    return new ConstrainedListIterator<E>(listIterator, constraint);
288  }
289
290  /** @see Constraints#constrainedListIterator */
291  static class ConstrainedListIterator<E> extends ForwardingListIterator<E> {
292    private final ListIterator<E> delegate;
293    private final Constraint<? super E> constraint;
294
295    public ConstrainedListIterator(
296        ListIterator<E> delegate, Constraint<? super E> constraint) {
297      this.delegate = delegate;
298      this.constraint = constraint;
299    }
300    @Override protected ListIterator<E> delegate() {
301      return delegate;
302    }
303
304    @Override public void add(E element) {
305      constraint.checkElement(element);
306      delegate.add(element);
307    }
308    @Override public void set(E element) {
309      constraint.checkElement(element);
310      delegate.set(element);
311    }
312  }
313
314  static <E> Collection<E> constrainedTypePreservingCollection(
315      Collection<E> collection, Constraint<E> constraint) {
316    if (collection instanceof SortedSet) {
317      return constrainedSortedSet((SortedSet<E>) collection, constraint);
318    } else if (collection instanceof Set) {
319      return constrainedSet((Set<E>) collection, constraint);
320    } else if (collection instanceof List) {
321      return constrainedList((List<E>) collection, constraint);
322    } else {
323      return constrainedCollection(collection, constraint);
324    }
325  }
326
327  /**
328   * Returns a constrained view of the specified multiset, using the specified
329   * constraint. Any operations that add new elements to the multiset will call
330   * the provided constraint. However, this method does not verify that
331   * existing elements satisfy the constraint.
332   *
333   * <p>The returned multiset is not serializable.
334   *
335   * @param multiset the multiset to constrain
336   * @param constraint the constraint that validates added elements
337   * @return a constrained view of the multiset
338   */
339  public static <E> Multiset<E> constrainedMultiset(
340      Multiset<E> multiset, Constraint<? super E> constraint) {
341    return new ConstrainedMultiset<E>(multiset, constraint);
342  }
343
344  /** @see Constraints#constrainedMultiset */
345  static class ConstrainedMultiset<E> extends ForwardingMultiset<E> {
346    private Multiset<E> delegate;
347    private final Constraint<? super E> constraint;
348
349    public ConstrainedMultiset(
350        Multiset<E> delegate, Constraint<? super E> constraint) {
351      this.delegate = checkNotNull(delegate);
352      this.constraint = checkNotNull(constraint);
353    }
354    @Override protected Multiset<E> delegate() {
355      return delegate;
356    }
357    @Override public boolean add(E element) {
358      return standardAdd(element);
359    }
360    @Override public boolean addAll(Collection<? extends E> elements) {
361      return delegate.addAll(checkElements(elements, constraint));
362    }
363    @Override public int add(E element, int occurrences) {
364      constraint.checkElement(element);
365      return delegate.add(element, occurrences);
366    }
367    @Override public int setCount(E element, int count) {
368      constraint.checkElement(element);
369      return delegate.setCount(element, count);
370    }
371    @Override public boolean setCount(E element, int oldCount, int newCount) {
372      constraint.checkElement(element);
373      return delegate.setCount(element, oldCount, newCount);
374    }
375  }
376
377  /*
378   * TODO(kevinb): For better performance, avoid making a copy of the elements
379   * by having addAll() call add() repeatedly instead.
380   */
381
382  private static <E> Collection<E> checkElements(
383      Collection<E> elements, Constraint<? super E> constraint) {
384    Collection<E> copy = Lists.newArrayList(elements);
385    for (E element : copy) {
386      constraint.checkElement(element);
387    }
388    return copy;
389  }
390}