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

io.polaris.core.map.ReferenceMap Maven / Gradle / Ivy

There is a newer version: 3.2.1
Show newest version
package io.polaris.core.map;

import io.polaris.core.function.FunctionWithArgs3;
import io.polaris.core.map.reference.ReferenceType;
import io.polaris.core.map.reference.ValueReference;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author Qt
 * @since 1.8
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public class ReferenceMap extends AbstractMap implements Map {

	private final BiFunction, Reference> keyRreferenceFactory;
	private final FunctionWithArgs3, V, ReferenceQueue, ValueReference, V>> valueReferenceFactory;
	private final Map, ValueReference, V>> raw;
	private final ReferenceQueue keyQueue = new ReferenceQueue<>();
	private final ReferenceQueue valueQueue = new ReferenceQueue<>();


	public ReferenceMap(Map, ValueReference, V>> raw, ReferenceType referenceType) {
		this.raw = raw;
		this.valueReferenceFactory = referenceType::buildValueReference;
		this.keyRreferenceFactory = referenceType::buildKeyReference;
	}

	public ReferenceMap(Supplier, ValueReference, V>>> supplier, ReferenceType referenceType) {
		this(supplier.get(), referenceType);
	}

	private Reference buildKeyReference(K key) {
		return keyRreferenceFactory.apply(key, keyQueue);
	}

	private ValueReference, V> buildValueReference(Reference key, V value) {
		return valueReferenceFactory.apply(key, value, valueQueue);
	}

	private void processQueue() {
		{
			// remove by key
			Reference ref;
			while ((ref = keyQueue.poll()) != null) {
				raw.remove(ref);
			}
		}
		{
			// remove by value
			Reference ref;
			while ((ref = valueQueue.poll()) != null) {
				if (ref instanceof ValueReference) {
					ValueReference, V> vr = (ValueReference, V>) ref;
					Reference keyRef = vr.key();
					raw.remove(keyRef, vr);
				}
			}
		}
	}

	public int size() {
		processQueue();
		return raw.size();
	}

	public boolean isEmpty() {
		processQueue();
		return raw.isEmpty();
	}

	public boolean containsKey(Object key) {
		if (key == null) {
			throw new NullPointerException();
		}
		processQueue();
		return raw.containsKey(buildKeyReference((K) key));
	}

	public V get(Object key) {
		if (key == null) {
			throw new NullPointerException();
		}
		processQueue();
		ValueReference, V> ref = raw.get(buildKeyReference((K) key));
		if (ref != null) {
			return ref.value();
		}
		return null;
	}

	public V put(K key, V value) {
		if (key == null) {
			throw new NullPointerException();
		}
		if (value == null) {
			throw new NullPointerException();
		}
		processQueue();
		Reference keyRef = buildKeyReference((K) key);
		ValueReference, V> ref = raw.put(keyRef, buildValueReference(keyRef, value));
		if (ref != null) {
			return ref.value();
		}
		return null;
	}

	public V remove(Object key) {
		if (key == null) {
			throw new NullPointerException();
		}
		processQueue();
		ValueReference, V> removed = raw.remove(buildKeyReference((K) key));
		if (removed == null) {
			return null;
		}
		return removed.value();
	}

	public void clear() {
		processQueue();
		raw.clear();
	}

	@Override
	public java.util.Set> entrySet() {
		if (raw.isEmpty()) {
			return Collections.emptyMap().entrySet();
		}
		processQueue();
		if (raw.isEmpty()) {
			return Collections.emptyMap().entrySet();
		}
		Map map = new HashMap();
		for (Entry, ValueReference, V>> entry : raw.entrySet()) {
			ValueReference, V> valueReference = entry.getValue();
			if (valueReference == null) {
				continue;
			}
			V value = valueReference.value();
			if (value == null) {
				continue;
			}
			K key = entry.getKey().get();
			if (key == null) {
				continue;
			}
			map.put(key, value);
		}
		return map.entrySet();
	}

	// region 代理接口默认方法

	@Override
	public void replaceAll(BiFunction function) {
		processQueue();
		raw.replaceAll((k, v) ->
			buildValueReference(k, function.apply(k.get(), v.value()))
		);
	}

	@Override
	public V putIfAbsent(K key, V value) {
		processQueue();
		Reference keyRef = buildKeyReference(key);
		ValueReference, V> ref = raw.putIfAbsent(keyRef, buildValueReference(keyRef, value));
		return ref == null ? null : ref.value();
	}

	@Override
	public boolean remove(Object key, Object value) {
		processQueue();
		Reference keyRef = buildKeyReference((K) key);
		return raw.remove(keyRef, buildValueReference(keyRef, (V) value));
	}

	@Override
	public boolean replace(K key, V oldValue, V newValue) {
		processQueue();
		Reference keyRef = buildKeyReference(key);
		return raw.replace(keyRef, buildValueReference(keyRef, oldValue), buildValueReference(keyRef, newValue));
	}

	@Override
	public V replace(K key, V value) {
		processQueue();
		Reference keyRef = buildKeyReference(key);
		ValueReference, V> ref = raw.replace(keyRef, buildValueReference(keyRef, value));
		return ref == null ? null : ref.value();
	}

	@Override
	public V computeIfAbsent(K key, Function mappingFunction) {
		processQueue();
		Reference keyRef = buildKeyReference(key);
		ValueReference, V> ref = raw.computeIfAbsent(keyRef, (k) -> buildValueReference(k, mappingFunction.apply(k.get())));
		return ref == null ? null : ref.value();
	}

	@Override
	public V computeIfPresent(K key, BiFunction remappingFunction) {
		processQueue();
		Reference keyRef = buildKeyReference(key);
		ValueReference, V> ref = raw.computeIfPresent(keyRef, (k, v) ->
			buildValueReference(k, v == null ? null : remappingFunction.apply(k.get(), v.value())));
		return ref == null ? null : ref.value();
	}

	@Override
	public V compute(K key, BiFunction remappingFunction) {
		processQueue();
		Reference keyRef = buildKeyReference(key);
		ValueReference, V> ref = raw.compute(keyRef, (k, v) ->
			buildValueReference(k, remappingFunction.apply(k.get(), v == null ? null : v.value())));
		return ref == null ? null : ref.value();
	}

	@Override
	public V merge(K key, V value, BiFunction remappingFunction) {
		processQueue();
		Reference keyRef = buildKeyReference(key);
		ValueReference, V> ref = raw.merge(keyRef, buildValueReference(keyRef, value), (v1, v2) ->
			buildValueReference(keyRef, remappingFunction.apply(v1.value(), v2.value())));
		return ref == null ? null : ref.value();
	}

	// endregion

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy