protected void putFuture(K key, KeyedFuture<K, V> future) {
		futures.put(key, future);
		future.exceptionally((exc) -> {
			synchronized (this) {
				if (forgetErrors.test(key, exc)) {
					//Msg.debug(this, "Work failed for " + key + " -> " + exc);
					futures.remove(key);
				}
			}
			return ExceptionUtils.rethrow(exc);
		}).thenAccept(val -> {
			synchronized (this) {
				if (futures.get(key) != future) {
					// The pending future was invalidated
					return;
				}
				if (forgetValues.test(key, val)) {
					futures.remove(key);
					return;
				}
				//Msg.debug(this, "Work completed for " + key + " -> " + value);
				map.put(key, val);
			}
		});
	}
Construct a lazy map for the given function

@param map the backing map. The lazy map ought to have an exclusive reference to this map.
           Mutations to the map outside of those caused by the lazy map may cause undefined
           behavior.
@param function specifies the computation, given a key
Ghidra/Framework/Generic/src/main/java/ghidra/async/AsyncLazyMap.java