mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
366 lines
15 KiB
Swift
366 lines
15 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift Atomics open source project
|
|
//
|
|
// Copyright (c) 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
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// A type that supports atomic operations through a separate atomic storage
|
|
/// representation.
|
|
///
|
|
/// Types that conform to the `AtomicRepresentable` protocol can be used as the
|
|
/// `Value` type parameter with the `Atomic` type. Conformances that utilize
|
|
/// existing atomic storage representations as their own representation will get
|
|
/// the primitive atomic operations available on `Atomic` for free. Such
|
|
/// operations include `load`, `store`, `exchange`, `compareExchange`, and
|
|
/// `weakCompareExchange`.
|
|
///
|
|
/// Conforming to the AtomicRepresentable protocol
|
|
/// --------------------------------------
|
|
///
|
|
/// Conforming your own custom types allow them to be used in the `Atomic` type
|
|
/// and get access to all of the primitive atomic operations explained above.
|
|
/// There are two main ways to conform your type to `AtomicRepresentable`:
|
|
///
|
|
/// 1. Using a predefined `RawRepresentable` conformance
|
|
/// 2. Manually conforming to `AtomicRepresentable`
|
|
///
|
|
/// If you custom type already conforms to `RawRepresentable`, then adding the
|
|
/// `AtomicRepresentable` conformance may be really simple! If the `RawValue`
|
|
/// associated type of your type is already itself an `AtomicRepresentable`,
|
|
/// then all you need to do is add the conformance and you're done!
|
|
///
|
|
/// enum TrafficLight: UInt8 {
|
|
/// case red
|
|
/// case yellow
|
|
/// case green
|
|
/// }
|
|
///
|
|
/// extension TrafficLight: AtomicRepresentable {}
|
|
///
|
|
/// And that's it! Here, we're utilizing Swift's automatic `RawRepresentable`
|
|
/// conformance synthesis for enums by declaring our "raw value" to be a
|
|
/// `UInt8`. By adding the `AtomicRepresentable` conformance, we automatically
|
|
/// figure out how to do the conformance from the `RawRepresentable`
|
|
/// implementation and do all of the necessary work for you. However, it is still
|
|
/// possible to customize this behavior using the manual method explained below.
|
|
///
|
|
/// Defining your own `AtomicRepresentable` conformance is pretty simple. All
|
|
/// you have to do is decide what atomic storage representation fits best for
|
|
/// your type, and create the bidirectional relationship between the two.
|
|
///
|
|
/// // A point in an x-y coordinate system.
|
|
/// struct GridPoint {
|
|
/// var x: Int
|
|
/// var y: Int
|
|
/// }
|
|
///
|
|
/// extension GridPoint: AtomicRepresentable {
|
|
/// typealias AtomicRepresentation = WordPair.AtomicRepresentation
|
|
///
|
|
/// static func encodeAtomicRepresentation(
|
|
/// _ value: consuming GridPoint
|
|
/// ) -> AtomicRepresentation {
|
|
/// let wordPair = WordPair(
|
|
/// first: UInt(bitPattern: value.x),
|
|
/// second: UInt(bitPattern: value.y)
|
|
/// )
|
|
///
|
|
/// return WordPair.encodeAtomicRepresentation(wordPair)
|
|
/// }
|
|
///
|
|
/// static func decodeAtomicRepresentation(
|
|
/// _ representation: consuming AtomicRepresentation
|
|
/// ) -> GridPoint {
|
|
/// let wordPair = WordPair.decodeAtomicRepresentation(representation)
|
|
///
|
|
/// return GridPoint(
|
|
/// x: Int(bitPattern: wordPair.first),
|
|
/// y: Int(bitPattern: wordPair.second)
|
|
/// )
|
|
/// }
|
|
/// }
|
|
///
|
|
/// Here, we're going to select `WordPair`'s atomic storage representation as
|
|
/// our own. This is very important because we only get the atomic operations
|
|
/// like `load` and `store` if our representation is one of the _fundamental_
|
|
/// storage representations. Luckily for us, `WordPair` does use one of these
|
|
/// types as its storage type.
|
|
///
|
|
/// In addition to selecting what storage representation our type will use, we
|
|
/// define two static functions that go from both our custom type to its
|
|
/// representation and the representation back to our own type. Because our
|
|
/// representation is the same as `WordPair.AtomicRepresentation`, we will
|
|
/// actually go through `WordPair`'s `AtomicRepresentable` conformance to help
|
|
/// define our own.
|
|
///
|
|
/// This is all you need to do to conform your custom type to the
|
|
/// `AtomicRepresentable` protocol. From here, you can use this type in all of
|
|
/// the primitive atomic operations like shown below:
|
|
///
|
|
/// func atomicGridPoint(_ gridPoint: Atomic<GridPoint>) {
|
|
/// let newGridPoint = GridPoint(x: 123, y: -456)
|
|
///
|
|
/// let oldGridPoint1 = gridPoint.load(ordering: .relaxed)
|
|
///
|
|
/// gridPoint.store(newGridPoint, ordering: .releasing)
|
|
///
|
|
/// let oldGridPoint2 = gridPoint.exchange(
|
|
/// desired: oldGridPoint1,
|
|
/// ordering: .acquiringAndReleasing
|
|
/// )
|
|
///
|
|
/// let (exchanged1, oldGridPoint2) = gridPoint.compareExchange(
|
|
/// expected: oldGridPoint1,
|
|
/// desired: newGridPoint,
|
|
/// ordering: .sequentiallyConsistent
|
|
/// )
|
|
///
|
|
/// let (exchanged2, oldGridPoint3) = gridPoint.weakCompareExchange(
|
|
/// expected: newGridPoint,
|
|
/// desired: oldGridPoint2,
|
|
/// ordering: .relaxed
|
|
/// )
|
|
/// }
|
|
///
|
|
/// List of Fundamental Atomic Representations
|
|
/// ------------------------------------------
|
|
///
|
|
/// When defining your own `AtomicRepresentable` conformance, it is critical
|
|
/// that your custom type should choose from the following list of types as its
|
|
/// own `AtomicRepresentation`:
|
|
///
|
|
/// - `UInt8.AtomicRepresentation`
|
|
/// - `UInt16.AtomicRepresentation`
|
|
/// - `UInt32.AtomicRepresentation`
|
|
/// - `UInt64.AtomicRepresentation`
|
|
/// - `UInt.AtomicRepresentation`
|
|
/// - `Int8.AtomicRepresentation`
|
|
/// - `Int16.AtomicRepresentation`
|
|
/// - `Int32.AtomicRepresentation`
|
|
/// - `Int64.AtomicRepresentation`
|
|
/// - `Int.AtomicRepresentation`
|
|
/// - `WordPair.AtomicRepresentation`
|
|
///
|
|
/// - Note: `Int8.AtomicRepresentation` is the same type as
|
|
/// `UInt8.AtomicRepresentation` and the same is true for all of the same
|
|
/// sized integer types. If your type wraps an unsigned integer, you should
|
|
/// prefer to use an unsigned integer's atomic representation instead of a
|
|
/// signed ones and vice versa. `Int` and `UInt`'s representation will be
|
|
/// 64 bits wide on 64 bit systems and 32 bit wide on 32 bit systems. `Int64`
|
|
/// and `UInt64` always conform to `AtomicRepresentable` on 64 bit systems,
|
|
/// but on 32 bit systems they will only conform if the platform supports
|
|
/// double wide atomics. `WordPair` will only conform to `AtomicRepresentable`
|
|
/// on platforms that support double wide atomics, but if they do it will be
|
|
/// 128 bits wide on 64 bit systems and 64 bits wide on 32 bit systems.
|
|
///
|
|
@available(SwiftStdlib 6.0, *)
|
|
public protocol AtomicRepresentable {
|
|
/// The storage representation type that `Self` encodes to and decodes from
|
|
/// which is a suitable type when used in atomic operations.
|
|
associatedtype AtomicRepresentation: BitwiseCopyable
|
|
|
|
/// Destroys a value of `Self` and prepares an `AtomicRepresentation` storage
|
|
/// type to be used for atomic operations.
|
|
///
|
|
/// - Note: This is not an atomic operation. This simply encodes the logical
|
|
/// type `Self` into its storage representation suitable for atomic
|
|
/// operations, `AtomicRepresentation`.
|
|
///
|
|
/// - Parameter value: A valid instance of `Self` that's about to be destroyed
|
|
/// to encode an instance of its `AtomicRepresentation`.
|
|
/// - Returns: The newly encoded `AtomicRepresentation` storage.
|
|
static func encodeAtomicRepresentation(
|
|
_ value: consuming Self
|
|
) -> AtomicRepresentation
|
|
|
|
/// Recovers the logical atomic type `Self` by destroying some
|
|
/// `AtomicRepresentation` storage instance returned from an atomic operation.
|
|
///
|
|
/// - Note: This is not an atomic operation. This simply decodes the storage
|
|
/// representation used in atomic operations back into the logical type for
|
|
/// normal use, `Self`.
|
|
///
|
|
/// - Parameter storage: The storage representation for `Self` that's used
|
|
/// within atomic operations.
|
|
/// - Returns: The newly decoded logical type `Self`.
|
|
static func decodeAtomicRepresentation(
|
|
_ storage: consuming AtomicRepresentation
|
|
) -> Self
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// RawRepresentable AtomicRepresentable conformance
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@available(SwiftStdlib 6.0, *)
|
|
extension RawRepresentable
|
|
where
|
|
Self: AtomicRepresentable,
|
|
RawValue: AtomicRepresentable
|
|
{
|
|
/// The storage representation type that `Self` encodes to and decodes from
|
|
/// which is a suitable type when used in atomic operations.
|
|
@available(SwiftStdlib 6.0, *)
|
|
public typealias AtomicRepresentation = RawValue.AtomicRepresentation
|
|
|
|
|
|
/// Destroys a value of `Self` and prepares an `AtomicRepresentation` storage
|
|
/// type to be used for atomic operations.
|
|
///
|
|
/// - Note: This is not an atomic operation. This simply encodes the logical
|
|
/// type `Self` into its storage representation suitable for atomic
|
|
/// operations, `AtomicRepresentation`.
|
|
///
|
|
/// - Parameter value: A valid instance of `Self` that's about to be destroyed
|
|
/// to encode an instance of its `AtomicRepresentation`.
|
|
/// - Returns: The newly encoded `AtomicRepresentation` storage.
|
|
@available(SwiftStdlib 6.0, *)
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
public static func encodeAtomicRepresentation(
|
|
_ value: consuming Self
|
|
) -> RawValue.AtomicRepresentation {
|
|
RawValue.encodeAtomicRepresentation(value.rawValue)
|
|
}
|
|
|
|
|
|
/// Recovers the logical atomic type `Self` by destroying some
|
|
/// `AtomicRepresentation` storage instance returned from an atomic operation.
|
|
///
|
|
/// - Note: This is not an atomic operation. This simply decodes the storage
|
|
/// representation used in atomic operations back into the logical type for
|
|
/// normal use, `Self`.
|
|
///
|
|
/// - Parameter storage: The storage representation for `Self` that's used
|
|
/// within atomic operations.
|
|
/// - Returns: The newly decoded logical type `Self`.
|
|
@available(SwiftStdlib 6.0, *)
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
public static func decodeAtomicRepresentation(
|
|
_ representation: consuming RawValue.AtomicRepresentation
|
|
) -> Self {
|
|
Self(rawValue: RawValue.decodeAtomicRepresentation(representation))!
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Never AtomicRepresentable conformance
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@available(SwiftStdlib 6.0, *)
|
|
extension Never: AtomicRepresentable {
|
|
/// The storage representation type that `Self` encodes to and decodes from
|
|
/// which is a suitable type when used in atomic operations.
|
|
@available(SwiftStdlib 6.0, *)
|
|
public typealias AtomicRepresentation = Never
|
|
|
|
|
|
/// Destroys a value of `Self` and prepares an `AtomicRepresentation` storage
|
|
/// type to be used for atomic operations.
|
|
///
|
|
/// - Note: This is not an atomic operation. This simply encodes the logical
|
|
/// type `Self` into its storage representation suitable for atomic
|
|
/// operations, `AtomicRepresentation`.
|
|
///
|
|
/// - Parameter value: A valid instance of `Self` that's about to be destroyed
|
|
/// to encode an instance of its `AtomicRepresentation`.
|
|
/// - Returns: The newly encoded `AtomicRepresentation` storage.
|
|
@available(SwiftStdlib 6.0, *)
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
public static func encodeAtomicRepresentation(
|
|
_ value: consuming Never
|
|
) -> Never {}
|
|
|
|
|
|
/// Recovers the logical atomic type `Self` by destroying some
|
|
/// `AtomicRepresentation` storage instance returned from an atomic operation.
|
|
///
|
|
/// - Note: This is not an atomic operation. This simply decodes the storage
|
|
/// representation used in atomic operations back into the logical type for
|
|
/// normal use, `Self`.
|
|
///
|
|
/// - Parameter storage: The storage representation for `Self` that's used
|
|
/// within atomic operations.
|
|
/// - Returns: The newly decoded logical type `Self`.
|
|
@available(SwiftStdlib 6.0, *)
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
public static func decodeAtomicRepresentation(
|
|
_ representation: consuming Never
|
|
) -> Never {}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Duration AtomicRepresentable conformance
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#if _pointerBitWidth(_64) && _hasAtomicBitWidth(_128)
|
|
|
|
@available(SwiftStdlib 6.0, *)
|
|
extension Duration: AtomicRepresentable {
|
|
/// The storage representation type that `Self` encodes to and decodes from
|
|
/// which is a suitable type when used in atomic operations.
|
|
@available(SwiftStdlib 6.0, *)
|
|
public typealias AtomicRepresentation = WordPair.AtomicRepresentation
|
|
|
|
|
|
/// Destroys a value of `Self` and prepares an `AtomicRepresentation` storage
|
|
/// type to be used for atomic operations.
|
|
///
|
|
/// - Note: This is not an atomic operation. This simply encodes the logical
|
|
/// type `Self` into its storage representation suitable for atomic
|
|
/// operations, `AtomicRepresentation`.
|
|
///
|
|
/// - Parameter value: A valid instance of `Self` that's about to be destroyed
|
|
/// to encode an instance of its `AtomicRepresentation`.
|
|
/// - Returns: The newly encoded `AtomicRepresentation` storage.
|
|
@available(SwiftStdlib 6.0, *)
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
public static func encodeAtomicRepresentation(
|
|
_ value: consuming Duration
|
|
) -> AtomicRepresentation {
|
|
WordPair.encodeAtomicRepresentation(
|
|
WordPair(
|
|
first: UInt(truncatingIfNeeded: value._high),
|
|
second: UInt(truncatingIfNeeded: value._low)
|
|
)
|
|
)
|
|
}
|
|
|
|
|
|
/// Recovers the logical atomic type `Self` by destroying some
|
|
/// `AtomicRepresentation` storage instance returned from an atomic operation.
|
|
///
|
|
/// - Note: This is not an atomic operation. This simply decodes the storage
|
|
/// representation used in atomic operations back into the logical type for
|
|
/// normal use, `Self`.
|
|
///
|
|
/// - Parameter storage: The storage representation for `Self` that's used
|
|
/// within atomic operations.
|
|
/// - Returns: The newly decoded logical type `Self`.
|
|
@available(SwiftStdlib 6.0, *)
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
public static func decodeAtomicRepresentation(
|
|
_ representation: consuming AtomicRepresentation
|
|
) -> Duration {
|
|
let wp = WordPair.decodeAtomicRepresentation(representation)
|
|
|
|
return Duration(
|
|
_high: Int64(truncatingIfNeeded: wp.first),
|
|
low: UInt64(truncatingIfNeeded: wp.second)
|
|
)
|
|
}
|
|
}
|
|
|
|
#endif
|