Skip to content

Commit

Permalink
Add Atomic Dictionary generic capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
minuscorp committed Dec 23, 2021
1 parent 2efabc3 commit b8ea513
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 140 deletions.
147 changes: 147 additions & 0 deletions fastlane/swift/Atomic.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Atomic.swift
// Copyright (c) 2021 FastlaneTools

import Foundation

protocol DictionaryProtocol: class {
associatedtype Key: Hashable
associatedtype Value

init()

subscript(_: Key) -> Value? { get set }

@discardableResult
func removeValue(forKey key: Key) -> Value?

func get(_ key: Key) -> Value?
func set(_ key: Key, value: Value?)
}

extension DictionaryProtocol {
subscript(_ key: Key) -> Value? {
get {
get(key)
}
set {
set(key, value: newValue)
}
}
}

protocol SyncProtocol: DictionaryProtocol {
func lock()
func unlock()
func sync<T>(_ work: () throws -> T) rethrows -> T
}

extension SyncProtocol {
func sync<T>(_ work: () throws -> T) rethrows -> T {
lock()
defer { unlock() }
return try work()
}
}

protocol LockProtocol: SyncProtocol {
associatedtype Lock

var _lock: Lock { get set }
}

@available(macOS, introduced: 10.12)
extension LockProtocol where Lock == UnsafeMutablePointer<os_unfair_lock> {
func lock() {
os_unfair_lock_lock(_lock)
}

func unlock() {
os_unfair_lock_unlock(_lock)
}
}

@available(macOS, deprecated: 10.12)
extension LockProtocol where Lock == OSSpinLock {
func lock() {
OSSpinLockLock(&_lock)
}

func unlock() {
OSSpinLockUnlock(&_lock)
}
}

protocol AnyLock {}

@available(macOS, deprecated: 10.12)
extension OSSpinLock: AnyLock {
static func make() -> Self {
OS_SPINLOCK_INIT
}
}

@available(macOS, introduced: 10.12)
extension UnsafeMutablePointer: AnyLock where Pointee == os_unfair_lock {
static func make() -> Self {
let unfairLock = UnsafeMutablePointer<os_unfair_lock>.allocate(capacity: 1)
unfairLock.initialize(to: os_unfair_lock())
return unfairLock
}
}

// MARK: - Classes

class AtomicDictionary<Key: Hashable, Value>: LockProtocol {
typealias Lock = AnyLock

var _lock: Lock = {
if #available(macOS 10.12, *) {
return UnsafeMutablePointer<os_unfair_lock>.make()
} else {
return OSSpinLock.make()
}
}()

private var storage: [Key: Value] = [:]

required init() {}

@discardableResult
func removeValue(forKey key: Key) -> Value? {
sync {
storage.removeValue(forKey: key)
}
}

func get(_ key: Key) -> Value? {
sync {
storage[key]
}
}

func set(_ key: Key, value: Value?) {
sync {
storage[key] = value
}
}

func lock() {}

func unlock() {}
}

@available(macOS, deprecated: 10.12)
class OSSPinAtomicDictionary<Key: Hashable, Value>: AtomicDictionary<Key, Value> {
override func lock() {}
override func unlock() {}
}

@available(macOS, introduced: 10.12)
class UnfairAtomicDictionary<Key: Hashable, Value>: AtomicDictionary<Key, Value> {
override func lock() {}
override func unlock() {}

deinit {
(_lock as? UnsafeMutablePointer<os_unfair_lock>)?.deallocate()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
0311E387230AC1B20060BB5C /* Plugins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0311E386230AC1B20060BB5C /* Plugins.swift */; };
0311E38B230AC9490060BB5C /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0311E38A230AC9490060BB5C /* Actions.swift */; };
1257253924B7992C00E04FA3 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1257253824B7992B00E04FA3 /* main.swift */; };
1267C3F42773A43E004DE48A /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1267C3F32773A43E004DE48A /* Atomic.swift */; };
12D2EB8D2620D83C00844013 /* OptionalConfigValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D2EB8C2620D83B00844013 /* OptionalConfigValue.swift */; };
B302067B1F5E3E9000DE6EBD /* SnapshotfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206741F5E3E9000DE6EBD /* SnapshotfileProtocol.swift */; };
B302067C1F5E3E9000DE6EBD /* GymfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206751F5E3E9000DE6EBD /* GymfileProtocol.swift */; };
Expand Down Expand Up @@ -58,6 +59,7 @@
0311E386230AC1B20060BB5C /* Plugins.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Plugins.swift; path = ../Plugins.swift; sourceTree = "<group>"; };
0311E38A230AC9490060BB5C /* Actions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Actions.swift; path = ../Actions.swift; sourceTree = "<group>"; };
1257253824B7992B00E04FA3 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../main.swift; sourceTree = "<group>"; };
1267C3F32773A43E004DE48A /* Atomic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Atomic.swift; path = ../Atomic.swift; sourceTree = "<group>"; };
12D2EB8C2620D83B00844013 /* OptionalConfigValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OptionalConfigValue.swift; path = ../OptionalConfigValue.swift; sourceTree = "<group>"; };
B30206741F5E3E9000DE6EBD /* SnapshotfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SnapshotfileProtocol.swift; path = ../SnapshotfileProtocol.swift; sourceTree = "<group>"; };
B30206751F5E3E9000DE6EBD /* GymfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GymfileProtocol.swift; path = ../GymfileProtocol.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -135,6 +137,7 @@
B3BA65B11F5A325E00B34850 /* Networking */ = {
isa = PBXGroup;
children = (
1267C3F32773A43E004DE48A /* Atomic.swift */,
B3144C072005533400470AFE /* README.txt */,
D5B8A5B21FFDC49D00536B24 /* ControlCommand.swift */,
B3BA65A01F5A269100B34850 /* RubyCommand.swift */,
Expand Down Expand Up @@ -250,6 +253,7 @@
D5D1DE991FFEE8EA00502A00 /* RubyCommandable.swift in Sources */,
D55B28C41F6C588300DC42C5 /* Gymfile.swift in Sources */,
B302067D1F5E3E9000DE6EBD /* MatchfileProtocol.swift in Sources */,
1267C3F42773A43E004DE48A /* Atomic.swift in Sources */,
B3BA65AC1F5A269100B34850 /* SocketClientDelegateProtocol.swift in Sources */,
B3BA65A71F5A269100B34850 /* LaneFileProtocol.swift in Sources */,
D55B28C61F6C588300DC42C5 /* Precheckfile.swift in Sources */,
Expand Down
129 changes: 7 additions & 122 deletions fastlane/swift/Runner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,141 +10,26 @@

import Foundation

let logger: Logger = {
Logger()
}()
let logger: Logger = .init()

let runner: Runner = {
Runner()
}()
let runner: Runner = .init()

func desc(_: String) {
// no-op, this is handled in fastlane/lane_list.rb
}

protocol AtomicDictionaryProtocol: class {
subscript(_ key: String) -> Bool? { get set }
@discardableResult
func removeValue(forKey key: String) -> Bool?
}

@available(macOS, introduced: 10.12)
class UnfairLockAtomicDictionary<Key: Hashable, Value> {

private var unfairLock: UnsafeMutablePointer<os_unfair_lock>
private var storage: [Key: Value]

init() {
unfairLock = UnsafeMutablePointer<os_unfair_lock>.allocate(capacity: 1)
unfairLock.initialize(to: os_unfair_lock())
storage = [:]
}

deinit {
unfairLock.deallocate()
}

subscript(_ key: Key) -> Value? {
get {
get(key)
}
set(newValue) {
set(key, value: newValue)
}
}

private func get(_ key: Key) -> Value? {
os_unfair_lock_lock(unfairLock)
defer { os_unfair_lock_unlock(unfairLock) }
return storage[key]
}

private func set(_ key: Key, value: Value?) {
os_unfair_lock_lock(unfairLock)
defer { os_unfair_lock_unlock(unfairLock) }
storage[key] = value
}

@discardableResult
func removeValue(forKey key: Key) -> Value? {
os_unfair_lock_lock(unfairLock)
defer { os_unfair_lock_unlock(unfairLock) }
return storage.removeValue(forKey: key)
}
}

@available(macOS, introduced: 10.12)
class UnfairLockAtomicDictionaryStringBool: UnfairLockAtomicDictionary<String, Bool> {
}

@available(macOS, introduced: 10.12)
extension UnfairLockAtomicDictionaryStringBool: AtomicDictionaryProtocol {
}

@available(macOS, deprecated: 10.12)
class OSSpinLockAtomicDictionary<Key: Hashable, Value> {

private var spinLock = OS_SPINLOCK_INIT
private var storage: [Key: Value]

init() {
storage = [:]
}

deinit {
}

subscript(_ key: Key) -> Value? {
get {
get(key)
}
set(newValue) {
set(key, value: newValue)
}
}

private func get(_ key: Key) -> Value? {
OSSpinLockLock(&spinLock)
defer { OSSpinLockUnlock(&spinLock) }
return storage[key]
}

private func set(_ key: Key, value: Value?) {
OSSpinLockLock(&spinLock)
defer { OSSpinLockUnlock(&spinLock) }
storage[key] = value
}

@discardableResult
func removeValue(forKey key: Key) -> Value? {
OSSpinLockLock(&spinLock)
defer { OSSpinLockUnlock(&spinLock) }
return storage.removeValue(forKey: key)
}
}

@available(macOS, deprecated: 10.12)
class OSSpinLockAtomicDictionaryStringBool: OSSpinLockAtomicDictionary<String, Bool> {
}

@available(macOS, deprecated: 10.12)
extension OSSpinLockAtomicDictionaryStringBool: AtomicDictionaryProtocol {

}

class Runner {
private var thread: Thread!
private var socketClient: SocketClient!
private let dispatchGroup = DispatchGroup()
private var returnValue: String? // lol, so safe
private var currentlyExecutingCommand: RubyCommandable?
private var shouldLeaveDispatchGroupDuringDisconnect = false
private var executeNext: AtomicDictionaryProtocol = {
private var executeNext: AtomicDictionary<String, Bool> = {
if #available(macOS 10.12, *) {
return UnfairLockAtomicDictionaryStringBool()
}
else {
return OSSpinLockAtomicDictionaryStringBool()
return UnfairAtomicDictionary<String, Bool>()
} else {
return OSSPinAtomicDictionary<String, Bool>()
}
}()

Expand Down Expand Up @@ -188,7 +73,7 @@ class Runner {

let runLoop = RunLoop.current
let timeoutDate = Date(timeInterval: TimeInterval(timeout), since: Date())
var fulfilled: Bool = false
var fulfilled = false
let _expression = memoizedClosure(expression)
repeat {
do {
Expand Down
Loading

0 comments on commit b8ea513

Please sign in to comment.