/*
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package org.glassfish.pfl.dynamic.copyobject.impl;

import java.util.Set ;
import java.util.Map ;
import java.util.AbstractMap ;

A cache intended to help speed up access to a Map. The idea is that some maps have a few values that are retrieved more frequently than others. So, we create a fixed size array that holds keys and values, and do a very fast hash on the key's identityHashCode. The cache is backed by a map, which can be an IdentityHashMap, or any other map (such as a WeakHashMap) where the keys satisfy k1.equals(k2) implies k1 == k2. Note that all put operations MUST go through this class, because calling put on the underlying map can result in the cache returning incorrect results for get.
/** A cache intended to help speed up access to a Map. * The idea is that some maps have a few values that are retrieved * more frequently than others. So, we create a fixed size array * that holds keys and values, and do a very fast hash on the key's * identityHashCode. The cache is backed by a map, which can be * an IdentityHashMap, or any other map (such as a WeakHashMap) * where the keys satisfy k1.equals(k2) implies k1 == k2. * Note that all put operations MUST go through this class, * because calling put on the underlying map can result in * the cache returning incorrect results for get. */
public class FastCache<K,V> extends AbstractMap<K,V> { public static final int TABLE_SIZE = 256 ; // must be a power of 2 private Map<K,V> map ; private Object[] keys = new Object[256] ; private Object[] values = new Object[256] ; private long cacheCount = 0 ; private long totalCount = 0 ; public long getCacheCount() { return cacheCount ; } public long getTotalCount() { return totalCount ; } public FastCache( Map<K,V> map ) { this.map = map ; } @Override public Set<Map.Entry<K,V>> entrySet() { return map.entrySet() ; } private int hash( Object key ) { // int hv = key.hashCode() ; int hv = System.identityHashCode( key ) ; return hv & (TABLE_SIZE-1) ; } @Override @SuppressWarnings("unchecked") public V get( Object key ) { totalCount++ ; int slot = hash( key ) ; @SuppressWarnings("unchecked") K ckey = (K)keys[slot] ; if (ckey == key ) { cacheCount++ ; return (V)values[slot] ; } else { V result = map.get( key ) ; keys[slot] = key ; values[slot] = result ; return result ; } }
Put the key and value in the cache and the underlying map. This writes through to the map, rather than first storing a value in the cache which is only written as required, because that makes it easier to preserve the correct behavior of the map.
/** Put the key and value in the cache and the underlying * map. This writes through to the map, rather than * first storing a value in the cache which is only * written as required, because that makes it easier * to preserve the correct behavior of the map. */
@Override public V put( K key, V value ) { int slot = hash( key ) ; keys[slot] = key ; values[slot] = value ; return map.put( key, value ) ; } }