/******************************************************************************* * Copyright (c) 2008, 2014 Stuart McCulloch * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Stuart McCulloch - initial API and implementation *******************************************************************************/ package org.eclipse.sisu.peaberry.internal; import static jsr166y.ConcurrentReferenceHashMap.Option.IDENTITY_COMPARISONS; import java.util.EnumSet; import java.util.concurrent.ConcurrentMap; import jsr166y.ConcurrentReferenceHashMap; import jsr166y.ConcurrentReferenceHashMap.Option; import jsr166y.ConcurrentReferenceHashMap.ReferenceType; /** * Provide computed maps based on the JSR166 {@link ConcurrentReferenceHashMap}. * * @see http://anonsvn.jboss.org/repos/jbosscache/experimental/jsr166/src/jsr166y * * @author mcculls@gmail.com (Stuart McCulloch) */ final class ComputedMapFactory { // instances not allowed private ComputedMapFactory() {} static final EnumSet<Option> IDENTITY = EnumSet.of(IDENTITY_COMPARISONS); /** * Computed mapping API. */ interface Function<K, V> { V compute(K key); } /** * @return concurrent computed map with the given reference types */ static <K, V> ConcurrentMap<K, V> computedMap(final ReferenceType keyType, final ReferenceType valType, final int capacity, final Function<K, V> function) { return new ComputedMap<K, V>(keyType, valType, capacity, function); } private static final class ComputedMap<K, V> extends ConcurrentReferenceHashMap<K, V> { private static final long serialVersionUID = 1L; private transient final Function<K, V> function; public ComputedMap(final ReferenceType keyType, final ReferenceType valType, final int capacity, final Function<K, V> function) { // small concurrency level, as most threads just read super(capacity, 0.75f, 2, keyType, valType, IDENTITY); this.function = function; } @Override @SuppressWarnings("unchecked") public V get(final Object key) { V value = super.get(key); if (null == value) { // no mapping, use key to compute a value final V newValue = function.compute((K) key); value = putIfAbsent((K) key, newValue); // /CLOVER:OFF if (null == value) { // /CLOVER:ON return newValue; } } return value; } } }