All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.javassist.scopedpool.SoftValueHashMap Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 */

package com.feilong.lib.javassist.scopedpool;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * This Map will remove entries when the value in the map has been cleaned from
 * garbage collection
 * 
 * @version $Revision: 1.4 $
 * @author Bill Burke
 */
public class SoftValueHashMap implements Map{

    private static class SoftValueRef extends SoftReference{

        public K key;

        private SoftValueRef(K key, V val, ReferenceQueue q){
            super(val, q);
            this.key = key;
        }

        private static  SoftValueRef create(K key,V val,ReferenceQueue q){
            if (val == null){
                return null;
            }else{
                return new SoftValueRef<>(key, val, q);
            }
        }

    }

    /**
     * Returns a set of the mappings contained in this hash table.
     */
    @Override
    public Set> entrySet(){
        processQueue();
        Set> ret = new HashSet<>();
        for (Entry> e : hash.entrySet()){
            ret.add(new SimpleImmutableEntry<>(e.getKey(), e.getValue().get()));
        }
        return ret;
    }

    /* Hash table mapping WeakKeys to values */
    private Map> hash;

    /* Reference queue for cleared WeakKeys */
    private ReferenceQueue          queue = new ReferenceQueue<>();

    /*
     * Remove all invalidated entries from the map, that is, remove all entries
     * whose values have been discarded.
     */
    private void processQueue(){
        Object ref;
        if (!hash.isEmpty()){
            while ((ref = queue.poll()) != null){
                if (ref instanceof SoftValueRef){
                    @SuppressWarnings("rawtypes")
                    SoftValueRef que = (SoftValueRef) ref;
                    if (ref == hash.get(que.key)){
                        // only remove if it is the *exact* same SoftValueRef
                        hash.remove(que.key);
                    }
                }
            }
        }
    }

    /* -- Constructors -- */

    /**
     * Constructs a new, empty WeakHashMap with the given initial
     * capacity and the given load factor.
     * 
     * @param initialCapacity
     *            The initial capacity of the WeakHashMap
     * 
     * @param loadFactor
     *            The load factor of the WeakHashMap
     * 
     * @throws IllegalArgumentException
     *             If the initial capacity is less than zero, or if the load
     *             factor is nonpositive
     */
    public SoftValueHashMap(int initialCapacity, float loadFactor){
        hash = new ConcurrentHashMap<>(initialCapacity, loadFactor);
    }

    /**
     * Constructs a new, empty WeakHashMap with the given initial
     * capacity and the default load factor, which is 0.75.
     * 
     * @param initialCapacity
     *            The initial capacity of the WeakHashMap
     * 
     * @throws IllegalArgumentException
     *             If the initial capacity is less than zero
     */
    public SoftValueHashMap(int initialCapacity){
        hash = new ConcurrentHashMap<>(initialCapacity);
    }

    /**
     * Constructs a new, empty WeakHashMap with the default
     * initial capacity and the default load factor, which is 0.75.
     */
    public SoftValueHashMap(){
        hash = new ConcurrentHashMap<>();
    }

    /**
     * Constructs a new WeakHashMap with the same mappings as the
     * specified Map. The WeakHashMap is created with
     * an initial capacity of twice the number of mappings in the specified map
     * or 11 (whichever is greater), and a default load factor, which is
     * 0.75.
     * 
     * @param t
     *            the map whose mappings are to be placed in this map.
     */
    public SoftValueHashMap(Map t){
        this(Math.max(2 * t.size(), 11), 0.75f);
        putAll(t);
    }

    /* -- Simple queries -- */

    /**
     * Returns the number of key-value mappings in this map. Note:
     * In contrast with most implementations of the
     * Map interface, the time required by this operation is
     * linear in the size of the map.
     */
    @Override
    public int size(){
        processQueue();
        return hash.size();
    }

    /**
     * Returns true if this map contains no key-value mappings.
     */
    @Override
    public boolean isEmpty(){
        processQueue();
        return hash.isEmpty();
    }

    /**
     * Returns true if this map contains a mapping for the
     * specified key.
     * 
     * @param key
     *            The key whose presence in this map is to be tested.
     */
    @Override
    public boolean containsKey(Object key){
        processQueue();
        return hash.containsKey(key);
    }

    /* -- Lookup and modification operations -- */

    /**
     * Returns the value to which this map maps the specified key.
     * If this map does not contain a value for this key, then return
     * null.
     * 
     * @param key
     *            The key whose associated value, if any, is to be returned.
     */
    @Override
    public V get(Object key){
        processQueue();
        return valueOrNull(hash.get(key));
    }

    /**
     * Updates this map so that the given key maps to the given
     * value. If the map previously contained a mapping for
     * key then that mapping is replaced and the previous value
     * is returned.
     * 
     * @param key
     *            The key that is to be mapped to the given value
     * @param value
     *            The value to which the given key is to be
     *            mapped
     * 
     * @return The previous value to which this key was mapped, or
     *         null if if there was no mapping for the key
     */
    @Override
    public V put(K key,V value){
        processQueue();
        return valueOrNull(hash.put(key, SoftValueRef.create(key, value, queue)));
    }

    /**
     * Removes the mapping for the given key from this map, if
     * present.
     * 
     * @param key
     *            The key whose mapping is to be removed.
     * 
     * @return The value to which this key was mapped, or null if
     *         there was no mapping for the key.
     */
    @Override
    public V remove(Object key){
        processQueue();
        return valueOrNull(hash.remove(key));
    }

    /**
     * Removes all mappings from this map.
     */
    @Override
    public void clear(){
        processQueue();
        hash.clear();
    }

    /*
     * Check whether the supplied value exists.
     * 
     * @param Object the value to compare.
     * 
     * @return true if it was found or null.
     */
    @Override
    public boolean containsValue(Object arg0){
        processQueue();
        if (null == arg0){
            return false;
        }

        for (SoftValueRef e : hash.values()){
            if (null != e && arg0.equals(e.get())){
                return true;
            }
        }
        return false;
    }

    /* {@inheritDoc} */
    @Override
    public Set keySet(){
        processQueue();
        return hash.keySet();
    }

    /* {@inheritDoc} */
    @Override
    public void putAll(Map arg0){
        processQueue();
        for (K key : arg0.keySet()){
            put(key, arg0.get(key));
        }
    }

    /* {@inheritDoc} */
    @Override
    public Collection values(){
        processQueue();
        List ret = new ArrayList<>();
        for (SoftValueRef e : hash.values()){
            ret.add(e.get());
        }
        return ret;
    }

    private V valueOrNull(SoftValueRef rtn){
        if (null == rtn){
            return null;
        }
        return rtn.get();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy