public final class

CopyOnWriteMultiset<E>

extends java.lang.Object

implements java.lang.Iterable<java.lang.Object>

 java.lang.Object

↳androidx.media3.common.util.CopyOnWriteMultiset<E>

Gradle dependencies

compile group: 'androidx.media3', name: 'media3-common', version: '1.5.0-alpha01'

  • groupId: androidx.media3
  • artifactId: media3-common
  • version: 1.5.0-alpha01

Artifact androidx.media3:media3-common:1.5.0-alpha01 it located at Google repository (https://maven.google.com/)

Overview

An unordered collection of elements that allows duplicates, but also allows access to a set of unique elements.

This class is thread-safe using the same method as java.util.concurrent.CopyOnWriteArrayList. Mutation methods cause the underlying data to be copied. CopyOnWriteMultiset.elementSet() and CopyOnWriteMultiset.iterator() return snapshots that are unaffected by subsequent mutations.

Iterating directly on this class reveals duplicate elements. Unique elements can be accessed via CopyOnWriteMultiset.elementSet(). Iteration order for both of these is not defined.

Summary

Constructors
publicCopyOnWriteMultiset()

Methods
public voidadd(java.lang.Object element)

Adds element to the multiset.

public intcount(java.lang.Object element)

Returns the number of occurrences of an element in this multiset.

public java.util.Set<java.lang.Object>elementSet()

Returns a snapshot of the unique elements currently in this multiset.

public java.util.Iterator<java.lang.Object>iterator()

Returns an iterator over a snapshot of all the elements currently in this multiset (including duplicates).

public voidremove(java.lang.Object element)

Removes element from the multiset.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public CopyOnWriteMultiset()

Methods

public void add(java.lang.Object element)

Adds element to the multiset.

Parameters:

element: The element to be added.

public void remove(java.lang.Object element)

Removes element from the multiset.

Parameters:

element: The element to be removed.

public java.util.Set<java.lang.Object> elementSet()

Returns a snapshot of the unique elements currently in this multiset.

Changes to the underlying multiset are not reflected in the returned value.

Returns:

An unmodifiable set containing the unique elements in this multiset.

public java.util.Iterator<java.lang.Object> iterator()

Returns an iterator over a snapshot of all the elements currently in this multiset (including duplicates).

Changes to the underlying multiset are not reflected in the returned value.

Returns:

An unmodifiable iterator over all the elements in this multiset (including duplicates).

public int count(java.lang.Object element)

Returns the number of occurrences of an element in this multiset.

Source

/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * 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 androidx.media3.common.util;

import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * An unordered collection of elements that allows duplicates, but also allows access to a set of
 * unique elements.
 *
 * <p>This class is thread-safe using the same method as {@link
 * java.util.concurrent.CopyOnWriteArrayList}. Mutation methods cause the underlying data to be
 * copied. {@link #elementSet()} and {@link #iterator()} return snapshots that are unaffected by
 * subsequent mutations.
 *
 * <p>Iterating directly on this class reveals duplicate elements. Unique elements can be accessed
 * via {@link #elementSet()}. Iteration order for both of these is not defined.
 *
 * @param <E> The type of element being stored.
 */
// Intentionally extending @NonNull-by-default Object to disallow @Nullable E types.
@SuppressWarnings("TypeParameterExplicitlyExtendsObject")
@UnstableApi
public final class CopyOnWriteMultiset<E extends Object> implements Iterable<E> {

  private final Object lock;

  @GuardedBy("lock")
  private final Map<E, Integer> elementCounts;

  @GuardedBy("lock")
  private Set<E> elementSet;

  @GuardedBy("lock")
  private List<E> elements;

  public CopyOnWriteMultiset() {
    lock = new Object();
    elementCounts = new HashMap<>();
    elementSet = Collections.emptySet();
    elements = Collections.emptyList();
  }

  /**
   * Adds {@code element} to the multiset.
   *
   * @param element The element to be added.
   */
  public void add(E element) {
    synchronized (lock) {
      List<E> elements = new ArrayList<>(this.elements);
      elements.add(element);
      this.elements = Collections.unmodifiableList(elements);

      @Nullable Integer count = elementCounts.get(element);
      if (count == null) {
        Set<E> elementSet = new HashSet<>(this.elementSet);
        elementSet.add(element);
        this.elementSet = Collections.unmodifiableSet(elementSet);
      }
      elementCounts.put(element, count != null ? count + 1 : 1);
    }
  }

  /**
   * Removes {@code element} from the multiset.
   *
   * @param element The element to be removed.
   */
  public void remove(E element) {
    synchronized (lock) {
      @Nullable Integer count = elementCounts.get(element);
      if (count == null) {
        return;
      }

      List<E> elements = new ArrayList<>(this.elements);
      elements.remove(element);
      this.elements = Collections.unmodifiableList(elements);

      if (count == 1) {
        elementCounts.remove(element);
        Set<E> elementSet = new HashSet<>(this.elementSet);
        elementSet.remove(element);
        this.elementSet = Collections.unmodifiableSet(elementSet);
      } else {
        elementCounts.put(element, count - 1);
      }
    }
  }

  /**
   * Returns a snapshot of the unique elements currently in this multiset.
   *
   * <p>Changes to the underlying multiset are not reflected in the returned value.
   *
   * @return An unmodifiable set containing the unique elements in this multiset.
   */
  public Set<E> elementSet() {
    synchronized (lock) {
      return elementSet;
    }
  }

  /**
   * Returns an iterator over a snapshot of all the elements currently in this multiset (including
   * duplicates).
   *
   * <p>Changes to the underlying multiset are not reflected in the returned value.
   *
   * @return An unmodifiable iterator over all the elements in this multiset (including duplicates).
   */
  @Override
  public Iterator<E> iterator() {
    synchronized (lock) {
      return elements.iterator();
    }
  }

  /** Returns the number of occurrences of an element in this multiset. */
  public int count(E element) {
    synchronized (lock) {
      return elementCounts.containsKey(element) ? elementCounts.get(element) : 0;
    }
  }
}