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 17package com.google.common.collect; 18 19import static com.google.common.base.Preconditions.checkNotNull; 20 21import com.google.common.annotations.GwtCompatible; 22 23import java.util.Collection; 24import java.util.List; 25import java.util.ListIterator; 26import java.util.RandomAccess; 27import java.util.Set; 28import 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 37final class 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 */ 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 62 public ConstrainedCollection( 63 Collection<E> delegate, Constraint<? super E> constraint) { 64 this.delegate = checkNotNull(delegate); 65 this.constraint = checkNotNull(constraint); 66 } 67 @Override protected Collection<E> delegate() { 68 return delegate; 69 } 70 @Override public boolean add(E element) { 71 constraint.checkElement(element); 72 return delegate.add(element); 73 } 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 */ 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 101 public ConstrainedSet(Set<E> delegate, Constraint<? super E> constraint) { 102 this.delegate = checkNotNull(delegate); 103 this.constraint = checkNotNull(constraint); 104 } 105 @Override protected Set<E> delegate() { 106 return delegate; 107 } 108 @Override public boolean add(E element) { 109 constraint.checkElement(element); 110 return delegate.add(element); 111 } 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 */ 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 139 ConstrainedSortedSet( 140 SortedSet<E> delegate, Constraint<? super E> constraint) { 141 this.delegate = checkNotNull(delegate); 142 this.constraint = checkNotNull(constraint); 143 } 144 @Override protected SortedSet<E> delegate() { 145 return delegate; 146 } 147 @Override public SortedSet<E> headSet(E toElement) { 148 return constrainedSortedSet(delegate.headSet(toElement), constraint); 149 } 150 @Override public SortedSet<E> subSet(E fromElement, E toElement) { 151 return constrainedSortedSet( 152 delegate.subSet(fromElement, toElement), constraint); 153 } 154 @Override public SortedSet<E> tailSet(E fromElement) { 155 return constrainedSortedSet(delegate.tailSet(fromElement), constraint); 156 } 157 @Override public boolean add(E element) { 158 constraint.checkElement(element); 159 return delegate.add(element); 160 } 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 */ 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 192 ConstrainedList(List<E> delegate, Constraint<? super E> constraint) { 193 this.delegate = checkNotNull(delegate); 194 this.constraint = checkNotNull(constraint); 195 } 196 @Override protected List<E> delegate() { 197 return delegate; 198 } 199 200 @Override public boolean add(E element) { 201 constraint.checkElement(element); 202 return delegate.add(element); 203 } 204 @Override public void add(int index, E element) { 205 constraint.checkElement(element); 206 delegate.add(index, element); 207 } 208 @Override public boolean addAll(Collection<? extends E> elements) { 209 return delegate.addAll(checkElements(elements, constraint)); 210 } 211 @Override public boolean addAll(int index, Collection<? extends E> elements) 212 { 213 return delegate.addAll(index, checkElements(elements, constraint)); 214 } 215 @Override public ListIterator<E> listIterator() { 216 return constrainedListIterator(delegate.listIterator(), constraint); 217 } 218 @Override public ListIterator<E> listIterator(int index) { 219 return constrainedListIterator(delegate.listIterator(index), constraint); 220 } 221 @Override public E set(int index, E element) { 222 constraint.checkElement(element); 223 return delegate.set(index, element); 224 } 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 { 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 */ 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 259 public ConstrainedListIterator( 260 ListIterator<E> delegate, Constraint<? super E> constraint) { 261 this.delegate = delegate; 262 this.constraint = constraint; 263 } 264 @Override protected ListIterator<E> delegate() { 265 return delegate; 266 } 267 268 @Override public void add(E element) { 269 constraint.checkElement(element); 270 delegate.add(element); 271 } 272 @Override public void set(E element) { 273 constraint.checkElement(element); 274 delegate.set(element); 275 } 276 } 277 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 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