Skip to content

Commit

Permalink
Replace AtomicValue._AtomicValue with AtomicReference._AtomicBase
Browse files Browse the repository at this point in the history
  • Loading branch information
lorentey committed Mar 18, 2023
1 parent cc86c55 commit 263c074
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 75 deletions.
7 changes: 5 additions & 2 deletions Sources/Atomics/AtomicInteger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift Atomics open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Copyright (c) 2020-2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand All @@ -21,7 +21,10 @@
/// exchange operation; however, this depends on the capabilities of
/// the compiler and the underlying hardware.
public protocol AtomicInteger: AtomicValue, FixedWidthInteger
where AtomicRepresentation: AtomicIntegerStorage {}
where
AtomicRepresentation: AtomicIntegerStorage,
AtomicRepresentation.Value == Self
{}

/// The storage representation for an atomic integer value, providing
/// pointer-based atomic operations.
Expand Down
6 changes: 3 additions & 3 deletions Sources/Atomics/AtomicOptional.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift Atomics open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Copyright (c) 2020-2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand All @@ -17,10 +17,10 @@
public protocol AtomicOptionalWrappable: AtomicValue {
/// The atomic storage representation for `Optional<Self>`.
associatedtype AtomicOptionalRepresentation: AtomicStorage
where AtomicOptionalRepresentation.Value == _AtomicValue?
where AtomicOptionalRepresentation.Value == AtomicRepresentation.Value?
}

extension Optional: AtomicValue
where Wrapped: AtomicOptionalWrappable, Wrapped._AtomicValue == Wrapped {
where Wrapped: AtomicOptionalWrappable, Wrapped.AtomicRepresentation.Value == Wrapped {
public typealias AtomicRepresentation = Wrapped.AtomicOptionalRepresentation
}
6 changes: 3 additions & 3 deletions Sources/Atomics/AtomicRawRepresentable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift Atomics open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Copyright (c) 2020-2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand All @@ -14,7 +14,7 @@ extension RawRepresentable
where
Self: AtomicValue,
RawValue: AtomicValue,
RawValue._AtomicValue == RawValue
RawValue.AtomicRepresentation.Value == RawValue
{
public typealias _AtomicValue = Self
public typealias AtomicRepresentation = AtomicRawRepresentableStorage<Self>
Expand All @@ -27,7 +27,7 @@ public struct AtomicRawRepresentableStorage<Value>: AtomicStorage
where
Value: RawRepresentable,
Value.RawValue: AtomicValue,
Value.RawValue._AtomicValue == Value.RawValue
Value.RawValue.AtomicRepresentation.Value == Value.RawValue
{
@usableFromInline internal typealias Storage = Value.RawValue.AtomicRepresentation
@usableFromInline
Expand Down
58 changes: 52 additions & 6 deletions Sources/Atomics/AtomicStrongReference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift Atomics open source project
//
// Copyright (c) 2020-2021 Apple Inc. and the Swift project authors
// Copyright (c) 2020-2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand All @@ -13,12 +13,59 @@
import _AtomicsShims

/// A class type that supports atomic strong references.
///
/// class MyObject: AtomicReference {}
///
/// let object = MyObject()
/// let ref = ManagedAtomic<MyObject>(object)
///
/// ref.load(ordering: .relaxed) // Returns `object`.
///
/// The conforming class is allowed to be non-final, but `ManagedAtomic` and
/// `UnsafeAtomic` do not support using a subclass as their generic argument --
/// the type of an atomic reference must be precisely the same class that
/// originally conformed to the protocol.
///
///
/// class Derived: MyObject {}
///
/// let ref2: ManagedAtomic<Derived>
/// // error: 'ManagedAtomic' requires the types 'Derived' and 'Base' be equivalent
///
/// Note that this limitation only affects the static type of the
/// `ManagedAtomic`/`UnsafeAtomic` variables. Such references still fully
/// support holding instances of subclasses of the conforming class. (Returned
/// may be downcasted from the base type after an `is` check.)
///
/// let child = Derived()
/// ref.store(child, ordering: .relaxed) // OK!
/// let value = ref.load(ordering: .relaxed)
/// // `value` is a variable of type `MyObject`, holding a `Derived` instance.
/// print(value is Derived) // Prints "true"
///
public protocol AtomicReference: AnyObject, AtomicOptionalWrappable
where
_AtomicValue: AnyObject,
AtomicRepresentation == AtomicReferenceStorage<_AtomicValue>,
AtomicOptionalRepresentation == AtomicOptionalReferenceStorage<_AtomicValue>
AtomicRepresentation == AtomicReferenceStorage<_AtomicBase>,
AtomicOptionalRepresentation == AtomicOptionalReferenceStorage<_AtomicBase>
{
/// This is a utility type that enables non-final classes to conform to
/// `AtomicReference`.
///
/// This associated type must be left at its default value, `Self`.
/// `ManagedAtomic` et al. currently require that `Self == _AtomicBase`,
/// so conformances that set this to anything else will technically build,
/// but they will not be very practical.
///
/// Ideally we could just require that `Self` should be a subtype of
/// `AtomicRepresentation.Value`; however we have no good way to
/// express that requirement.
///
/// protocol AtomicValue where Self: AtomicRepresentation.Value {
/// associatedtype AtomicRepresentation: AtomicStorage
/// }
///
/// See https://github.com/apple/swift-atomics/issues/53 for more details.
associatedtype _AtomicBase: AnyObject = Self
}

/// The maximum number of other threads that can start accessing a
Expand All @@ -40,8 +87,7 @@ extension Unmanaged {
extension Unmanaged {
fileprivate static func passRetained(_ instance: __owned Instance?) -> Self? {
guard let instance = instance else { return nil }
// Note: Swift 5.2 doesn't like this optional promotion without the explicit cast
return .passRetained(instance) as Self
return .passRetained(instance)
}
}

Expand Down
5 changes: 2 additions & 3 deletions Sources/Atomics/AtomicValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift Atomics open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Copyright (c) 2020-2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand All @@ -13,10 +13,9 @@
/// A type that supports atomic operations through a separate atomic storage
/// representation.
public protocol AtomicValue {
associatedtype _AtomicValue = Self
/// The atomic storage representation for this value.
associatedtype AtomicRepresentation: AtomicStorage
where AtomicRepresentation.Value == _AtomicValue
/* where Self is a subtype of AtomicRepresentation.Value */
}

/// The storage representation for an atomic value, providing pointer-based
Expand Down
48 changes: 32 additions & 16 deletions Sources/Atomics/HighLevelTypes.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,15 @@ ${autogenerated_warning()}
/// management of the underlying storage representation.
@frozen
public struct UnsafeAtomic<Value: AtomicValue>
where Value._AtomicValue == Value {
where Value.AtomicRepresentation.Value == Value {
// Note: the Value._AtomicValue == Value requirement could be relaxed,
// at the cost of adding a bunch of potentially ambiguous overloads.
// (We'd need one set of implementations for `Value == Value._AtomicValue`,
// and another for `Value: AtomicReference`.)

public typealias Storage = Value.AtomicRepresentation
@usableFromInline
internal typealias _Storage = Storage

@usableFromInline
internal let _ptr: UnsafeMutablePointer<Storage>
Expand Down Expand Up @@ -77,25 +84,33 @@ extension UnsafeAtomic: @unchecked Sendable where Value: Sendable {}
/// A reference type holding an atomic value, with automatic memory management.
@_fixed_layout
public class ManagedAtomic<Value: AtomicValue>
where Value._AtomicValue == Value {
where Value.AtomicRepresentation.Value == Value {
// Note: the Value._AtomicValue == Value requirement could be relaxed,
// at the cost of adding a bunch of potentially ambiguous overloads.
// (We'd need one set of implementations for `Value == Value._AtomicValue`,
// and another for `Value: AtomicReference`.)

@usableFromInline
internal typealias _Storage = Value.AtomicRepresentation

@usableFromInline
internal var _storage: Value.AtomicRepresentation
internal var _storage: _Storage

/// Initialize a new managed atomic instance holding the specified initial
/// value.
@inline(__always) @_alwaysEmitIntoClient
public init(_ value: Value) {
_storage = Value.AtomicRepresentation(value)
_storage = _Storage(value)
}

deinit {
_ = _storage.dispose()
}

@_alwaysEmitIntoClient @inline(__always)
internal var _ptr: UnsafeMutablePointer<Value.AtomicRepresentation> {
internal var _ptr: UnsafeMutablePointer<_Storage> {
_getUnsafePointerToStoredProperties(self)
.assumingMemoryBound(to: Value.AtomicRepresentation.self)
.assumingMemoryBound(to: _Storage.self)
}
}

Expand All @@ -113,7 +128,7 @@ extension ${type} {
public func load(
ordering: AtomicLoadOrdering
) -> Value {
Value.AtomicRepresentation.atomicLoad(at: _ptr, ordering: ordering)
_Storage.atomicLoad(at: _ptr, ordering: ordering)
}

/// Atomically sets the current value to `desired`, applying the specified
Expand All @@ -127,7 +142,7 @@ extension ${type} {
_ desired: __owned Value,
ordering: AtomicStoreOrdering
) {
Value.AtomicRepresentation.atomicStore(desired, at: _ptr, ordering: ordering)
_Storage.atomicStore(desired, at: _ptr, ordering: ordering)
}

/// Atomically sets the current value to `desired` and returns the original
Expand All @@ -142,7 +157,7 @@ extension ${type} {
_ desired: __owned Value,
ordering: AtomicUpdateOrdering
) -> Value {
Value.AtomicRepresentation.atomicExchange(desired, at: _ptr, ordering: ordering)
_Storage.atomicExchange(desired, at: _ptr, ordering: ordering)
}

/// Perform an atomic compare and exchange operation on the current value,
Expand Down Expand Up @@ -175,7 +190,7 @@ extension ${type} {
desired: __owned Value,
ordering: AtomicUpdateOrdering
) -> (exchanged: Bool, original: Value) {
Value.AtomicRepresentation.atomicCompareExchange(
_Storage.atomicCompareExchange(
expected: expected,
desired: desired,
at: _ptr,
Expand Down Expand Up @@ -220,7 +235,7 @@ extension ${type} {
successOrdering: AtomicUpdateOrdering,
failureOrdering: AtomicLoadOrdering
) -> (exchanged: Bool, original: Value) {
Value.AtomicRepresentation.atomicCompareExchange(
_Storage.atomicCompareExchange(
expected: expected,
desired: desired,
at: _ptr,
Expand Down Expand Up @@ -269,7 +284,7 @@ extension ${type} {
successOrdering: AtomicUpdateOrdering,
failureOrdering: AtomicLoadOrdering
) -> (exchanged: Bool, original: Value) {
Value.AtomicRepresentation.atomicWeakCompareExchange(
_Storage.atomicWeakCompareExchange(
expected: expected,
desired: desired,
at: _ptr,
Expand Down Expand Up @@ -297,7 +312,7 @@ extension ${type} where Value: AtomicInteger {
${label} operand: Value${" = 1" if "crement" in name else ""},
ordering: AtomicUpdateOrdering
) -> Value {
Value.AtomicRepresentation.atomicLoadThen${name}(
_Storage.atomicLoadThen${name}(
${argLabel(label)}operand,
at: _ptr,
ordering: ordering)
Expand All @@ -322,7 +337,7 @@ extension ${type} where Value: AtomicInteger {
${label} operand: Value${" = 1" if "crement" in name else ""},
ordering: AtomicUpdateOrdering
) -> Value {
let original = Value.AtomicRepresentation.atomicLoadThen${name}(
let original = _Storage.atomicLoadThen${name}(
${argLabel(label)}operand,
at: _ptr,
ordering: ordering)
Expand All @@ -344,7 +359,7 @@ extension ${type} where Value: AtomicInteger {
by operand: Value = 1,
ordering: AtomicUpdateOrdering
) {
_ = Value.AtomicRepresentation.atomicLoadThenWrappingIncrement(
_ = _Storage.atomicLoadThenWrappingIncrement(
by: operand,
at: _ptr,
ordering: ordering)
Expand All @@ -364,9 +379,10 @@ extension ${type} where Value: AtomicInteger {
by operand: Value = 1,
ordering: AtomicUpdateOrdering
) {
_ = Value.AtomicRepresentation.atomicLoadThenWrappingDecrement(
_ = _Storage.atomicLoadThenWrappingDecrement(
by: operand,
at: _ptr,
ordering: ordering)
}
}
%end
Loading

0 comments on commit 263c074

Please sign in to comment.