/* * Javolution - Java(TM) Solution for Real-Time and Embedded Systems * Copyright (C) 2012 - Javolution (http://javolution.org/) * All rights reserved. * * Permission to use, copy, modify, and distribute this software is * freely granted, provided that this notice is preserved. */ package javolution.util.internal.map; import java.util.Iterator; import java.util.Map; import javolution.util.function.Consumer; import javolution.util.function.Equality; import javolution.util.service.MapService; /** * An atomic view over a map (copy-on-write). */ public class AtomicMapImpl<K, V> extends MapView<K, V> { /** Thread-Safe Iterator. */ private class IteratorImpl implements Iterator<Entry<K, V>> { private Entry<K, V> current; private final Iterator<Entry<K, V>> targetIterator = targetView().iterator(); @Override public boolean hasNext() { return targetIterator.hasNext(); } @Override public Entry<K, V> next() { current = targetIterator.next(); return current; } @Override public void remove() { if (current == null) throw new IllegalStateException(); AtomicMapImpl.this.remove(current.getKey()); current = null; } } private static final long serialVersionUID = 0x600L; // Version. protected volatile MapService<K, V> immutable; // The copy used by readers. protected transient Thread updatingThread; // The thread executing an update. public AtomicMapImpl(final MapService<K, V> target) { super(target); this.immutable = cloneTarget(); } @Override public synchronized void clear() { target().clear(); if (!updateInProgress()) { immutable = cloneTarget(); } } @Override public synchronized AtomicMapImpl<K, V> clone() { AtomicMapImpl<K, V> copy = (AtomicMapImpl<K, V>) super.clone(); copy.updatingThread = null; return copy; } @Override public boolean containsKey(final Object key) { return targetView().containsKey(key); } @Override public boolean containsValue(final Object value) { return targetView().containsValue(value); } @Override public V get(final Object key) { return targetView().get(key); } @Override public boolean isEmpty() { return targetView().isEmpty(); } @Override public Iterator<Entry<K, V>> iterator() { return new IteratorImpl(); } @Override public Equality<? super K> keyComparator() { return targetView().keyComparator(); } @Override public synchronized V put(final K key, final V value) { V v = target().put(key, value); if (!updateInProgress()) immutable = cloneTarget(); return v; } @Override public synchronized void putAll(final Map<? extends K, ? extends V> m) { target().putAll(m); if (!updateInProgress()) immutable = cloneTarget(); } @Override public synchronized V putIfAbsent(final K key, final V value) { V v = target().putIfAbsent(key, value); if (!updateInProgress()) immutable = cloneTarget(); return v; } @Override public synchronized V remove(final Object key) { V v = target().remove(key); if (!updateInProgress()) immutable = cloneTarget(); return v; } @Override public synchronized boolean remove(final Object key, final Object value) { boolean changed = target().remove(key, value); if (changed && !updateInProgress()) immutable = cloneTarget(); return changed; } @Override public synchronized V replace(final K key, final V value) { V v = target().replace(key, value); if (!updateInProgress()) immutable = cloneTarget(); return v; } @Override public synchronized boolean replace(final K key, final V oldValue, final V newValue) { boolean changed = target().replace(key, oldValue, newValue); if (changed && !updateInProgress()) immutable = cloneTarget(); return changed; } @Override public int size() { return targetView().size(); } @Override public synchronized void update(final Consumer<MapService<K, V>> action, final MapService<K, V> view) { updatingThread = Thread.currentThread(); // Update in progress. try { target().update(action, view); // No copy performed. } finally { updatingThread = null; immutable = cloneTarget(); // One single copy ! } } @Override public Equality<? super V> valueComparator() { return targetView().valueComparator(); } /** Returns a clone copy of target. */ protected MapService<K, V> cloneTarget() { try { return target().clone(); } catch (CloneNotSupportedException e) { throw new Error("Cannot happen since target is Cloneable."); } } /** * Returns either the immutable target or the actual target if updating thread. */ protected MapService<K, V> targetView() { return ((updatingThread == null) || (updatingThread != Thread.currentThread())) ? immutable : target(); } /** Indicates if the current thread is doing an atomic update. */ protected final boolean updateInProgress() { return updatingThread == Thread.currentThread(); } }