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 017 package com.google.common.collect; 018 019 import static com.google.common.base.Preconditions.checkArgument; 020 import static com.google.common.base.Preconditions.checkNotNull; 021 import static com.google.common.base.Preconditions.checkState; 022 import static com.google.common.collect.BstSide.LEFT; 023 import static com.google.common.collect.BstSide.RIGHT; 024 025 import java.io.IOException; 026 import java.io.ObjectInputStream; 027 import java.io.ObjectOutputStream; 028 import java.io.Serializable; 029 import java.util.Comparator; 030 import java.util.ConcurrentModificationException; 031 import java.util.Iterator; 032 033 import javax.annotation.Nullable; 034 035 import com.google.common.annotations.GwtCompatible; 036 import com.google.common.annotations.GwtIncompatible; 037 import com.google.common.primitives.Ints; 038 039 /** 040 * A multiset which maintains the ordering of its elements, according to either 041 * their natural order or an explicit {@link Comparator}. In all cases, this 042 * implementation uses {@link Comparable#compareTo} or {@link 043 * Comparator#compare} instead of {@link Object#equals} to determine 044 * equivalence of instances. 045 * 046 * <p><b>Warning:</b> The comparison must be <i>consistent with equals</i> as 047 * explained by the {@link Comparable} class specification. Otherwise, the 048 * resulting multiset will violate the {@link java.util.Collection} contract, 049 * which is specified in terms of {@link Object#equals}. 050 * 051 * @author Louis Wasserman 052 * @author Jared Levy 053 * @since 2.0 (imported from Google Collections Library) 054 */ 055 @GwtCompatible(emulated = true) 056 public final class TreeMultiset<E> extends AbstractSortedMultiset<E> 057 implements Serializable { 058 059 /** 060 * Creates a new, empty multiset, sorted according to the elements' natural 061 * order. All elements inserted into the multiset must implement the 062 * {@code Comparable} interface. Furthermore, all such elements must be 063 * <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a 064 * {@code ClassCastException} for any elements {@code e1} and {@code e2} in 065 * the multiset. If the user attempts to add an element to the multiset that 066 * violates this constraint (for example, the user attempts to add a string 067 * element to a set whose elements are integers), the {@code add(Object)} 068 * call will throw a {@code ClassCastException}. 069 * 070 * <p>The type specification is {@code <E extends Comparable>}, instead of the 071 * more specific {@code <E extends Comparable<? super E>>}, to support 072 * classes defined without generics. 073 */ 074 public static <E extends Comparable> TreeMultiset<E> create() { 075 return new TreeMultiset<E>(Ordering.natural()); 076 } 077 078 /** 079 * Creates a new, empty multiset, sorted according to the specified 080 * comparator. All elements inserted into the multiset must be <i>mutually 081 * comparable</i> by the specified comparator: {@code comparator.compare(e1, 082 * e2)} must not throw a {@code ClassCastException} for any elements {@code 083 * e1} and {@code e2} in the multiset. If the user attempts to add an element 084 * to the multiset that violates this constraint, the {@code add(Object)} call 085 * will throw a {@code ClassCastException}. 086 * 087 * @param comparator the comparator that will be used to sort this multiset. A 088 * null value indicates that the elements' <i>natural ordering</i> should 089 * be used. 090 */ 091 @SuppressWarnings("unchecked") 092 public static <E> TreeMultiset<E> create( 093 @Nullable Comparator<? super E> comparator) { 094 return (comparator == null) 095 ? new TreeMultiset<E>((Comparator) Ordering.natural()) 096 : new TreeMultiset<E>(comparator); 097 } 098 099 /** 100 * Creates an empty multiset containing the given initial elements, sorted 101 * according to the elements' natural order. 102 * 103 * <p>This implementation is highly efficient when {@code elements} is itself 104 * a {@link Multiset}. 105 * 106 * <p>The type specification is {@code <E extends Comparable>}, instead of the 107 * more specific {@code <E extends Comparable<? super E>>}, to support 108 * classes defined without generics. 109 */ 110 public static <E extends Comparable> TreeMultiset<E> create( 111 Iterable<? extends E> elements) { 112 TreeMultiset<E> multiset = create(); 113 Iterables.addAll(multiset, elements); 114 return multiset; 115 } 116 117 /** 118 * Returns an iterator over the elements contained in this collection. 119 */ 120 @Override 121 public Iterator<E> iterator() { 122 // Needed to avoid Javadoc bug. 123 return super.iterator(); 124 } 125 126 private TreeMultiset(Comparator<? super E> comparator) { 127 super(comparator); 128 this.range = GeneralRange.all(comparator); 129 this.rootReference = new Reference<Node<E>>(); 130 } 131 132 private TreeMultiset(GeneralRange<E> range, Reference<Node<E>> root) { 133 super(range.comparator()); 134 this.range = range; 135 this.rootReference = root; 136 } 137 138 @SuppressWarnings("unchecked") 139 E checkElement(Object o) { 140 return (E) o; 141 } 142 143 private transient final GeneralRange<E> range; 144 145 private transient final Reference<Node<E>> rootReference; 146 147 static final class Reference<T> { 148 T value; 149 150 public Reference() {} 151 152 public T get() { 153 return value; 154 } 155 156 public boolean compareAndSet(T expected, T newValue) { 157 if (value == expected) { 158 value = newValue; 159 return true; 160 } 161 return false; 162 } 163 } 164 165 @Override 166 int distinctElements() { 167 Node<E> root = rootReference.get(); 168 return Ints.checkedCast(BstRangeOps.totalInRange(distinctAggregate(), range, root)); 169 } 170 171 @Override 172 public int size() { 173 Node<E> root = rootReference.get(); 174 return Ints.saturatedCast(BstRangeOps.totalInRange(sizeAggregate(), range, root)); 175 } 176 177 @Override 178 public int count(@Nullable Object element) { 179 try { 180 E e = checkElement(element); 181 if (range.contains(e)) { 182 Node<E> node = BstOperations.seek(comparator(), rootReference.get(), e); 183 return countOrZero(node); 184 } 185 return 0; 186 } catch (ClassCastException e) { 187 return 0; 188 } catch (NullPointerException e) { 189 return 0; 190 } 191 } 192 193 private int mutate(@Nullable E e, MultisetModifier modifier) { 194 BstMutationRule<E, Node<E>> mutationRule = BstMutationRule.createRule( 195 modifier, 196 BstCountBasedBalancePolicies. 197 <E, Node<E>>singleRebalancePolicy(distinctAggregate()), 198 nodeFactory()); 199 BstMutationResult<E, Node<E>> mutationResult = 200 BstOperations.mutate(comparator(), mutationRule, rootReference.get(), e); 201 if (!rootReference.compareAndSet( 202 mutationResult.getOriginalRoot(), mutationResult.getChangedRoot())) { 203 throw new ConcurrentModificationException(); 204 } 205 Node<E> original = mutationResult.getOriginalTarget(); 206 return countOrZero(original); 207 } 208 209 @Override 210 public int add(E element, int occurrences) { 211 checkElement(element); 212 if (occurrences == 0) { 213 return count(element); 214 } 215 checkArgument(range.contains(element)); 216 return mutate(element, new AddModifier(occurrences)); 217 } 218 219 @Override 220 public int remove(@Nullable Object element, int occurrences) { 221 if (element == null) { 222 return 0; 223 } else if (occurrences == 0) { 224 return count(element); 225 } 226 try { 227 E e = checkElement(element); 228 return range.contains(e) ? mutate(e, new RemoveModifier(occurrences)) : 0; 229 } catch (ClassCastException e) { 230 return 0; 231 } 232 } 233 234 @Override 235 public boolean setCount(E element, int oldCount, int newCount) { 236 checkElement(element); 237 checkArgument(range.contains(element)); 238 return mutate(element, new ConditionalSetCountModifier(oldCount, newCount)) 239 == oldCount; 240 } 241 242 @Override 243 public int setCount(E element, int count) { 244 checkElement(element); 245 checkArgument(range.contains(element)); 246 return mutate(element, new SetCountModifier(count)); 247 } 248 249 private BstPathFactory<Node<E>, BstInOrderPath<Node<E>>> pathFactory() { 250 return BstInOrderPath.inOrderFactory(); 251 } 252 253 @Override 254 Iterator<Entry<E>> entryIterator() { 255 Node<E> root = rootReference.get(); 256 final BstInOrderPath<Node<E>> startingPath = 257 BstRangeOps.furthestPath(range, LEFT, pathFactory(), root); 258 return iteratorInDirection(startingPath, RIGHT); 259 } 260 261 @Override 262 Iterator<Entry<E>> descendingEntryIterator() { 263 Node<E> root = rootReference.get(); 264 final BstInOrderPath<Node<E>> startingPath = 265 BstRangeOps.furthestPath(range, RIGHT, pathFactory(), root); 266 return iteratorInDirection(startingPath, LEFT); 267 } 268 269 private Iterator<Entry<E>> iteratorInDirection( 270 @Nullable BstInOrderPath<Node<E>> start, final BstSide direction) { 271 final Iterator<BstInOrderPath<Node<E>>> pathIterator = 272 new AbstractLinkedIterator<BstInOrderPath<Node<E>>>(start) { 273 @Override 274 protected BstInOrderPath<Node<E>> computeNext(BstInOrderPath<Node<E>> previous) { 275 if (!previous.hasNext(direction)) { 276 return null; 277 } 278 BstInOrderPath<Node<E>> next = previous.next(direction); 279 // TODO(user): only check against one side 280 return range.contains(next.getTip().getKey()) ? next : null; 281 } 282 }; 283 return new Iterator<Entry<E>>() { 284 E toRemove = null; 285 286 @Override 287 public boolean hasNext() { 288 return pathIterator.hasNext(); 289 } 290 291 @Override 292 public Entry<E> next() { 293 BstInOrderPath<Node<E>> path = pathIterator.next(); 294 return new LiveEntry( 295 toRemove = path.getTip().getKey(), path.getTip().elemCount()); 296 } 297 298 @Override 299 public void remove() { 300 checkState(toRemove != null); 301 setCount(toRemove, 0); 302 toRemove = null; 303 } 304 }; 305 } 306 307 class LiveEntry extends Multisets.AbstractEntry<E> { 308 private Node<E> expectedRoot; 309 private final E element; 310 private int count; 311 312 private LiveEntry(E element, int count) { 313 this.expectedRoot = rootReference.get(); 314 this.element = element; 315 this.count = count; 316 } 317 318 @Override 319 public E getElement() { 320 return element; 321 } 322 323 @Override 324 public int getCount() { 325 if (rootReference.get() == expectedRoot) { 326 return count; 327 } else { 328 // check for updates 329 expectedRoot = rootReference.get(); 330 return count = TreeMultiset.this.count(element); 331 } 332 } 333 } 334 335 @Override 336 public void clear() { 337 Node<E> root = rootReference.get(); 338 Node<E> cleared = BstRangeOps.minusRange(range, 339 BstCountBasedBalancePolicies.<E, Node<E>>fullRebalancePolicy(distinctAggregate()), 340 nodeFactory(), root); 341 if (!rootReference.compareAndSet(root, cleared)) { 342 throw new ConcurrentModificationException(); 343 } 344 } 345 346 @Override 347 public SortedMultiset<E> headMultiset(E upperBound, BoundType boundType) { 348 checkNotNull(upperBound); 349 return new TreeMultiset<E>( 350 range.intersect(GeneralRange.upTo(comparator, upperBound, boundType)), rootReference); 351 } 352 353 @Override 354 public SortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) { 355 checkNotNull(lowerBound); 356 return new TreeMultiset<E>( 357 range.intersect(GeneralRange.downTo(comparator, lowerBound, boundType)), rootReference); 358 } 359 360 /** 361 * {@inheritDoc} 362 * 363 * @since 11.0 364 */ 365 @Override 366 public Comparator<? super E> comparator() { 367 return super.comparator(); 368 } 369 370 private static final class Node<E> extends BstNode<E, Node<E>> implements Serializable { 371 private final long size; 372 private final int distinct; 373 374 private Node(E key, int elemCount, @Nullable Node<E> left, 375 @Nullable Node<E> right) { 376 super(key, left, right); 377 checkArgument(elemCount > 0); 378 this.size = (long) elemCount + sizeOrZero(left) + sizeOrZero(right); 379 this.distinct = 1 + distinctOrZero(left) + distinctOrZero(right); 380 } 381 382 int elemCount() { 383 long result = size - sizeOrZero(childOrNull(LEFT)) 384 - sizeOrZero(childOrNull(RIGHT)); 385 return Ints.checkedCast(result); 386 } 387 388 private Node(E key, int elemCount) { 389 this(key, elemCount, null, null); 390 } 391 392 private static final long serialVersionUID = 0; 393 } 394 395 private static long sizeOrZero(@Nullable Node<?> node) { 396 return (node == null) ? 0 : node.size; 397 } 398 399 private static int distinctOrZero(@Nullable Node<?> node) { 400 return (node == null) ? 0 : node.distinct; 401 } 402 403 private static int countOrZero(@Nullable Node<?> entry) { 404 return (entry == null) ? 0 : entry.elemCount(); 405 } 406 407 @SuppressWarnings("unchecked") 408 private BstAggregate<Node<E>> distinctAggregate() { 409 return (BstAggregate) DISTINCT_AGGREGATE; 410 } 411 412 private static final BstAggregate<Node<Object>> DISTINCT_AGGREGATE = 413 new BstAggregate<Node<Object>>() { 414 @Override 415 public int entryValue(Node<Object> entry) { 416 return 1; 417 } 418 419 @Override 420 public long treeValue(@Nullable Node<Object> tree) { 421 return distinctOrZero(tree); 422 } 423 }; 424 425 @SuppressWarnings("unchecked") 426 private BstAggregate<Node<E>> sizeAggregate() { 427 return (BstAggregate) SIZE_AGGREGATE; 428 } 429 430 private static final BstAggregate<Node<Object>> SIZE_AGGREGATE = 431 new BstAggregate<Node<Object>>() { 432 @Override 433 public int entryValue(Node<Object> entry) { 434 return entry.elemCount(); 435 } 436 437 @Override 438 public long treeValue(@Nullable Node<Object> tree) { 439 return sizeOrZero(tree); 440 } 441 }; 442 443 @SuppressWarnings("unchecked") 444 private BstNodeFactory<Node<E>> nodeFactory() { 445 return (BstNodeFactory) NODE_FACTORY; 446 } 447 448 private static final BstNodeFactory<Node<Object>> NODE_FACTORY = 449 new BstNodeFactory<Node<Object>>() { 450 @Override 451 public Node<Object> createNode(Node<Object> source, @Nullable Node<Object> left, 452 @Nullable Node<Object> right) { 453 return new Node<Object>(source.getKey(), source.elemCount(), left, right); 454 } 455 }; 456 457 private abstract class MultisetModifier implements BstModifier<E, Node<E>> { 458 abstract int newCount(int oldCount); 459 460 @Nullable 461 @Override 462 public BstModificationResult<Node<E>> modify(E key, @Nullable Node<E> originalEntry) { 463 int oldCount = countOrZero(originalEntry); 464 int newCount = newCount(oldCount); 465 if (oldCount == newCount) { 466 return BstModificationResult.identity(originalEntry); 467 } else if (newCount == 0) { 468 return BstModificationResult.rebalancingChange(originalEntry, null); 469 } else if (oldCount == 0) { 470 return BstModificationResult.rebalancingChange(null, new Node<E>(key, newCount)); 471 } else { 472 return BstModificationResult.rebuildingChange(originalEntry, 473 new Node<E>(originalEntry.getKey(), newCount)); 474 } 475 } 476 } 477 478 private final class AddModifier extends MultisetModifier { 479 private final int countToAdd; 480 481 private AddModifier(int countToAdd) { 482 checkArgument(countToAdd > 0); 483 this.countToAdd = countToAdd; 484 } 485 486 @Override 487 int newCount(int oldCount) { 488 checkArgument(countToAdd <= Integer.MAX_VALUE - oldCount, "Cannot add this many elements"); 489 return oldCount + countToAdd; 490 } 491 } 492 493 private final class RemoveModifier extends MultisetModifier { 494 private final int countToRemove; 495 496 private RemoveModifier(int countToRemove) { 497 checkArgument(countToRemove > 0); 498 this.countToRemove = countToRemove; 499 } 500 501 @Override 502 int newCount(int oldCount) { 503 return Math.max(0, oldCount - countToRemove); 504 } 505 } 506 507 private final class SetCountModifier extends MultisetModifier { 508 private final int countToSet; 509 510 private SetCountModifier(int countToSet) { 511 checkArgument(countToSet >= 0); 512 this.countToSet = countToSet; 513 } 514 515 @Override 516 int newCount(int oldCount) { 517 return countToSet; 518 } 519 } 520 521 private final class ConditionalSetCountModifier extends MultisetModifier { 522 private final int expectedCount; 523 private final int setCount; 524 525 private ConditionalSetCountModifier(int expectedCount, int setCount) { 526 checkArgument(setCount >= 0 & expectedCount >= 0); 527 this.expectedCount = expectedCount; 528 this.setCount = setCount; 529 } 530 531 @Override 532 int newCount(int oldCount) { 533 return (oldCount == expectedCount) ? setCount : oldCount; 534 } 535 } 536 537 /* 538 * TODO(jlevy): Decide whether entrySet() should return entries with an 539 * equals() method that calls the comparator to compare the two keys. If that 540 * change is made, AbstractMultiset.equals() can simply check whether two 541 * multisets have equal entry sets. 542 */ 543 544 /** 545 * @serialData the comparator, the number of distinct elements, the first 546 * element, its count, the second element, its count, and so on 547 */ 548 @GwtIncompatible("java.io.ObjectOutputStream") 549 private void writeObject(ObjectOutputStream stream) throws IOException { 550 stream.defaultWriteObject(); 551 stream.writeObject(elementSet().comparator()); 552 Serialization.writeMultiset(this, stream); 553 } 554 555 @GwtIncompatible("java.io.ObjectInputStream") 556 private void readObject(ObjectInputStream stream) 557 throws IOException, ClassNotFoundException { 558 stream.defaultReadObject(); 559 @SuppressWarnings("unchecked") // reading data stored by writeObject 560 Comparator<? super E> comparator = (Comparator<? super E>) stream.readObject(); 561 Serialization.getFieldSetter(AbstractSortedMultiset.class, "comparator").set(this, comparator); 562 Serialization.getFieldSetter(TreeMultiset.class, "range").set(this, 563 GeneralRange.all(comparator)); 564 Serialization.getFieldSetter(TreeMultiset.class, "rootReference").set(this, 565 new Reference<Node<E>>()); 566 Serialization.populateMultiset(this, stream); 567 } 568 569 @GwtIncompatible("not needed in emulated source") 570 private static final long serialVersionUID = 1; 571 }