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

com.neko233.toolchain.common.base.Memoizer Maven / Gradle / Ivy

package com.neko233.toolchain.common.base;

import com.neko233.toolchain.common.annotation.ThreadSafe;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;


/**
 * 备忘录 with TTL. 存储相同的输入
 * A memoized function stores the output corresponding to some set of specific
 * inputs. Subsequent calls with remembered inputs return the remembered result
 * rather than recalculating it.
 *
 * @author SolarisNeko
 */
@ThreadSafe
public final class Memoizer {

    // 1min expire
    private static final Supplier DEFAULT_EXPIRATION_NANOS = memoize(Memoizer::queryExpirationConfig,
            TimeUnit.MINUTES.toNanos(1));

    private Memoizer() {
    }

    private static long queryExpirationConfig() {
        return TimeUnit.MILLISECONDS.toNanos(BaseGlobalConfig233.get(BaseGlobalConfig233.OSHI_UTIL_MEMOIZER_EXPIRATION, 300));
    }

    /**
     * @return The number of nanoseconds to keep memoized values before refreshing
     */
    public static long defaultExpiration() {
        return DEFAULT_EXPIRATION_NANOS.get();
    }

    /**
     * Store a supplier in a delegate function to be computed once, and only again
     * after time to live (ttl) has expired.
     *
     * @param       The type of object supplied
     * @param original The {@link java.util.function.Supplier} to memoize
     * @param ttlNanos Time in nanoseconds to retain calculation. If negative, retain
     *                 indefinitely.
     * @return A memoized version of the supplier
     */
    public static  Supplier memoize(Supplier original, long ttlNanos) {
        // Adapted from Guava's ExpiringMemoizingSupplier
        return new Supplier() {
            final Supplier delegate = original;
            volatile T value; // NOSONAR squid:S3077
            volatile long expirationNanos;

            @Override
            public T get() {
                long nanos = expirationNanos;
                long now = System.nanoTime();
                if (nanos == 0 || (ttlNanos >= 0 && now - nanos >= 0)) {
                    synchronized (this) {
                        if (nanos == expirationNanos) { // recheck for lost race
                            T t = delegate.get();
                            value = t;
                            nanos = now + ttlNanos;
                            expirationNanos = (nanos == 0) ? 1 : nanos;
                            return t;
                        }
                    }
                }
                return value;
            }
        };
    }

    /**
     * Store a supplier in a delegate function to be computed only once.
     *
     * @param       The type of object supplied
     * @param original The {@link java.util.function.Supplier} to memoize
     * @return A memoized version of the supplier
     */
    public static  Supplier memoize(Supplier original) {
        return memoize(original, -1L);
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy