From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- ridljar/com/sun/star/lib/util/WeakMap.java | 319 +++++++++++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 ridljar/com/sun/star/lib/util/WeakMap.java (limited to 'ridljar/com/sun/star/lib/util/WeakMap.java') diff --git a/ridljar/com/sun/star/lib/util/WeakMap.java b/ridljar/com/sun/star/lib/util/WeakMap.java new file mode 100644 index 000000000..f3b3b55a3 --- /dev/null +++ b/ridljar/com/sun/star/lib/util/WeakMap.java @@ -0,0 +1,319 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package com.sun.star.lib.util; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * A hash map that holds values of type WeakReference. + * + *

Like HashMap, this implementation provides all of the + * optional map operations, and permits the null key.

+ * + *

Also like HashMap, this implementation is not synchronized. + * If multiple threads share an instance, and at least one of them executes any + * modifying operations on the WeakMap, they have to use external + * synchronization.

+ * + *

Unlike other map implementations, WeakMap is asymmetric in + * that put expects the given value to be a plain object that is + * then wrapped in a WeakReference, while the occurrences of values + * in all other methods (containsValue, entrySet, + * equals, get, hashCode, + * remove, values, and also the return value of + * put) expect already wrapped instances of + * WeakReference. That is, after weakMap.put("key", + * o), weakMap.get("key").equals(o) does not work as + * naïvely expected; neither does + * weakMap1.putAll(weakMap2).

+ * + *

At an arbitrary time after the WeakReference value of an + * entry has been cleared by the garbage collector, the entry is automatically + * removed from the map.

+ * + *

Values placed into a WeakMap may optionally support the + * DisposeNotifier interface. For those that do, the associated + * WeakReference wrappers are automatically cleared as soon as the + * values are disposed.

+ * + * Note that this class does not actually implement the Map interface properly, + * the type of the return value of the entrySet and values methods is wrong, + * but the "implements Map" is retained for backward compatibility. + */ +public final class WeakMap implements Map { + + /** + * Declare the map as WeakReference instead of Entry because it makes the return + * type signatures of values() and keySet() cleaner. + */ + private final HashMap> map = new HashMap>(); + private final ReferenceQueue queue = new ReferenceQueue(); + + /** + * Constructs an empty WeakMap. + */ + public WeakMap() {} + + /** + * Constructs a new WeakMap with the same mappings as the + * specified Map. + * + * @param m the map whose mappings are to be placed in this map + */ + public WeakMap(Map m) { + putAll(m); + } + + /** + * Returns the number of key–value mappings in this map. + * + *

This is a non-modifying operation.

+ * + * @return the number of key–value mappings in this map + */ + public int size() { + return map.size(); + } + + /** + * Returns true if this map contains no key–value + * mappings. + * + *

This is a non-modifying operation.

+ * + * @return true if this map contains no key–value + * mappings + */ + public boolean isEmpty() { + return map.isEmpty(); + } + + /** + * Returns true if this map contains a mapping for the + * specified key. + * + *

This is a non-modifying operation.

+ * + * @param key the key whose presence in this map is to be tested + * @return true if this map contains a mapping for the + * specified key + */ + public boolean containsKey(/*K*/ Object key) { + return map.containsKey(key); + } + + /** + * Returns true if this map maps one or more keys to the + * specified value. + * + *

This is a non-modifying operation.

+ * + * @param value the value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + */ + public boolean containsValue(Object /*WeakReference*/ value) { + return map.containsValue(value); + } + + /** + * Returns the value to which the specified key is mapped in this map, or + * null if the map contains no mapping for this key. + * + *

This is a non-modifying operation.

+ * + * @param key the key whose associated value is to be returned + * + * @return the value to which this map maps the specified key, or + * null if the map contains no mapping for this key + */ + public WeakReference get(/*K*/ Object key) { + return map.get(key); + } + + /** + * Associates the specified value with the specified key in this map. + * + *

This is a modifying operation.

+ * + * @param key the key with which the specified value is to be associated + * @param value the value to be associated with the specified key. This + * must be a plain object, which is then wrapped in a + * WeakReference. + * @return previous value associated with the specified key, or + * null if there was no mapping for the key + */ + public Object /*WeakReference*/ put(/*K*/ Object key, /*V*/ Object value) { + cleanUp(); + return map.put((K) key, new Entry((K) key, (V) value, queue)); + } + + /** + * Removes the mapping for this key from this map if present. + * + *

This is a modifying operation.

+ * + * @param key the key whose mapping is to be removed from the map + * @return previous value associated with the specified key, or + * null if there was no mapping for the key + */ + public Object /*WeakReference*/ remove(/*K*/ Object key) { + cleanUp(); + return map.remove(key); + } + + /** + * Copies all of the mappings from the specified map to this map. + * + *

This is a modifying operation.

+ * + * @param m mappings to be stored in this map. The values of those mappings + * must be plain objects, which are then wrapped in instances of + * WeakReference. + */ + public void putAll(Map/**/ m) { + cleanUp(); + for (Iterator> i = m.entrySet().iterator(); i.hasNext();) { + Map.Entry e = i.next(); + K k = e.getKey(); + map.put(k, new Entry(k, e.getValue(), queue)); + } + } + + /** + * Removes all mappings from this map. + * + *

This is a modifying operation.

+ */ + public void clear() { + cleanUp(); + map.clear(); + } + + /** + * Returns a view of the keys contained in this map. + * + *

This is a non-modifying operation.

+ * + * @return a set view of the keys contained in this map + */ + public Set keySet() { + return map.keySet(); + } + + /** + * Returns a collection view of the values contained in this map. + * + *

This is a non-modifying operation.

+ * + * @return a collection view of the values contained in this map + */ + public Collection> values() { + return map.values(); + } + + /** + * Returns a collection view of the mappings contained in this map. + * + *

This is a non-modifying operation.

+ * + * @return a collection view of the mappings contained in this map + */ + public Set/*>>*/ entrySet() { + return map.entrySet(); + } + + @Override + public boolean equals(Object o) { + return map.equals(o); + } + + @Override + public int hashCode() { + return map.hashCode(); + } + + /** + * Returns the referent of a WeakReference, silently handling a + * null argument. + * + *

This static method is useful to wrap around the return values of + * methods like get.

+ * + * @param ref must be either an instance of WeakReference or + * null + * @return the referent of the specified WeakReference, or + * null if ref is null + */ + public static T getValue(Object /*WeakReference*/ ref) { + return ref == null ? null : ((WeakReference) ref).get(); + } + + /** + * cleanUp() must only be called from within modifying methods. Otherwise, + * the implementations of entrySet, keySet and values would break + * (Specifically, iterating over the collections returned by those + * methods), as non-modifying methods might modify the underlying map. + **/ + private void cleanUp() { + for (;;) { + Entry e = (Entry) queue.poll(); + if (e == null) { + break; + } + // It is possible that an Entry e1 becomes weakly reachable, then + // another Entry e2 is added to the map for the same key, and only + // then e1 is enqueued. To not erroneously remove the new e2 in + // that case, check whether the map still contains e1: + Object k = e.key; + if (e == map.get(k)) { + map.remove(k); + } + } + } + + private static final class Entry extends WeakReference + implements DisposeListener + { + private final K key; + + private Entry(K key, V value, ReferenceQueue queue) { + super(value, queue); + this.key = key; + if (value instanceof DisposeNotifier) { + ((DisposeNotifier) value).addDisposeListener(this); + } + } + + /** + * @see DisposeListener#notifyDispose(DisposeNotifier) + */ + public void notifyDispose(DisposeNotifier source) { + clear(); + enqueue(); + } + } + +} -- cgit v1.2.3