1010//
1111//===----------------------------------------------------------------------===//
1212
13- // #############################################################################
14- // # #
15- // # DO NOT EDIT THIS FILE; IT IS AUTOGENERATED. #
16- // # #
17- // #############################################################################
13+ /// A lazily initializable atomic strong reference.
14+ ///
15+ /// These values can be set (initialized) exactly once, but read many
16+ /// times.
17+ @frozen
18+ public struct AtomicLazyReference < Instance: AnyObject > : ~ Copyable {
19+ /// The value logically stored in an atomic lazy reference value.
20+ public typealias Value = Instance ?
21+
22+ @usableFromInline
23+ internal let _storage : Atomic < Unmanaged < Instance > ? >
24+
25+ /// Initializes a new managed atomic lazy reference with a nil value.
26+ @inlinable
27+ public init ( ) {
28+ _storage = Atomic ( nil )
29+ }
30+
31+ @inlinable
32+ deinit {
33+ if let unmanaged = _storage. load ( ordering: . acquiring) {
34+ unmanaged. release ( )
35+ }
36+ }
37+ }
38+
39+ extension AtomicLazyReference {
40+ /// Atomically initializes this reference if its current value is nil, then
41+ /// returns the initialized value. If this reference is already initialized,
42+ /// then `storeIfNilThenLoad(_:)` discards its supplied argument and returns
43+ /// the current value without updating it.
44+ ///
45+ /// The following example demonstrates how this can be used to implement a
46+ /// thread-safe lazily initialized reference:
47+ ///
48+ /// ```
49+ /// class Image {
50+ /// var _histogram: UnsafeAtomicLazyReference<Histogram> = .init()
51+ ///
52+ /// // This is safe to call concurrently from multiple threads.
53+ /// var atomicLazyHistogram: Histogram {
54+ /// if let histogram = _histogram.load() { return histogram }
55+ /// // Note that code here may run concurrently on
56+ /// // multiple threads, but only one of them will get to
57+ /// // succeed setting the reference.
58+ /// let histogram = ...
59+ /// return _histogram.storeIfNilThenLoad(histogram)
60+ /// }
61+ /// ```
62+ ///
63+ /// This operation uses acquiring-and-releasing memory ordering.
64+ public func storeIfNilThenLoad( _ desired: __owned Instance) -> Instance {
65+ let desiredUnmanaged = Unmanaged . passRetained ( desired)
66+ let ( exchanged, current) = _storage. compareExchange (
67+ expected: nil ,
68+ desired: desiredUnmanaged,
69+ ordering: . acquiringAndReleasing)
70+ if !exchanged {
71+ // The reference has already been initialized. Balance the retain that
72+ // we performed on `desired`.
73+ desiredUnmanaged. release ( )
74+ return current!. takeUnretainedValue ( )
75+ }
76+ return desiredUnmanaged. takeUnretainedValue ( )
77+ }
1878
79+ /// Atomically loads and returns the current value of this reference.
80+ ///
81+ /// The load operation is performed with the memory ordering
82+ /// `AtomicLoadOrdering.acquiring`.
83+ public func load( ) -> Instance ? {
84+ let value = _storage. load ( ordering: . acquiring)
85+ return value? . takeUnretainedValue ( )
86+ }
87+ }
1988
2089/// An unsafe reference type holding a lazily initializable atomic
2190/// strong reference, requiring manual memory management of the
@@ -125,47 +194,6 @@ extension UnsafeAtomicLazyReference {
125194 }
126195}
127196
128- /// A reference type holding a lazily initializable atomic
129- /// strong reference, with automatic memory management.
130- ///
131- /// These values can be set (initialized) exactly once, but read many
132- /// times.
133- @_fixed_layout
134- public class ManagedAtomicLazyReference < Instance: AnyObject > {
135- /// The value logically stored in an atomic lazy reference value.
136- public typealias Value = Instance ?
137-
138- @usableFromInline
139- internal typealias _Rep = Optional < Unmanaged < Instance > > . AtomicRepresentation
140-
141- /// The atomic representation of the value stored inside.
142- ///
143- /// Warning: This ivar must only ever be accessed via `_ptr` after
144- /// its initialization.
145- @usableFromInline
146- internal let _storage : _Rep
147-
148- /// Initializes a new managed atomic lazy reference with a nil value.
149- @inlinable
150- public init ( ) {
151- _storage = _Rep ( nil )
152- }
153-
154- deinit {
155- if let unmanaged = _ptr. pointee. dispose ( ) {
156- unmanaged. release ( )
157- }
158- }
159-
160- @_alwaysEmitIntoClient @inline ( __always)
161- internal var _ptr : UnsafeMutablePointer < _Rep > {
162- _getUnsafePointerToStoredProperties ( self ) . assumingMemoryBound ( to: _Rep. self)
163- }
164- }
165-
166- extension ManagedAtomicLazyReference : @unchecked Sendable
167- where Instance: Sendable { }
168-
169197extension UnsafeAtomicLazyReference {
170198 /// Atomically initializes this reference if its current value is nil, then
171199 /// returns the initialized value. If this reference is already initialized,
@@ -194,10 +222,10 @@ extension UnsafeAtomicLazyReference {
194222 public func storeIfNilThenLoad( _ desired: __owned Instance) -> Instance {
195223 let desiredUnmanaged = Unmanaged . passRetained ( desired)
196224 let ( exchanged, current) = _Rep. atomicCompareExchange (
197- expected: nil ,
198- desired: desiredUnmanaged,
199- at: _ptr,
200- ordering: . acquiringAndReleasing)
225+ expected: nil ,
226+ desired: desiredUnmanaged,
227+ at: _ptr,
228+ ordering: . acquiringAndReleasing)
201229 if !exchanged {
202230 // The reference has already been initialized. Balance the retain that
203231 // we performed on `desired`.
@@ -216,6 +244,34 @@ extension UnsafeAtomicLazyReference {
216244 return value? . takeUnretainedValue ( )
217245 }
218246}
247+
248+ /// A reference type holding a lazily initializable atomic
249+ /// strong reference, with automatic memory management.
250+ ///
251+ /// These values can be set (initialized) exactly once, but read many
252+ /// times.
253+ @_fixed_layout
254+ public class ManagedAtomicLazyReference < Instance: AnyObject > {
255+ /// The value logically stored in an atomic lazy reference value.
256+ public typealias Value = Instance ?
257+
258+ /// The actual lazily initialized reference value.
259+ @usableFromInline
260+ internal let _storage : AtomicLazyReference < Instance >
261+
262+ /// Initializes a new managed atomic lazy reference with a nil value.
263+ @inlinable
264+ public init ( ) {
265+ _storage = AtomicLazyReference ( )
266+ }
267+
268+ deinit {
269+ }
270+ }
271+
272+ extension ManagedAtomicLazyReference : @unchecked Sendable
273+ where Instance: Sendable { }
274+
219275extension ManagedAtomicLazyReference {
220276 /// Atomically initializes this reference if its current value is nil, then
221277 /// returns the initialized value. If this reference is already initialized,
@@ -242,27 +298,14 @@ extension ManagedAtomicLazyReference {
242298 ///
243299 /// This operation uses acquiring-and-releasing memory ordering.
244300 public func storeIfNilThenLoad( _ desired: __owned Instance) -> Instance {
245- let desiredUnmanaged = Unmanaged . passRetained ( desired)
246- let ( exchanged, current) = _Rep. atomicCompareExchange (
247- expected: nil ,
248- desired: desiredUnmanaged,
249- at: _ptr,
250- ordering: . acquiringAndReleasing)
251- if !exchanged {
252- // The reference has already been initialized. Balance the retain that
253- // we performed on `desired`.
254- desiredUnmanaged. release ( )
255- return current!. takeUnretainedValue ( )
256- }
257- return desiredUnmanaged. takeUnretainedValue ( )
301+ _storage. storeIfNilThenLoad ( desired)
258302 }
259303
260304 /// Atomically loads and returns the current value of this reference.
261305 ///
262306 /// The load operation is performed with the memory ordering
263307 /// `AtomicLoadOrdering.acquiring`.
264308 public func load( ) -> Instance ? {
265- let value = _Rep. atomicLoad ( at: _ptr, ordering: . acquiring)
266- return value? . takeUnretainedValue ( )
309+ _storage. load ( )
267310 }
268311}
0 commit comments