Skip to content
This repository has been archived by the owner on Aug 29, 2022. It is now read-only.

Move to Swift 4 minimum #200

Merged
merged 5 commits into from
Feb 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
disabled_rules:
- block_based_kvo
- nesting
- todo
opt_in_rules:
- empty_count
- vertical_whitespace
line_length: 220
type_name:
excluded: My
2 changes: 1 addition & 1 deletion Configurations/Base.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,4 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
CLANG_ANALYZER_NONNULL = YES

// Swift Compiler - Version
SWIFT_VERSION = 3.0
SWIFT_VERSION = 4.0
3 changes: 3 additions & 0 deletions Configurations/Framework.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@ PRODUCT_NAME = Deferred

// Swift Compiler - Custom Flags
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) XCODE

// Swift Compiler - General
SWIFT_INSTALL_OBJC_HEADER = NO
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
enableThreadSanitizer = "YES"
codeCoverageEnabled = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
enableThreadSanitizer = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
enableThreadSanitizer = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
Expand Down
36 changes: 22 additions & 14 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// swift-tools-version:4.0

//
// Package.swift
// Deferred
Expand All @@ -10,18 +12,24 @@ import PackageDescription

let package = Package(
name: "Deferred",
products: [
.library(name: "Deferred", type: .dynamic, targets: [ "Deferred", "Task" ])
],
targets: [
Target(name: "Atomics"),
Target(name: "Deferred", dependencies: [
.Target(name: "Atomics")
]),
Target(name: "Task", dependencies: [
.Target(name: "Deferred")
])
], exclude: [
"Tests/AllTestsCommon.swift"
]
)

let dylib = Product(name: "Deferred", type: .Library(.Dynamic), modules: "Deferred", "Task")
products.append(dylib)
.target(name: "Atomics"),
.target(
name: "Deferred",
dependencies: [ "Atomics" ]),
.testTarget(
name: "DeferredTests",
dependencies: [ "Deferred" ],
exclude: [ "Tests/AllTestsCommon.swift" ]),
.target(
name: "Task",
dependencies: [ "Deferred" ]),
.testTarget(
name: "TaskTests",
dependencies: [ "Deferred", "Task" ],
exclude: [ "Tests/AllTestsCommon.swift" ])
],
swiftLanguageVersions: [ 4 ])
80 changes: 35 additions & 45 deletions Sources/Deferred/Deferred.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import Dispatch

#if SWIFT_PACKAGE
import Atomics
import Atomics
#elseif XCODE
import Deferred.Atomics
import Deferred.Atomics
#endif

/// A deferred is a value that may become determined (or "filled") at some point
Expand Down Expand Up @@ -40,7 +40,7 @@ public final class Deferred<Value>: FutureProtocol, PromiseProtocol {
/// Creates an instance resolved with `value`.
public init(filledWith value: Value) {
storage.withUnsafeMutablePointerToElements { (pointerToElement) in
pointerToElement.initialize(to: Storage.box(value))
pointerToElement.initialize(to: Storage.convertToReference(value))
}
}

Expand All @@ -55,7 +55,8 @@ public final class Deferred<Value>: FutureProtocol, PromiseProtocol {
private func notify(flags: DispatchWorkItemFlags, upon queue: DispatchQueue, execute body: @escaping(Value) -> Void) {
group.notify(flags: flags, queue: queue) { [storage] in
guard let ptr = storage.withAtomicPointerToElement({ bnr_atomic_ptr_load($0, .none) }) else { return }
body(Storage.unbox(from: ptr))
let reference = Unmanaged<AnyObject>.fromOpaque(ptr).takeUnretainedValue()
body(Storage.convertFromReference(reference))
}
}

Expand All @@ -81,7 +82,8 @@ public final class Deferred<Value>: FutureProtocol, PromiseProtocol {
guard case .success = group.wait(timeout: time),
let ptr = storage.withAtomicPointerToElement({ bnr_atomic_ptr_load($0, .none) }) else { return nil }

return Storage.unbox(from: ptr)
let reference = Unmanaged<AnyObject>.fromOpaque(ptr).takeUnretainedValue()
return Storage.convertFromReference(reference)
}

// MARK: PromiseProtocol
Expand All @@ -94,7 +96,7 @@ public final class Deferred<Value>: FutureProtocol, PromiseProtocol {

@discardableResult
public func fill(with value: Value) -> Bool {
let box = Storage.box(value)
let box = Unmanaged.passRetained(Storage.convertToReference(value))

let wonRace = storage.withAtomicPointerToElement {
bnr_atomic_ptr_compare_and_swap($0, nil, box.toOpaque(), .thread)
Expand All @@ -110,29 +112,12 @@ public final class Deferred<Value>: FutureProtocol, PromiseProtocol {
}
}

#if swift(>=3.1) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS))
private typealias DeferredRaw<T> = Unmanaged<AnyObject>
#else
// In order to assign the value of a scalar in a Deferred using atomics, we must
// box it up into something word-sized. See `atomicInitialize` above.
private final class Box<T> {
let contents: T
private final class DeferredStorage<Value>: ManagedBuffer<Void, AnyObject?> {

init(_ contents: T) {
self.contents = contents
}
}

private typealias DeferredRaw<T> = Unmanaged<Box<T>>
#endif
private typealias My = DeferredStorage<Value>

private final class DeferredStorage<Value>: ManagedBuffer<Void, DeferredRaw<Value>?> {

typealias _Self = DeferredStorage<Value>
typealias Element = DeferredRaw<Value>

static func create() -> _Self {
return unsafeDowncast(super.create(minimumCapacity: 1, makingHeaderWith: { _ in }), to: _Self.self)
static func create() -> DeferredStorage<Value> {
return unsafeDowncast(super.create(minimumCapacity: 1, makingHeaderWith: { _ in }), to: My.self)
}

func withAtomicPointerToElement<Return>(_ body: (UnsafeMutablePointer<UnsafeAtomicRawPointer>) throws -> Return) rethrows -> Return {
Expand All @@ -141,28 +126,33 @@ private final class DeferredStorage<Value>: ManagedBuffer<Void, DeferredRaw<Valu
}
}

deinit {
guard let ptr = withAtomicPointerToElement({ bnr_atomic_ptr_load($0, .global) }) else { return }
Element.fromOpaque(ptr).release()
}

static func unbox(from ptr: UnsafeMutableRawPointer) -> Value {
let raw = Element.fromOpaque(ptr)
#if swift(>=3.1) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS))
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
static func convertFromReference(_ value: AnyObject) -> Value {
// Contract of using box(_:) counterpart
// swiftlint:disable:next force_cast
return raw.takeUnretainedValue() as! Value
#else
return raw.takeUnretainedValue().contents
#endif
return value as! Value
}

static func convertToReference(_ value: Value) -> AnyObject {
return value as AnyObject
}
#else
// In order to assign the value in a Deferred using atomics, we must
// box it up into something word-sized. See `fill(with:)` above.
private final class Box {
let wrapped: Value
init(_ wrapped: Value) {
self.wrapped = wrapped
}
}

static func convertToReference(_ value: Value) -> AnyObject {
return Box(value)
}

static func box(_ value: Value) -> Element {
#if swift(>=3.1) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS))
return Unmanaged.passRetained(value as AnyObject)
#else
return Unmanaged.passRetained(Box(value))
#endif
static func convertFromReference(_ value: AnyObject) -> Value {
return unsafeDowncast(value, to: Box.self).wrapped
}
#endif

}
6 changes: 3 additions & 3 deletions Sources/Deferred/Executor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Dispatch
import Foundation
#if !os(macOS) && !os(iOS) && !os(tvOS) && !os(watchOS)
import CoreFoundation
import CoreFoundation
#endif

/// An executor calls closures submitted to it, typically in first-in, first-out
Expand Down Expand Up @@ -127,9 +127,9 @@ extension OperationQueue: Executor {
extension CFRunLoop: Executor {
@nonobjc public func submit(_ body: @escaping() -> Void) {
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
CFRunLoopPerformBlock(self, CFRunLoopMode.defaultMode.rawValue, body)
CFRunLoopPerformBlock(self, CFRunLoopMode.defaultMode.rawValue, body)
#else
CFRunLoopPerformBlock(self, kCFRunLoopDefaultMode, body)
CFRunLoopPerformBlock(self, kCFRunLoopDefaultMode, body)
#endif
CFRunLoopWakeUp(self)
}
Expand Down
5 changes: 1 addition & 4 deletions Sources/Deferred/FutureComposition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Dispatch

// swiftlint:disable force_cast
// swiftlint:disable function_parameter_count
// swiftlint:disable large_tuple
// swiftlint:disable line_length
// We darn well know what unholiness we are pulling

Expand Down Expand Up @@ -123,7 +124,3 @@ extension FutureProtocol {
}
}
}

// swiftlint:enable line_length
// swiftlint:enable function_parameter_count
// swiftlint:enable force_cast
Loading