Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the Regex type Sendable #457

Merged
merged 8 commits into from
Jun 1, 2022
Merged
Show file tree
Hide file tree
Changes from 6 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
12 changes: 11 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,19 @@ let package = Package(
.target(
name: "_CUnicode",
dependencies: []),
.target(
name: "_LazyAtomicShims",
dependencies: []),
.target(
name: "_LazyAtomic",
dependencies: ["_LazyAtomicShims"]),
natecook1000 marked this conversation as resolved.
Show resolved Hide resolved
.target(
name: "_StringProcessing",
dependencies: ["_RegexParser", "_CUnicode"],
dependencies: [
"_RegexParser",
"_CUnicode",
"_LazyAtomic",
],
swiftSettings: publicStdlibSettings),
.target(
name: "RegexBuilder",
Expand Down
69 changes: 69 additions & 0 deletions Sources/_LazyAtomic/Int.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022 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
//
//===----------------------------------------------------------------------===//

// THIS FILE IS PART OF A SUBSET OF https://github.com/apple/swift-atomics/

import _LazyAtomicShims

extension Int {
@frozen
public struct AtomicRepresentation {
public typealias Value = Int

@usableFromInline
var _storage: _AtomicIntStorage

@inline(__always) @_alwaysEmitIntoClient
public init(_ value: Value) {
self._storage = _sa_prepare_Int(value)
}

@inline(__always) @_alwaysEmitIntoClient
public func dispose() -> Value {
return _sa_dispose_Int(_storage)
}
}
}

extension UnsafeMutablePointer
where Pointee == Int.AtomicRepresentation {
@inlinable @inline(__always)
internal var _extract: UnsafeMutablePointer<_AtomicIntStorage> {
// `Int` is layout-compatible with its only stored property.
return UnsafeMutableRawPointer(self)
.assumingMemoryBound(to: _AtomicIntStorage.self)
}
}

extension Int.AtomicRepresentation {
@_semantics("atomics.requires_constant_orderings")
@_transparent @_alwaysEmitIntoClient
public static func atomicLoad(
at pointer: UnsafeMutablePointer<Self>
) -> Value {
_sa_load_acquire_Int(pointer._extract)
}

@_semantics("atomics.requires_constant_orderings")
@_transparent @_alwaysEmitIntoClient
public static func atomicCompareExchange(
expected: Value,
desired: Value,
at pointer: UnsafeMutablePointer<Self>
) -> (exchanged: Bool, original: Value) {
var expected = expected
let exchanged: Bool
exchanged = _sa_cmpxchg_strong_acq_rel_acquire_Int(
pointer._extract,
&expected, desired)
return (exchanged, expected)
}
}
84 changes: 84 additions & 0 deletions Sources/_LazyAtomic/Unmanaged.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022 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
//
//===----------------------------------------------------------------------===//

// THIS FILE IS PART OF A SUBSET OF https://github.com/apple/swift-atomics/

extension Unmanaged {
@frozen
public struct AtomicOptionalRepresentation {
public typealias Value = Unmanaged?
@usableFromInline internal typealias Storage = Int.AtomicRepresentation

@usableFromInline
internal let _storage: Storage

@inline(__always) @_alwaysEmitIntoClient
public init(_ value: Value) {
self._storage = .init(Self._encode(value))
}

@inline(__always) @_alwaysEmitIntoClient
public func dispose() -> Value {
Self._decode(_storage.dispose())
}
}
}

extension Unmanaged.AtomicOptionalRepresentation {
@_transparent @_alwaysEmitIntoClient
@usableFromInline
internal static func _extract(
_ ptr: UnsafeMutablePointer<Self>
) -> UnsafeMutablePointer<Storage> {
// `Self` is layout-compatible with its only stored property.
return UnsafeMutableRawPointer(ptr)
.assumingMemoryBound(to: Storage.self)
}

@_transparent @_alwaysEmitIntoClient
internal static func _decode(_ bitPattern: Int) -> Value {
guard let opaque = UnsafeRawPointer(bitPattern: bitPattern) else {
return nil
}
return Unmanaged.fromOpaque(opaque)
}

@_transparent @_alwaysEmitIntoClient
internal static func _encode(_ value: Value) -> Int {
guard let value = value else { return 0 }
return Int(bitPattern: value.toOpaque())
}
}

extension Unmanaged.AtomicOptionalRepresentation {
@_semantics("atomics.requires_constant_orderings")
@_transparent @_alwaysEmitIntoClient
public static func atomicLoad(
at pointer: UnsafeMutablePointer<Self>
) -> Value {
let encoded = Storage.atomicLoad(at: _extract(pointer))
return _decode(encoded)
}

@_semantics("atomics.requires_constant_orderings")
@_transparent @_alwaysEmitIntoClient
public static func atomicCompareExchange(
expected: Value,
desired: Value,
at pointer: UnsafeMutablePointer<Self>
) -> (exchanged: Bool, original: Value) {
let (exchanged, original) = Storage.atomicCompareExchange(
expected: _encode(expected),
desired: _encode(desired),
at: _extract(pointer))
return (exchanged, _decode(original))
}
}
95 changes: 95 additions & 0 deletions Sources/_LazyAtomic/UnsafeAtomicLazyReference.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022 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
//
//===----------------------------------------------------------------------===//

// THIS FILE IS PART OF A SUBSET OF https://github.com/apple/swift-atomics/

@frozen
public struct UnsafeAtomicLazyReference<Instance: AnyObject> {
public typealias Value = Instance?

@usableFromInline
internal typealias _Rep = Unmanaged<Instance>.AtomicOptionalRepresentation

@usableFromInline
internal let _ptr: UnsafeMutablePointer<_Rep>

@_transparent // Debug performance
public init(@_nonEphemeral at pointer: UnsafeMutablePointer<Storage>) {
// `Storage` is layout-compatible with its only stored property.
_ptr = UnsafeMutableRawPointer(pointer).assumingMemoryBound(to: _Rep.self)
}
}

#if compiler(>=5.5) && canImport(_Concurrency)
extension UnsafeAtomicLazyReference: @unchecked Sendable
where Instance: Sendable {}
#endif

extension UnsafeAtomicLazyReference {
@frozen
public struct Storage {
@usableFromInline
internal var _storage: _Rep

@inlinable @inline(__always)
public init() {
_storage = _Rep(nil)
}

@inlinable @inline(__always)
@discardableResult
public mutating func dispose() -> Value {
defer { _storage = _Rep(nil) }
return _storage.dispose()?.takeRetainedValue()
}
}
}

extension UnsafeAtomicLazyReference {
@inlinable
public static func create() -> Self {
let ptr = UnsafeMutablePointer<Storage>.allocate(capacity: 1)
ptr.initialize(to: Storage())
return Self(at: ptr)
}

@discardableResult
@inlinable
public func destroy() -> Value {
// `Storage` is layout-compatible with its only stored property.
let address = UnsafeMutableRawPointer(_ptr)
.assumingMemoryBound(to: Storage.self)
defer { address.deallocate() }
return address.pointee.dispose()
}
}

extension UnsafeAtomicLazyReference {
public func storeIfNilThenLoad(_ desired: __owned Instance) -> Instance {
let desiredUnmanaged = Unmanaged.passRetained(desired)
let (exchanged, current) = _Rep.atomicCompareExchange(
expected: nil,
desired: desiredUnmanaged,
at: _ptr)
if !exchanged {
// The reference has already been initialized. Balance the retain that
// we performed on `desired`.
desiredUnmanaged.release()
return current!.takeUnretainedValue()
}
return desiredUnmanaged.takeUnretainedValue()
}

public func load() -> Instance? {
let value = _Rep.atomicLoad(at: _ptr)
return value?.takeUnretainedValue()
}
}
12 changes: 12 additions & 0 deletions Sources/_LazyAtomicShims/_LazyAtomicShims.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022 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
//
//===----------------------------------------------------------------------===//

#include "include/_LazyAtomicShims.h"
98 changes: 98 additions & 0 deletions Sources/_LazyAtomicShims/include/_LazyAtomicShims.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022 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
//
//===----------------------------------------------------------------------===//

// THIS FILE IS PART OF A SUBSET OF https://github.com/apple/swift-atomics/

#ifndef SWIFT_STDLIB_SHIMS_LAZYATOMIC_H
#define SWIFT_STDLIB_SHIMS_LAZYATOMIC_H

#include <stdbool.h>
#include <stdint.h>
#include <assert.h>
// The atomic primitives are only needed when this is compiled using Swift's
// Clang Importer. This allows us to continue reling on some Clang extensions
// (see https://github.com/apple/swift-atomics/issues/37).
#if defined(__swift__)
# include <stdatomic.h>
#endif

#if defined(__swift__)

#define SWIFTATOMIC_INLINE static inline __attribute__((__always_inline__))
#define SWIFTATOMIC_SWIFT_NAME(name) __attribute__((swift_name(#name)))

// Definition of an atomic storage type.
#define SWIFTATOMIC_STORAGE_TYPE(swiftType, cType, storageType) \
typedef struct { \
_Atomic(storageType) value; \
} _sa_##swiftType \
SWIFTATOMIC_SWIFT_NAME(_Atomic##swiftType##Storage);

// Storage value initializer
#define SWIFTATOMIC_PREPARE_FN(swiftType, cType, storageType) \
SWIFTATOMIC_INLINE \
_sa_##swiftType _sa_prepare_##swiftType(cType value) \
{ \
_sa_##swiftType storage = { SWIFTATOMIC_ENCODE_##swiftType(value) }; \
assert(atomic_is_lock_free(&storage.value)); \
return storage; \
}

// Storage value disposal function
#define SWIFTATOMIC_DISPOSE_FN(swiftType, cType, storageType) \
SWIFTATOMIC_INLINE \
cType _sa_dispose_##swiftType(_sa_##swiftType storage) \
{ \
return SWIFTATOMIC_DECODE_##swiftType(storage.value); \
}

// Atomic load
#define SWIFTATOMIC_LOAD_FN(swiftType, cType, storageType, order) \
SWIFTATOMIC_INLINE \
cType _sa_load_##order##_##swiftType( \
_sa_##swiftType *ptr) \
{ \
return SWIFTATOMIC_DECODE_##swiftType( \
atomic_load_explicit(&ptr->value, \
memory_order_##order)); \
}

// Atomic compare/exchange
#define SWIFTATOMIC_CMPXCHG_FN_SIMPLE(_kind, swiftType, cType, storageType, succ, fail) \
SWIFTATOMIC_INLINE \
bool \
_sa_cmpxchg_##_kind##_##succ##_##fail##_##swiftType( \
_sa_##swiftType *ptr, \
cType *expected, \
cType desired) \
{ \
return atomic_compare_exchange_##_kind##_explicit( \
&ptr->value, \
expected, \
desired, \
memory_order_##succ, \
memory_order_##fail); \
}

#define SWIFTATOMIC_DEFINE_TYPE(variant, swiftType, cType, storageType) \
SWIFTATOMIC_STORAGE_TYPE(swiftType, cType, storageType) \
SWIFTATOMIC_PREPARE_FN(swiftType, cType, storageType) \
SWIFTATOMIC_DISPOSE_FN(swiftType, cType, storageType) \
SWIFTATOMIC_LOAD_FN(swiftType, cType, storageType, acquire) \
SWIFTATOMIC_CMPXCHG_FN_##variant(strong, swiftType, cType, storageType, acq_rel, acquire)

#define SWIFTATOMIC_ENCODE_Int(value) (value)
#define SWIFTATOMIC_DECODE_Int(value) (value)
SWIFTATOMIC_DEFINE_TYPE(SIMPLE, Int, intptr_t, intptr_t)

#endif // __swift__

#endif // SWIFT_STDLIB_SHIMS_LAZYATOMIC_H
Loading