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

org.apache.jena.atlas.lib.RefCountingMap Maven / Gradle / Ivy

There is a newer version: 5.2.0
Show newest version
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.jena.atlas.lib;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * A key {@literal ->} value 'map' which reference counts entries.
 *
 * 

* The same (key,value) pair can be added to the map several times and then * removed several times. A reference count is incremented for each addition * and, provided the count is greater than 0, decremented on removal. *

* *

* The pair is removed from the map when a remove decrements the reference count to 0. *

* *

* This class is thread safe. *

* * @param * @param */ public class RefCountingMap { /* * Uses CountedRef instances which are pairs of an integer and * and a reference. These instances are immutable - a new instance * is created on each increment/decrement operation. This could * result in churn in the garbage collector under heavy use. */ protected Map> map = new ConcurrentHashMap<>() ; public RefCountingMap() {} public boolean contains(K key) { return map.containsKey(key) ; } public Collection keys() { return map.keySet() ; } public int size() { return map.size() ; } public boolean isEmpty() { return map.isEmpty() ; } /** Clear the map of all keys regardless of reference counts. */ public void clear() { map.clear() ; } public Set keySet() { return map.keySet(); } public boolean containsKey(Object key) { return map.containsKey(key); } /** * Add a key value pair to the map. * *

* if there is no entry in the map for the key, then a key value pair is added * to the map with a reference count of 1. *

* *

* If there is already an entry in the map for the same key and value, * the reference count for that entry is incremented. *

* *

* if there is an entry in the map for the key, but with a different value, * then that entry is replaced with a new entry for the key and value with * a reference count of 1. *

* * @param key * @param value */ public void add(K key, T value) { // map.compute is atomic map.compute(key, (k, v) -> { int refCount = 1 ; if (v != null && ( v.getRef().equals(value) ) ) { refCount = v.getCount() + 1; } return new CountedRef<>(value, refCount ); }); } /** * Decrement the reference count for a key, and remove the corresponding entry from the map * if the result is 0. * *

* Do nothing if there is no entry in the map corresponding to the key. *

* @param key */ public void remove(K key) { // map.compute is atomic map.compute(key, (k, v) -> { if (v == null) return null ; int refCount = v.getCount() - 1 ; if ( refCount == 0 ) return null ; else return new CountedRef<>(v.getRef(), refCount); }); } /** * Remove the entry corresponding to the key from the map completely. * *

* This method ignores the reference count. *

* * @param key */ public void removeAll(K key) { map.remove(key); } /** * Return the reference count for the entry corresponding to a key in the map. * *

* Returns 0 if there is no entry in the map corresponding to the key. *

* @param key * @return the reference count for the entry corresponding to key in the map, * or 0 if there is no corresponding entry. */ public int refCount(K key) { CountedRef ref = map.get(key); if (ref == null) { return 0 ; } else { return ref.getCount(); } } /** * Return the value associated with a key in the map. * * @param key * @return the value associated with the key, or null if there is no such value. */ public T get(Object key) { CountedRef ref = map.get(key); if ( ref == null ) return null ; return ref.getRef(); } /* * An immutable pair of an integer count and an object reference */ class CountedRef { final int refCount; final R ref; CountedRef(R ref, int refCount) { this.refCount = refCount; this.ref = ref; } int getCount() { return refCount ; } R getRef() { return ref; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy