-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into functional-shorthands
- Loading branch information
Showing
28 changed files
with
1,323 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
java-commons/src/main/java/ru/progrm_jarvis/javacommons/cache/Cache.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package ru.progrm_jarvis.javacommons.cache; | ||
|
||
import lombok.NonNull; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
import java.util.function.Function; | ||
|
||
/** | ||
* Simple cache interface. | ||
* {@link #never() No-op implementation} (the one which never performs any caching) is considered correct. | ||
* | ||
* @param <K> type of cache keys | ||
* @param <V> type of cached values | ||
* | ||
* @apiNote currently <b>java-commons</b> does not implement its own functional cache, | ||
* it simply provides a universal interface and wrappers for known implementations | ||
*/ | ||
@FunctionalInterface | ||
public interface Cache<K, V> { | ||
|
||
/** | ||
* Gets the value from the cache computing it on demand using the provided function. | ||
* | ||
* @param key key by which ti get the value from cache | ||
* @param mappingFunction function used to create the value if there is no cached one | ||
* @return the current value associated with the specified key | ||
* | ||
* @throws NullPointerException if {@code key} is {@code null} | ||
* @throws NullPointerException if {@code mappingFunction} is {@code null} | ||
*/ | ||
V get(@NonNull K key, @NonNull Function<? super K, ? extends V> mappingFunction); | ||
|
||
/** | ||
* Creates a cache which actually never performs caching. | ||
* | ||
* @param <K> type of cache keys | ||
* @param <V> type of cached values | ||
* @return cache which actually never performs caching | ||
*/ | ||
static @NotNull <K, V> Cache<K, V> never() { | ||
return (key, mappingFunction) -> mappingFunction.apply(key); | ||
} | ||
} |
74 changes: 74 additions & 0 deletions
74
java-commons/src/main/java/ru/progrm_jarvis/javacommons/cache/CacheFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package ru.progrm_jarvis.javacommons.cache; | ||
|
||
import lombok.AccessLevel; | ||
import lombok.NoArgsConstructor; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
/** | ||
* Factory used for creation of generic {@link Cache caches}. | ||
*/ | ||
public interface CacheFactory { | ||
|
||
/** | ||
* Creates a new cache whose keys will be stored {@link java.lang.ref.WeakReference weakly}. | ||
* | ||
* @param <K> type of cache keys | ||
* @param <V> type of cached values | ||
* @return weak keys cache | ||
*/ | ||
<K, V> @NotNull Cache<K, V> weakKeysCache(); | ||
|
||
/** | ||
* Creates a new cache whose values will be stored {@link java.lang.ref.WeakReference weakly}. | ||
* | ||
* @param <K> type of cache keys | ||
* @param <V> type of cached values | ||
* @return weak values cache | ||
*/ | ||
<K, V> @NotNull Cache<K, V> weakValuesCache(); | ||
|
||
/** | ||
* Creates a new cache whose values will be stored {@link java.lang.ref.SoftReference softly}. | ||
* | ||
* @param <K> type of cache keys | ||
* @param <V> type of cached values | ||
* @return soft values cache | ||
*/ | ||
<K, V> @NotNull Cache<K, V> softValuesCache(); | ||
|
||
/** | ||
* Creates a cache factory which always creates {@link Cache#never() no-op caches}. | ||
* | ||
* @return cache factory which always supplies {@link Cache#never() no-op caches} | ||
*/ | ||
static @NotNull CacheFactory never() { | ||
return NeverCacheFactory.INSTANCE; | ||
} | ||
|
||
/** | ||
* {@link CacheFactory} which always creates {@link Cache#never() no-op caches}. | ||
*/ | ||
@NoArgsConstructor(access = AccessLevel.PRIVATE) | ||
final class NeverCacheFactory implements CacheFactory { | ||
|
||
/** | ||
* Singleton instance of this cache factory. | ||
*/ | ||
private static final @NotNull CacheFactory INSTANCE = new NeverCacheFactory(); | ||
|
||
@Override | ||
public <K, V> @NotNull Cache<K, V> weakKeysCache() { | ||
return Cache.never(); | ||
} | ||
|
||
@Override | ||
public <K, V> @NotNull Cache<K, V> weakValuesCache() { | ||
return Cache.never(); | ||
} | ||
|
||
@Override | ||
public <K, V> @NotNull Cache<K, V> softValuesCache() { | ||
return Cache.never(); | ||
} | ||
} | ||
} |
66 changes: 66 additions & 0 deletions
66
java-commons/src/main/java/ru/progrm_jarvis/javacommons/cache/Caches.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package ru.progrm_jarvis.javacommons.cache; | ||
|
||
import lombok.experimental.UtilityClass; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
/** | ||
* Utility for creating commonly used caches depending on runtime capabilities. | ||
* If no cache is available then {@link Cache#never() no-op cache} is used. | ||
*/ | ||
@UtilityClass | ||
public class Caches { | ||
|
||
/** | ||
* Factory used for creation of {@link Cache caches}. | ||
* This will try to be the best implementation available | ||
* but will fallback to {@link CacheFactory#never() no-op} if none is available. | ||
*/ | ||
private final @NotNull CacheFactory DEFAULT_FACTORY; | ||
|
||
static { | ||
final CacheFactory factory; | ||
DEFAULT_FACTORY = (factory = CaffeineCache.tryCreateFactory()) == null ? CacheFactory.never() : factory; | ||
} | ||
|
||
/** | ||
* Gets the default cache factory. | ||
* | ||
* @return default cache factory | ||
*/ | ||
public @NotNull CacheFactory defaultFactory() { | ||
return DEFAULT_FACTORY; | ||
} | ||
|
||
/** | ||
* Creates a new cache whose keys will be stored {@link java.lang.ref.WeakReference weakly}. | ||
* | ||
* @param <K> type of cache keys | ||
* @param <V> type of cached values | ||
* @return weak keys cache | ||
*/ | ||
public <K, V> @NotNull Cache<K, V> weakKeysCache() { | ||
return DEFAULT_FACTORY.weakKeysCache(); | ||
} | ||
|
||
/** | ||
* Creates a new cache whose values will be stored {@link java.lang.ref.WeakReference weakly}. | ||
* | ||
* @param <K> type of cache keys | ||
* @param <V> type of cached values | ||
* @return weak values cache | ||
*/ | ||
public <K, V> @NotNull Cache<K, V> weakValuesCache() { | ||
return DEFAULT_FACTORY.weakValuesCache(); | ||
} | ||
|
||
/** | ||
* Creates a new cache whose values will be stored {@link java.lang.ref.WeakReference softly}. | ||
* | ||
* @param <K> type of cache keys | ||
* @param <V> type of cached values | ||
* @return soft values cache | ||
*/ | ||
public <K, V> @NotNull Cache<K, V> softValuesCache() { | ||
return DEFAULT_FACTORY.softValuesCache(); | ||
} | ||
} |
97 changes: 97 additions & 0 deletions
97
java-commons/src/main/java/ru/progrm_jarvis/javacommons/cache/CaffeineCache.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package ru.progrm_jarvis.javacommons.cache; | ||
|
||
import com.github.benmanes.caffeine.cache.Caffeine; | ||
import lombok.AccessLevel; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.experimental.FieldDefaults; | ||
import lombok.experimental.UtilityClass; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
import ru.progrm_jarvis.javacommons.util.BlackHole; | ||
|
||
/** | ||
* Utilities for creation of <a href="https://github.com/ben-manes/caffeine">Caffeine</a>-based | ||
* {@link CacheFactory cache factories}. | ||
*/ | ||
@UtilityClass | ||
public class CaffeineCache { | ||
|
||
/** | ||
* Flag indicating whether {@link Caffeine} is available | ||
*/ | ||
private static final boolean AVAILABLE; | ||
|
||
static { | ||
boolean available = true; | ||
try { // check if Caffeine class is available | ||
BlackHole.consume(Caffeine.class); | ||
} catch (final Throwable ignored) { | ||
available = false; | ||
} | ||
AVAILABLE = available; | ||
} | ||
|
||
/** | ||
* Creates a Caffeine Cache factory. | ||
* | ||
* @return created Caffeine Cache factory | ||
* | ||
* @throws IllegalStateException if Caffeine is not available | ||
*/ | ||
public static @NotNull CacheFactory createFactory() { | ||
if (AVAILABLE) return new CaffeineCacheFactory(); | ||
|
||
throw new IllegalStateException("Caffeine Cache is not available"); | ||
} | ||
|
||
/** | ||
* Attempts to create a Caffeine Cache factory. | ||
* | ||
* @return created Caffeine Cache factory or {@code null} if it is unavailable | ||
*/ | ||
public static @Nullable CacheFactory tryCreateFactory() { | ||
return AVAILABLE ? CaffeineCacheFactory.INSTANCE : null; | ||
} | ||
|
||
/** | ||
* {@link CacheFactory} backed by Caffeine Cache. | ||
*/ | ||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) | ||
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) | ||
private static final class CaffeineCacheFactory implements CacheFactory { | ||
|
||
/** | ||
* Singleton instance of this {@link CacheFactory} implementation | ||
*/ | ||
private static final @NotNull CacheFactory INSTANCE = new CaffeineCacheFactory(); | ||
|
||
/** | ||
* Wraps the provided {@link com.github.benmanes.caffeine.cache.Cache Caffeine Cache} into {@link Cache}. | ||
* | ||
* @param caffeineCache Caffeine Cache to be wrapped | ||
* @param <K> type of cache keys | ||
* @param <V> type of cached values | ||
* @return wrapped Caffeine Cache | ||
*/ | ||
private static <K, V> @NotNull Cache<K, V> wrap( | ||
final @NotNull com.github.benmanes.caffeine.cache.Cache<K, V> caffeineCache | ||
) { | ||
return caffeineCache::get; | ||
} | ||
|
||
@Override | ||
public <K, V> @NotNull Cache<K, V> weakKeysCache() { | ||
return wrap(Caffeine.newBuilder().weakKeys().build()); | ||
} | ||
|
||
@Override | ||
public <K, V> @NotNull Cache<K, V> weakValuesCache() { | ||
return wrap(Caffeine.newBuilder().weakValues().build()); | ||
} | ||
|
||
@Override | ||
public <K, V> @NotNull Cache<K, V> softValuesCache() { | ||
return wrap(Caffeine.newBuilder().softValues().build()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.