Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Latest commit

 

History

History
History
129 lines (117 loc) · 3.88 KB

File metadata and controls

129 lines (117 loc) · 3.88 KB
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#if arch(wasm32)
#if canImport(wasi_pthread)
import wasi_pthread
#endif
#elseif canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#else
#error("Unsupported platform")
#endif
/// A property wrapper that provides thread-local storage for a value.
///
/// The value is stored in a thread-local variable, which is a separate copy for each thread.
@propertyWrapper
final class ThreadLocal<Value>: Sendable {
#if compiler(>=6.1) && _runtime(_multithreaded)
/// The wrapped value stored in the thread-local storage.
/// The initial value is `nil` for each thread.
var wrappedValue: Value? {
get {
guard let pointer = pthread_getspecific(key) else {
return nil
}
return fromPointer(pointer)
}
set {
if let oldPointer = pthread_getspecific(key) {
release(oldPointer)
}
if let newValue = newValue {
let pointer = toPointer(newValue)
pthread_setspecific(key, pointer)
}
}
}
private let key: pthread_key_t
private let toPointer: @Sendable (Value) -> UnsafeMutableRawPointer
private let fromPointer: @Sendable (UnsafeMutableRawPointer) -> Value
private let release: @Sendable (UnsafeMutableRawPointer) -> Void
/// A constructor that requires `Value` to be `AnyObject` to be
/// able to store the value directly in the thread-local storage.
init() where Value: AnyObject {
var key = pthread_key_t()
pthread_key_create(&key, nil)
self.key = key
self.toPointer = { Unmanaged.passRetained($0).toOpaque() }
self.fromPointer = { Unmanaged<Value>.fromOpaque($0).takeUnretainedValue() }
self.release = { Unmanaged<Value>.fromOpaque($0).release() }
}
private class Box {
let value: Value
init(_ value: Value) {
self.value = value
}
}
/// A constructor that doesn't require `Value` to be `AnyObject` but
/// boxing the value in heap-allocated memory.
init(boxing _: Void) {
var key = pthread_key_t()
pthread_key_create(&key, nil)
self.key = key
self.toPointer = {
let box = Box($0)
let pointer = Unmanaged.passRetained(box).toOpaque()
return pointer
}
self.fromPointer = {
let box = Unmanaged<Box>.fromOpaque($0).takeUnretainedValue()
return box.value
}
self.release = { Unmanaged<Box>.fromOpaque($0).release() }
}
#else
// Fallback implementation for platforms that don't support pthread
private class SendableBox: @unchecked Sendable {
var value: Value? = nil
}
private let _storage = SendableBox()
var wrappedValue: Value? {
get { _storage.value }
set { _storage.value = newValue }
}
init() where Value: AnyObject {
wrappedValue = nil
}
init(boxing _: Void) {
wrappedValue = nil
}
#endif
deinit {
preconditionFailure("ThreadLocal can only be used as an immortal storage, cannot be deallocated")
}
}
/// A property wrapper that lazily initializes a thread-local value
/// for each thread that accesses the value.
@propertyWrapper
final class LazyThreadLocal<Value>: Sendable {
private let storage: ThreadLocal<Value>
var wrappedValue: Value {
if let value = storage.wrappedValue {
return value
}
let value = initialValue()
storage.wrappedValue = value
return value
}
private let initialValue: @Sendable () -> Value
init(initialize: @Sendable @escaping () -> Value) where Value: AnyObject {
self.storage = ThreadLocal()
self.initialValue = initialize
}
init(initialize: @Sendable @escaping () -> Value) {
self.storage = ThreadLocal(boxing: ())
self.initialValue = initialize
}
}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.