Async Memoization

Memoization utilities for caching expensive sync and async computations.

← Back
Language: swift | Tags: memoization cache performance actor
/// Memoize expensive computations
func memoize<Input: Hashable, Output>(
    _ function: @escaping (Input) -> Output
) -> (Input) -> Output {
    var cache: [Input: Output] = [:]
    return { input in
        if let cached = cache[input] { return cached }
        let result = function(input)
        cache[input] = result
        return result
    }
}

/// Actor-based async memoization (thread-safe)
actor AsyncMemoizer<Input: Hashable, Output> {
    private var cache: [Input: Output] = [:]
    private var inProgress: [Input: Task<Output, Error>] = [:]

    func memoize(
        _ input: Input,
        compute: @escaping (Input) async throws -> Output
    ) async throws -> Output {
        if let cached = cache[input] { return cached }
        if let existing = inProgress[input] { return try await existing.value }

        let task = Task { try await compute(input) }
        inProgress[input] = task

        do {
            let result = try await task.value
            cache[input] = result
            inProgress[input] = nil
            return result
        } catch {
            inProgress[input] = nil
            throw error
        }
    }
}

// Usage:
// let memoizedFib = memoize { n in n <= 1 ? n : fib(n-1) + fib(n-2) }
// let memoizer = AsyncMemoizer<URL, Data>()
// let data = try await memoizer.memoize(url) { try await fetchData($0) }