Skip to content

Commit b01a8f2

Browse files
authored
[Swift 6] Add AtomicBox to CoreInternal (#14594)
1 parent f49b37f commit b01a8f2

File tree

2 files changed

+53
-12
lines changed

2 files changed

+53
-12
lines changed

FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift

+8-12
Original file line numberDiff line numberDiff line change
@@ -59,27 +59,23 @@ final class HeartbeatStorage: Sendable, HeartbeatStorageProtocol {
5959
// `nonisolated(unsafe)` to disable concurrency-safety checks. The
6060
// property's access is protected by an external synchronization mechanism
6161
// (see `instancesLock` property).
62-
private nonisolated(unsafe) static var cachedInstances: [
63-
String: WeakContainer<HeartbeatStorage>
64-
] = [:]
62+
private nonisolated(unsafe) static var cachedInstances: AtomicBox<
63+
[String: WeakContainer<HeartbeatStorage>]
64+
> = AtomicBox([:])
6565
#else
6666
// TODO(Xcode 16): Delete this block when minimum supported Xcode is
6767
// Xcode 16.
68-
private static var cachedInstances: [
69-
String: WeakContainer<HeartbeatStorage>
70-
] = [:]
68+
static var cachedInstances: AtomicBox<[String: WeakContainer<HeartbeatStorage>]> =
69+
AtomicBox([:])
7170
#endif // compiler(>=6)
7271

73-
/// Used to synchronize concurrent access to the `cachedInstances` property.
74-
private static let instancesLock = NSLock()
75-
7672
/// Gets an existing `HeartbeatStorage` instance with the given `id` if one exists. Otherwise,
7773
/// makes a new instance with the given `id`.
7874
///
7975
/// - Parameter id: A string identifier.
8076
/// - Returns: A `HeartbeatStorage` instance.
8177
static func getInstance(id: String) -> HeartbeatStorage {
82-
instancesLock.withLock {
78+
cachedInstances.withLock { cachedInstances in
8379
if let cachedInstance = cachedInstances[id]?.object {
8480
return cachedInstance
8581
} else {
@@ -110,8 +106,8 @@ final class HeartbeatStorage: Sendable, HeartbeatStorageProtocol {
110106

111107
deinit {
112108
// Removes the instance if it was cached.
113-
_ = Self.instancesLock.withLock {
114-
Self.cachedInstances.removeValue(forKey: id)
109+
Self.cachedInstances.withLock { value in
110+
value.removeValue(forKey: id)
115111
}
116112
}
117113

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import Foundation
16+
17+
final class AtomicBox<T> {
18+
private var _value: T
19+
private let lock = NSLock()
20+
21+
public init(_ value: T) {
22+
_value = value
23+
}
24+
25+
public func value() -> T {
26+
lock.withLock {
27+
_value
28+
}
29+
}
30+
31+
@discardableResult
32+
public func withLock(_ mutatingBody: (_ value: inout T) -> Void) -> T {
33+
lock.withLock {
34+
mutatingBody(&_value)
35+
return _value
36+
}
37+
}
38+
39+
@discardableResult
40+
public func withLock<R>(_ mutatingBody: (_ value: inout T) throws -> R) rethrows -> R {
41+
try lock.withLock {
42+
try mutatingBody(&_value)
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)