Async Memoization
Memoization utilities for caching expensive sync and async computations.
/// 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) }