Coverage Report - org.webslinger.lang.AtomicMap
 
Classes in this File Line Coverage Branch Coverage Complexity
AtomicMap
15%
15/97
16%
3/19
0
AtomicMap$MapMutator
N/A
N/A
0
AtomicMap$MapProcessor
N/A
N/A
0
AtomicMap$SerialMapMutator
N/A
N/A
0
AtomicMap$SerialMapProcessor
N/A
N/A
0
 
 1  
 package org.webslinger.lang;
 2  
 
 3  
 import java.lang.reflect.Array;
 4  
 import java.util.Collections;
 5  
 import java.util.Comparator;
 6  
 import java.util.HashMap;
 7  
 import java.util.Iterator;
 8  
 import java.util.Map;
 9  
 import java.util.SortedMap;
 10  
 import java.util.TreeMap;
 11  
 import java.util.concurrent.atomic.AtomicInteger;
 12  
 import java.util.concurrent.atomic.AtomicStampedReference;
 13  
 
 14  
 public class AtomicMap<K, V> {
 15  
     private final AtomicStampedReference<Map<K, V>> ref;
 16  27
     private final AtomicInteger serial = new AtomicInteger();
 17  
 
 18  
     public AtomicMap() {
 19  27
         this(new HashMap<K, V>());
 20  27
     }
 21  
 
 22  27
     public AtomicMap(Map<K, V> initial) {
 23  27
         ref = new AtomicStampedReference<Map<K, V>>(copyMap(initial), 0);
 24  27
     }
 25  
 
 26  
     protected V createValue(K key) {
 27  0
         throw new UnsupportedOperationException();
 28  
     }
 29  
 
 30  
     public int getSerial() {
 31  0
         return ref.getStamp();
 32  
     }
 33  
 
 34  
     protected Map<K, V> copyMap(Map<K, V> old) {
 35  265
         return old instanceof SortedMap ? new TreeMap<K, V>((SortedMap<K, V>) old) : new HashMap<K, V>(old);
 36  
     }
 37  
 
 38  
     public Map<K, V> map(int[] serial) {
 39  0
         Map<K, V> map = ref.get(serial);
 40  0
         return map instanceof SortedMap ? Collections.unmodifiableSortedMap((SortedMap<K, V>) map) : Collections.unmodifiableMap(map);
 41  
     }
 42  
 
 43  
     public Map<K, V> map() {
 44  7738
         Map<K, V> map = ref.getReference();
 45  7744
         return map instanceof SortedMap ? Collections.unmodifiableSortedMap((SortedMap<K, V>) map) : Collections.unmodifiableMap(map);
 46  
     }
 47  
 
 48  
     public K[] getKeys(int[] serial, Class<K> type) {
 49  0
         Map<K, V> map = ref.get(serial);
 50  0
         return map.keySet().toArray((K[]) Array.newInstance(type, map.size()));
 51  
     }
 52  
 
 53  
     public K[] getKeys(Class<K> type) {
 54  0
         Map<K, V> map = ref.getReference();
 55  0
         return map.keySet().toArray((K[]) Array.newInstance(type, map.size()));
 56  
     }
 57  
 
 58  
     public void clear() {
 59  0
         clear(new HashMap<K, V>());
 60  0
     }
 61  
 
 62  
     public void clear(Map<K, V> newMap) {
 63  0
         ref.set(copyMap(newMap), serial.incrementAndGet());
 64  0
     }
 65  
 
 66  
     public V get(K key) {
 67  0
         return ref.getReference().get(key);
 68  
     }
 69  
 
 70  
     public boolean containsKey(K key) {
 71  0
         return ref.getReference().containsKey(key);
 72  
     }
 73  
 
 74  
     public V getOrCreate(K key) {
 75  
         Map<K, V> oldMap, newMap;
 76  0
         int[] oldSerial = new int[1];
 77  
         V value;
 78  
         do {
 79  0
             oldMap = ref.get(oldSerial);
 80  0
             value = oldMap.get(key);
 81  0
             if (value != null) return value;
 82  0
             value = createValue(key);
 83  0
             newMap = copyMap(oldMap);
 84  0
             newMap.put(key, value);
 85  0
         } while (!ref.compareAndSet(oldMap, newMap, oldSerial[0], serial.incrementAndGet()));
 86  0
         return value;
 87  
     }
 88  
 
 89  
     public V getOrCreate(K key, boolean[] isNew) {
 90  
         Map<K, V> oldMap, newMap;
 91  0
         int[] oldSerial = new int[1];
 92  
         V value;
 93  
         do {
 94  0
             oldMap = ref.get(oldSerial);
 95  0
             value = oldMap.get(key);
 96  0
             isNew[0] = false;
 97  0
             if (value != null) return value;
 98  0
             value = createValue(key);
 99  0
             newMap = copyMap(oldMap);
 100  0
             isNew[0] = true;
 101  0
             newMap.put(key, value);
 102  0
         } while (!ref.compareAndSet(oldMap, newMap, oldSerial[0], serial.incrementAndGet()));
 103  0
         return value;
 104  
     }
 105  
 
 106  
     public V put(K key, V value) {
 107  
         Map<K, V> oldMap, newMap;
 108  238
         int[] oldSerial = new int[1];
 109  
         V oldValue;
 110  
         do {
 111  238
             oldMap = ref.get(oldSerial);
 112  238
             newMap = copyMap(oldMap);
 113  238
             oldValue = newMap.put(key, value);
 114  238
         } while (!ref.compareAndSet(oldMap, newMap, oldSerial[0], serial.incrementAndGet()));
 115  238
         return oldValue;
 116  
     }
 117  
 
 118  
     public V remove(K key) {
 119  
         Map<K, V> oldMap, newMap;
 120  0
         int[] oldSerial = new int[1];
 121  
         V oldValue;
 122  
         do {
 123  0
             oldMap = ref.get(oldSerial);
 124  0
             newMap = copyMap(oldMap);
 125  0
             newMap.putAll(oldMap);
 126  0
             oldValue = newMap.remove(key);
 127  0
         } while (!ref.compareAndSet(oldMap, newMap, oldSerial[0], serial.incrementAndGet()));
 128  0
         return oldValue;
 129  
     }
 130  
 
 131  
     public void mutate(MapMutator<K, V> mutator) {
 132  
         Map<K, V> oldMap, newMap;
 133  0
         int[] oldSerial = new int[1];
 134  
         do {
 135  0
             oldMap = ref.get(oldSerial);
 136  0
             newMap = copyMap(oldMap);
 137  0
             mutator.start(newMap);
 138  0
             Iterator<Map.Entry<K, V>> it = newMap.entrySet().iterator();
 139  0
             while (it.hasNext()) {
 140  0
                 Map.Entry<K, V> entry = it.next();
 141  0
                 if (mutator.mutate(entry)) it.remove();
 142  0
             }
 143  0
             mutator.end(newMap);
 144  0
         } while (!ref.compareAndSet(oldMap, newMap, oldSerial[0], serial.incrementAndGet()));
 145  0
     }
 146  
 
 147  
     public interface MapMutator<K, V> {
 148  
         void start(Map<K, V> map);
 149  
         boolean mutate(Map.Entry<K, V> entry);
 150  
         void end(Map<K, V> map);
 151  
     }
 152  
 
 153  
     public void mutate(SerialMapMutator<K, V> mutator) {
 154  
         Map<K, V> oldMap, newMap;
 155  0
         int[] oldSerial = new int[1];
 156  
         do {
 157  0
             oldMap = ref.get(oldSerial);
 158  0
             newMap = copyMap(oldMap);
 159  0
             mutator.start(oldSerial[0], newMap);
 160  0
             Iterator<Map.Entry<K, V>> it = newMap.entrySet().iterator();
 161  0
             while (it.hasNext()) {
 162  0
                 Map.Entry<K, V> entry = it.next();
 163  0
                 if (mutator.mutate(oldSerial[0], entry)) it.remove();
 164  0
             }
 165  0
             mutator.end(oldSerial[0], newMap);
 166  0
         } while (!ref.compareAndSet(oldMap, newMap, oldSerial[0], serial.incrementAndGet()));
 167  0
     }
 168  
 
 169  
     public interface SerialMapMutator<K, V> {
 170  
         void start(int serial, Map<K, V> map);
 171  
         boolean mutate(int serial, Map.Entry<K, V> entry);
 172  
         void end(int serial, Map<K, V> map);
 173  
     }
 174  
 
 175  
     public void process(MapProcessor<K, V> processor) {
 176  
         Map<K, V> map;
 177  
         do {
 178  0
             map = ref.getReference();
 179  0
             Map<K, V> roMap = Collections.unmodifiableMap(map);
 180  0
             processor.start(roMap);
 181  0
             for (Map.Entry<K, V> entry: roMap.entrySet()) {
 182  0
                 processor.process(entry);
 183  
             }
 184  0
             processor.end(roMap);
 185  0
         } while (ref.getReference() != map);
 186  0
     }
 187  
 
 188  
     public interface MapProcessor<K, V> {
 189  
         void start(Map<K, V> map);
 190  
         void process(Map.Entry<K, V> entry);
 191  
         void end(Map<K, V> map);
 192  
     }
 193  
 
 194  
     public void process(SerialMapProcessor<K, V> processor) {
 195  
         Map<K, V> map;
 196  0
         int[] oldSerial = new int[1];
 197  
         do {
 198  0
             map = ref.get(oldSerial);
 199  0
             Map<K, V> roMap = Collections.unmodifiableMap(map);
 200  0
             processor.start(oldSerial[0], roMap);
 201  0
             for (Map.Entry<K, V> entry: roMap.entrySet()) {
 202  0
                 processor.process(oldSerial[0], entry);
 203  
             }
 204  0
             processor.end(oldSerial[0], roMap);
 205  0
         } while (ref.getReference() != map);
 206  0
     }
 207  
 
 208  
     public interface SerialMapProcessor<K, V> {
 209  
         void start(int serial, Map<K, V> map);
 210  
         void process(int serial, Map.Entry<K, V> entry);
 211  
         void end(int serial, Map<K, V> map);
 212  
     }
 213  
 }