Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * 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.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.CollectPreconditions.checkNonnegative;
 import static com.google.common.collect.CollectPreconditions.checkRemove;
 
 
 import java.util.Map;
 import java.util.Set;
 
Basic implementation of Multiset<E> backed by an instance of Map<E, Count>.

For serialization to work, the subclass must specify explicit readObject and writeObject methods.

Author(s):
Kevin Bourrillion
 
 @GwtCompatible(emulated = true)
 abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
     implements Serializable {
 
   private transient Map<E, CountbackingMap;
 
   /*
    * Cache the size for efficiency. Using a long lets us avoid the need for
    * overflow checking and ensures that size() will function correctly even if
    * the multiset had once been larger than Integer.MAX_VALUE.
    */
   private transient long size;

  
Standard constructor.
 
   protected AbstractMapBasedMultiset(Map<E, CountbackingMap) {
     this. = checkNotNull(backingMap);
     this. = super.size();
   }

  
Used during deserialization only. The backing map must be empty.
 
   void setBackingMap(Map<E, CountbackingMap) {
     this. = backingMap;
   }
 
   // Required Implementations
 
  

Invoking com.google.common.collect.Multiset.Entry.getCount() on an entry in the returned set always returns the current count of that element in the multiset, as opposed to the count at the time the entry was retrieved.

 
   @Override
   public Set<Multiset.Entry<E>> entrySet() {
     return super.entrySet();
   }
 
   @Override
     final Iterator<Map.Entry<E, Count>> backingEntries =
         .entrySet().iterator();
     return new Iterator<Multiset.Entry<E>>() {
       Map.Entry<E, CounttoRemove;
 
       @Override
       public boolean hasNext() {
         return backingEntries.hasNext();
       }
 
       @Override
       public Multiset.Entry<E> next() {
         final Map.Entry<E, CountmapEntry = backingEntries.next();
          = mapEntry;
         return new Multisets.AbstractEntry<E>() {
           @Override
          public E getElement() {
            return mapEntry.getKey();
          }
          @Override
          public int getCount() {
            Count count = mapEntry.getValue();
            if (count == null || count.get() == 0) {
              Count frequency = .get(getElement());
              if (frequency != null) {
                return frequency.get();
              }
            }
            return (count == null) ? 0 : count.get();
          }
        };
      }
      @Override
      public void remove() {
        checkRemove( != null);
         -= .getValue().getAndSet(0);
        backingEntries.remove();
         = null;
      }
    };
  }
  public void clear() {
    for (Count frequency : .values()) {
      frequency.set(0);
    }
    .clear();
     = 0L;
  }
  int distinctElements() {
    return .size();
  }
  // Optimizations - Query Operations
  @Override public int size() {
    return Ints.saturatedCast();
  }
  @Override public Iterator<E> iterator() {
    return new MapBasedMultisetIterator();
  }
  /*
   * Not subclassing AbstractMultiset$MultisetIterator because next() needs to
   * retrieve the Map.Entry<E, Count> entry, which can then be used for
   * a more efficient remove() call.
   */
  private class MapBasedMultisetIterator implements Iterator<E> {
    final Iterator<Map.Entry<E, Count>> entryIterator;
    int occurrencesLeft;
    boolean canRemove;
      this. = .entrySet().iterator();
    }
    @Override
    public boolean hasNext() {
      return  > 0 || .hasNext();
    }
    @Override
    public E next() {
      if ( == 0) {
         = .next();
         = .getValue().get();
      }
      --;
       = true;
      return .getKey();
    }
    @Override
    public void remove() {
      int frequency = .getValue().get();
      if (frequency <= 0) {
        throw new ConcurrentModificationException();
      }
      if (.getValue().addAndGet(-1) == 0) {
        .remove();
      }
      --;
       = false;
    }
  }
  @Override public int count(@Nullable Object element) {
    Count frequency = Maps.safeGet(element);
    return (frequency == null) ? 0 : frequency.get();
  }
  // Optional Operations - Modification Operations

  

Throws:
java.lang.IllegalArgumentException if the call would result in more than java.lang.Integer.MAX_VALUE occurrences of element in this multiset.
  @Override public int add(@Nullable E elementint occurrences) {
    if (occurrences == 0) {
      return count(element);
    }
        occurrences > 0, "occurrences cannot be negative: %s"occurrences);
    Count frequency = .get(element);
    int oldCount;
    if (frequency == null) {
      oldCount = 0;
      .put(elementnew Count(occurrences));
    } else {
      oldCount = frequency.get();
      long newCount = (longoldCount + (longoccurrences;
      checkArgument(newCount <= .,
          "too many occurrences: %s"newCount);
      frequency.getAndAdd(occurrences);
    }
     += occurrences;
    return oldCount;
  }
  @Override public int remove(@Nullable Object elementint occurrences) {
    if (occurrences == 0) {
      return count(element);
    }
        occurrences > 0, "occurrences cannot be negative: %s"occurrences);
    Count frequency = .get(element);
    if (frequency == null) {
      return 0;
    }
    int oldCount = frequency.get();
    int numberRemoved;
    if (oldCount > occurrences) {
      numberRemoved = occurrences;
    } else {
      numberRemoved = oldCount;
      .remove(element);
    }
    frequency.addAndGet(-numberRemoved);
     -= numberRemoved;
    return oldCount;
  }
  // Roughly a 33% performance improvement over AbstractMultiset.setCount().
  @Override public int setCount(@Nullable E elementint count) {
    checkNonnegative(count"count");
    Count existingCounter;
    int oldCount;
    if (count == 0) {
      existingCounter = .remove(element);
      oldCount = getAndSet(existingCountercount);
    } else {
      existingCounter = .get(element);
      oldCount = getAndSet(existingCountercount);
      if (existingCounter == null) {
        .put(elementnew Count(count));
      }
    }
     += (count - oldCount);
    return oldCount;
  }
  private static int getAndSet(Count iint count) {
    if (i == null) {
      return 0;
    }
    return i.getAndSet(count);
  }
  // Don't allow default serialization.
New to GrepCode? Check out our FAQ X