/** Sends all deferred notifications, starting with the given one. */ static <K,V> void notifyChanges(final Cache<K,V> cache, Deferred<K,V> entry) { while (entry != null) { cache.notifyChange(entry.key, entry.value); entry = entry.next; } } }
/** * If the given key is mapped to the given old value, removes that value. Otherwise does nothing. * If a value is under computation in another thread, then this method unconditionally returns {@code false}. * * @param key key of the value to remove. * @param oldValue previous value expected to be mapped to the given key. * @return {@code true} if the value has been removed, {@code false} otherwise. * * @see #get(Object) * * @since 1.0 */ @Override @SuppressWarnings("unchecked") public boolean remove(final Object key, final Object oldValue) { final boolean done = map.remove(key, oldValue); if (done) { notifyChange((K) key, null); } return done; }
/** * Returns the computed value. */ @Override public V peek() { return value; }
/** * Removes the value mapped to the given key in the cache. If a value is under computation in another thread, * then the other thread may fail with an {@link IllegalStateException} unless {@link #isKeyCollisionAllowed()} * returns {@code true}. For more safety, consider using {@link #remove(Object, Object)} instead. * * @param key the key of the value to removed. * @return the value previously mapped to the given key, or {@code null} if no value existed before this * method call or if the value was under computation in another thread. * * @see #get(Object) * @see #remove(Object, Object) */ @Override @SuppressWarnings("unchecked") public V remove(final Object key) { final Object oldValue = map.remove(key); if (oldValue != null) { notifyChange((K) key, null); } return immediateValueOf(oldValue); }
/** * If the given key is mapped to the given old value, replaces that value with the given new value. * Otherwise does nothing. A null {@code value} argument removes the entry if the condition matches. * If a value is under computation in another thread, then this method unconditionally returns {@code false}. * * @param key key of the value to replace. * @param oldValue previous value expected to be mapped to the given key. * @param newValue the new value to put if the condition matches, or {@code null} for removing the mapping. * @return {@code true} if the value has been replaced, {@code false} otherwise. * * @since 1.0 */ @Override public boolean replace(final K key, final V oldValue, final V newValue) { ensureValidType(newValue); final boolean done; if (oldValue != null) { done = (newValue != null) ? map.replace(key, oldValue, newValue) : map.remove(key, oldValue); } else { done = (newValue != null) && map.putIfAbsent(key, newValue) == null; } if (done) { notifyChange(key, newValue); } return done; }
/** * Puts the given value in cache and immediately returns the old value. * A null {@code value} argument removes the entry. If a different value is under computation in another thread, * then the other thread may fail with an {@link IllegalStateException} unless {@link #isKeyCollisionAllowed()} * returns {@code true}. For more safety, consider using {@link #putIfAbsent putIfAbsent(…)} instead. * * @param key the key to associate with a value. * @param value the value to associate with the given key, or {@code null} for removing the mapping. * @return the value previously mapped to the given key, or {@code null} if no value existed before this * method call or if the value was under computation in another thread. * * @see #get(Object) * @see #putIfAbsent(Object, Object) */ @Override public V put(final K key, final V value) { ensureValidType(value); final Object previous = (value != null) ? map.put(key, value) : map.remove(key); if (previous != value) { notifyChange(key, value); } return immediateValueOf(previous); }
/** * If the given key is mapped to any value, replaces that value with the given new value. * Otherwise does nothing. A null {@code value} argument removes the entry. * If a different value is under computation in another thread, then the other thread may fail with * an {@link IllegalStateException} unless {@link #isKeyCollisionAllowed()} returns {@code true}. * * @param key key of the value to replace. * @param value the new value to use in replacement of the previous one, or {@code null} for removing the mapping. * @return the value previously mapped to the given key, or {@code null} if no value existed before this * method call or if the value was under computation in another thread. * * @see #replace(Object, Object, Object) * * @since 1.0 */ @Override public V replace(final K key, final V value) { ensureValidType(value); final Object previous = (value != null) ? map.replace(key, value) : map.remove(key); if (previous != null) { // A null value means that 'replace' did nothing. notifyChange(key, value); } return immediateValueOf(previous); }
/** * If no value is already mapped and no value is under computation for the given key, puts the given value * in the cache. Otherwise returns the current value (potentially blocking until the computation finishes). * A null {@code value} argument is equivalent to a no-op. Otherwise a {@code null} return value means that * the given {@code value} has been stored in the {@code Cache}. * * @param key the key to associate with a value. * @param value the value to associate with the given key if no value already exists, or {@code null}. * @return the existing value mapped to the given key, or {@code null} if none existed before this method call. * * @see #get(Object) * @see #computeIfAbsent(Object, Function) * * @since 1.0 */ @Override public V putIfAbsent(final K key, final V value) { if (value == null) { return null; } ensureValidType(value); final Object previous = map.putIfAbsent(key, value); if (previous == null) { // A non-null value means that 'putIfAbsent' did nothing. notifyChange(key, value); } return valueOf(previous); }
notifyChange(key, result);