Created
March 16, 2023 17:41
-
-
Save adam-zethraeus/52f815a820d9129aa56e72e69271255c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public struct Locked<T>: LockedValue { | |
public init(_ value: T) { | |
let lock = Self.make(for: value) | |
withLock = { act in | |
lock.lock() | |
defer { lock.unlock() } | |
return act(&lock.unsafe_wrapped) | |
} | |
} | |
private let withLock: ((inout T) -> Any) -> Any | |
public func take<aT>(_ act: (inout T) -> aT) -> aT { | |
withLock(act) as! aT | |
} | |
} | |
extension Locked { | |
@inline(__always) | |
fileprivate static func make(for value: T) -> some LockType<T> { | |
#if canImport(os) | |
if #available(iOS 16, macOS 13, *) { | |
return OSUnfairLocked(value) | |
} else { | |
return NSLocked(value) | |
} | |
#elseif canImport(Foundation) | |
return NSLocked(value) | |
#else | |
return PThreadLock(value) | |
#endif | |
} | |
} | |
private protocol LockedValue<T> { | |
associatedtype T | |
@discardableResult | |
init(_:T) | |
func take<aT>(_: (inout T) -> aT) -> aT | |
} | |
private protocol LockType<T>: AnyObject { | |
associatedtype T | |
@inline(__always) | |
func lock() | |
@inline(__always) | |
func unlock() | |
var unsafe_wrapped: T { get set } | |
} | |
#if canImport(Foundation) | |
import Foundation | |
private final class NSLocked<T>: LockType { | |
fileprivate var unsafe_wrapped: T | |
private let nslock = NSLock() | |
fileprivate init(_ value: T) { | |
self.unsafe_wrapped = value | |
} | |
@inline(__always) | |
fileprivate func lock() { | |
nslock.lock() | |
} | |
@inline(__always) | |
fileprivate func unlock() { | |
nslock.unlock() | |
} | |
} | |
#endif | |
#if canImport(os) | |
import os | |
@available(iOS 16, macOS 13, *) | |
private final class OSUnfairLocked<T>: LockType { | |
private let oslock: OSAllocatedUnfairLock<()> | |
fileprivate var unsafe_wrapped: T | |
fileprivate init(_ value: T) { | |
oslock = .init(initialState: ()) | |
unsafe_wrapped = value | |
} | |
@inline(__always) | |
fileprivate func lock() { | |
oslock.lock() | |
} | |
@inline(__always) | |
fileprivate func unlock() { | |
oslock.unlock() | |
} | |
} | |
#endif | |
private final class PThreadLock<T>: LockType { | |
private var mutex = pthread_mutex_t() | |
fileprivate var unsafe_wrapped: T | |
fileprivate init(_ value: T) { | |
unsafe_wrapped = value | |
} | |
@inline(__always) | |
fileprivate func lock() { | |
pthread_mutex_lock(&mutex) | |
} | |
@inline(__always) | |
fileprivate func unlock() { | |
pthread_mutex_unlock(&mutex) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment