Using WeakRef for Caching

The following example uses WeakRef to implement a cache. If calculating certain data is time-consuming, we can use weak references to cache the results and prevent excessive caching that could lead to OOM.

import std.ref.{WeakRef, CleanupPolicy}

public interface Cacheable<T> {
    static func reCalculate() : T
}

public class Data <: Cacheable<Data> {
    public var number: Int64

    init(n : Int64) {
                number = n
    }

    public static func reCalculate(): Data {
        // Simulate calculation.
        println("re-calculations!")
        let data = Data(321)
        return data
    }
}

public class Cache<T> where T <: Object & Cacheable<T> {
    private var cache : WeakRef<T>

    public init(data: T) {
        cache = WeakRef<T>(data, CleanupPolicy.DEFERRED) // Here, we select the DEFERRED policy to store data for as long as possible.
    }

    public func getData(): T {
        match(cache.value) {
            case Some(x) => x
            case None =>
                // Perform recalculation if the GC releases the data in the cache.
                let data = T.reCalculate()
                cache = WeakRef<T>(data, CleanupPolicy.DEFERRED)
                data
        }
    }

    public func clear() : Unit {
        cache.clear()
    }
}

main () {
    let data = Data(123)
    var c = Cache<Data>(data)
    println(c.getData().number) // Read data directly from the cache. Recalculation is not required.
    println(c.getData().number) // Read data directly from the cache. Recalculation is not required.
    c.clear() // Clear the cache.
    println(c.getData().number) // Perform recalculation.
    return 0
}

Results:

123
123
re-calculations!
321