Home | History | Annotate | Download | only in concurrent
      1 /*
      2  * Copyright (c) 2016 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 package org.mockito.internal.util.concurrent;
      6 
      7 import java.util.Iterator;
      8 import java.util.Map;
      9 
     10 /**
     11  * <p>
     12  * A thread-safe set with weak values. Entries are based on a key's system hash code and keys are considered equal only by reference equality.
     13  * </p>
     14  * This class does not implement the {@link java.util.Set} interface because this implementation is incompatible
     15  * with the set contract. While iterating over a set's entries, any value that has not passed iteration is referenced non-weakly.
     16  */
     17 public class WeakConcurrentSet<V> implements Runnable, Iterable<V> {
     18 
     19     final WeakConcurrentMap<V, Boolean> target;
     20 
     21     public WeakConcurrentSet(Cleaner cleaner) {
     22         switch (cleaner) {
     23             case INLINE:
     24                 target = new WeakConcurrentMap.WithInlinedExpunction<V, Boolean>();
     25                 break;
     26             case THREAD:
     27             case MANUAL:
     28                 target = new WeakConcurrentMap<V, Boolean>(cleaner == Cleaner.THREAD);
     29                 break;
     30             default:
     31                 throw new AssertionError();
     32         }
     33     }
     34 
     35     /**
     36      * @param value The value to add to the set.
     37      * @return {@code true} if the value was added to the set and was not contained before.
     38      */
     39     public boolean add(V value) {
     40         return target.put(value, Boolean.TRUE) == null; // is null or Boolean.TRUE
     41     }
     42 
     43     /**
     44      * @param value The value to check if it is contained in the set.
     45      * @return {@code true} if the set contains the value.
     46      */
     47     public boolean contains(V value) {
     48         return target.containsKey(value);
     49     }
     50 
     51     /**
     52      * @param value The value to remove from the set.
     53      * @return {@code true} if the value is contained in the set.
     54      */
     55     public boolean remove(V value) {
     56         return target.remove(value);
     57     }
     58 
     59     /**
     60      * Clears the set.
     61      */
     62     public void clear() {
     63         target.clear();
     64     }
     65 
     66     /**
     67      * Returns the approximate size of this set where the returned number is at least as big as the actual number of entries.
     68      *
     69      * @return The minimum size of this set.
     70      */
     71     public int approximateSize() {
     72         return target.approximateSize();
     73     }
     74 
     75     @Override
     76     public void run() {
     77         target.run();
     78     }
     79 
     80     /**
     81      * Determines the cleaning format. A reference is removed either by an explicitly started cleaner thread
     82      * associated with this instance ({@link Cleaner#THREAD}), as a result of interacting with this thread local
     83      * from any thread ({@link Cleaner#INLINE} or manually by submitting the detached thread local to a thread
     84      * ({@link Cleaner#MANUAL}).
     85      */
     86     public enum Cleaner {
     87         THREAD, INLINE, MANUAL
     88     }
     89 
     90     /**
     91      * Cleans all unused references.
     92      */
     93     public void expungeStaleEntries() {
     94         target.expungeStaleEntries();
     95     }
     96 
     97     /**
     98      * @return The cleaner thread or {@code null} if no such thread was set.
     99      */
    100     public Thread getCleanerThread() {
    101         return target.getCleanerThread();
    102     }
    103 
    104     @Override
    105     public Iterator<V> iterator() {
    106         return new ReducingIterator<V>(target.iterator());
    107     }
    108 
    109     private static class ReducingIterator<V> implements Iterator<V> {
    110 
    111         private final Iterator<Map.Entry<V, Boolean>> iterator;
    112 
    113         private ReducingIterator(Iterator<Map.Entry<V, Boolean>> iterator) {
    114             this.iterator = iterator;
    115         }
    116 
    117         @Override
    118         public void remove() {
    119             iterator.remove();
    120         }
    121 
    122         @Override
    123         public V next() {
    124             return iterator.next().getKey();
    125         }
    126 
    127         @Override
    128         public boolean hasNext() {
    129             return iterator.hasNext();
    130         }
    131     }
    132 }
    133