Skip to content

Commit fad3c10

Browse files
authored
Merge pull request #1867 from ahoppen/cache-transformed
Cached transformed results in `Cache`
2 parents 3cf015a + 1c1a1cf commit fad3c10

File tree

2 files changed

+27
-12
lines changed

2 files changed

+27
-12
lines changed

Sources/BuildSystemIntegration/BuildSystemManager.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,19 +1012,21 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
10121012
return []
10131013
}
10141014

1015+
let request = BuildTargetSourcesRequest(targets: targets.sorted { $0.uri.stringValue < $1.uri.stringValue })
1016+
10151017
// If we have a cached request for a superset of the targets, serve the result from that cache entry.
10161018
let fromSuperset = await orLog("Getting source files from superset request") {
1017-
try await cachedTargetSources.get(isolation: self) { request in
1018-
targets.isSubset(of: request.targets)
1019-
} transform: { response in
1020-
return BuildTargetSourcesResponse(items: response.items.filter { targets.contains($0.target) })
1021-
}
1019+
try await cachedTargetSources.getDerived(
1020+
isolation: self,
1021+
request,
1022+
canReuseKey: { targets.isSubset(of: $0.targets) },
1023+
transform: { BuildTargetSourcesResponse(items: $0.items.filter { targets.contains($0.target) }) }
1024+
)
10221025
}
10231026
if let fromSuperset {
10241027
return fromSuperset.items
10251028
}
10261029

1027-
let request = BuildTargetSourcesRequest(targets: targets.sorted { $0.uri.stringValue < $1.uri.stringValue })
10281030
let response = try await cachedTargetSources.get(request, isolation: self) { request in
10291031
try await buildSystemAdapter.send(request)
10301032
}

Sources/SwiftExtensions/Cache.swift

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,28 @@ package class Cache<Key: Sendable & Hashable, Result: Sendable> {
3333
return try await task.value
3434
}
3535

36-
package func get(
36+
/// Get the value cached for `key`. If no value exists for `key`, try deriving the result from an existing cache entry
37+
/// that satisfies `canReuseKey` by applying `transform` to that result.
38+
package func getDerived(
3739
isolation: isolated any Actor,
38-
whereKey keyPredicate: (Key) -> Bool,
39-
transform: @Sendable @escaping (Result) -> Result
40+
_ key: Key,
41+
canReuseKey: @Sendable @escaping (Key) -> Bool,
42+
transform: @Sendable @escaping (_ cachedResult: Result) -> Result
4043
) async throws -> Result? {
41-
for (key, value) in storage {
42-
if keyPredicate(key) {
43-
return try await transform(value.value)
44+
if let cached = storage[key] {
45+
// If we have a value for the requested key, prefer that
46+
return try await cached.value
47+
}
48+
49+
// See if don't have an entry for this key, see if we can derive the value from a cached entry.
50+
for (cachedKey, cachedValue) in storage {
51+
guard canReuseKey(cachedKey) else {
52+
continue
4453
}
54+
let transformed = Task { try await transform(cachedValue.value) }
55+
// Cache the transformed result.
56+
storage[key] = transformed
57+
return try await transformed.value
4558
}
4659
return nil
4760
}

0 commit comments

Comments
 (0)