refactored private class UIDefaultsLoader.Cache to public class SoftCache and implement the Map interface

This commit is contained in:
Karl Tauber
2021-11-12 10:12:34 +01:00
parent d80b581ace
commit ccdb981917
2 changed files with 170 additions and 43 deletions

View File

@@ -26,9 +26,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -56,6 +53,7 @@ import com.formdev.flatlaf.util.DerivedColor;
import com.formdev.flatlaf.util.GrayFilter;
import com.formdev.flatlaf.util.HSLColor;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.SoftCache;
import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
@@ -84,7 +82,7 @@ class UIDefaultsLoader
private static int parseColorDepth;
private static final Cache<String, Object> fontCache = new Cache<>();
private static final SoftCache<String, Object> fontCache = new SoftCache<>();
static void loadDefaultsFromProperties( Class<?> lookAndFeelClass, List<FlatDefaultsAddon> addons,
Properties additionalDefaults, boolean dark, UIDefaults defaults )
@@ -1296,43 +1294,4 @@ class UIDefaultsLoader
private static void throwMissingParametersException( String value ) {
throw new IllegalArgumentException( "missing parameters in function '" + value + "'" );
}
//---- class Cache --------------------------------------------------------
private static class Cache<K,V>
{
private final Map<K, CacheReference<K,V>> map = new HashMap<>();
private final ReferenceQueue<V> queue = new ReferenceQueue<>();
V get( K key ) {
expungeStaleEntries();
CacheReference<K,V> ref = map.get( key );
return (ref != null) ? ref.get() : null;
}
void put( K key, V value ) {
expungeStaleEntries();
map.put( key, new CacheReference<>( key, value, queue ) );
}
@SuppressWarnings( "unchecked" )
void expungeStaleEntries() {
Reference<? extends V> reference;
while( (reference = queue.poll()) != null )
map.remove( ((CacheReference<K,V>)reference).key );
}
//---- class CacheReference ----
private static class CacheReference<K,V>
extends SoftReference<V>
{
final K key;
public CacheReference( K key, V value, ReferenceQueue<? super V> queue ) {
super( value, queue );
this.key = key;
}
}
}
}

View File

@@ -0,0 +1,168 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed 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
*
* https://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 com.formdev.flatlaf.util;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
/**
* A simple cache (map) that uses soft references for the values.
*
* @author Karl Tauber
* @since 2
*/
public class SoftCache<K,V>
implements Map<K, V>
{
private final Map<K, CacheReference<K,V>> map;
private final ReferenceQueue<V> queue = new ReferenceQueue<>();
public SoftCache() {
map = new HashMap<>();
}
public SoftCache( int initialCapacity ) {
map = new HashMap<>( initialCapacity );
}
@Override
public int size() {
expungeStaleEntries();
return map.size();
}
@Override
public boolean isEmpty() {
expungeStaleEntries();
return map.isEmpty();
}
@Override
public boolean containsKey( Object key ) {
expungeStaleEntries();
return map.containsKey( key );
}
/**
* Not supported. Throws {@link UnsupportedOperationException}.
*/
@Override
public boolean containsValue( Object value ) {
throw new UnsupportedOperationException();
}
@Override
public V get( Object key ) {
expungeStaleEntries();
return getRef( map.get( key ) );
}
@Override
public V put( K key, V value ) {
expungeStaleEntries();
return getRef( map.put( key, new CacheReference<>( key, value, queue ) ) );
}
@Override
public V remove( Object key ) {
expungeStaleEntries();
return getRef( map.remove( key ) );
}
private V getRef( CacheReference<K,V> ref ) {
return (ref != null) ? ref.get() : null;
}
@Override
public void putAll( Map<? extends K, ? extends V> m ) {
expungeStaleEntries();
for( Entry<? extends K, ? extends V> e : m.entrySet() )
put( e.getKey(), e.getValue() );
}
@Override
public void clear() {
map.clear();
expungeStaleEntries();
}
@Override
public Set<K> keySet() {
expungeStaleEntries();
return map.keySet();
}
/**
* Not supported. Throws {@link UnsupportedOperationException}.
*/
@Override
public Collection<V> values() {
throw new UnsupportedOperationException();
}
/**
* Not supported. Throws {@link UnsupportedOperationException}.
*/
@Override
public Set<Entry<K, V>> entrySet() {
throw new UnsupportedOperationException();
}
/**
* Not supported. Throws {@link UnsupportedOperationException}.
*/
@Override
public void forEach( BiConsumer<? super K, ? super V> action ) {
throw new UnsupportedOperationException();
}
/**
* Not supported. Throws {@link UnsupportedOperationException}.
*/
@Override
public void replaceAll( BiFunction<? super K, ? super V, ? extends V> function ) {
throw new UnsupportedOperationException();
}
@SuppressWarnings( "unchecked" )
private void expungeStaleEntries() {
Reference<? extends V> reference;
while( (reference = queue.poll()) != null )
map.remove( ((CacheReference<K,V>)reference).key );
}
//---- class CacheReference ----
private static class CacheReference<K,V>
extends SoftReference<V>
{
// needed to remove reference from map in expungeStaleEntries()
final K key;
CacheReference( K key, V value, ReferenceQueue<? super V> queue ) {
super( value, queue );
this.key = key;
}
}
}