Skip to content

Commit

Permalink
_CollectionsUtilities: Use gyb to allow defining these helpers as int…
Browse files Browse the repository at this point in the history
…ernal or public depending on COLLECTIONS_SINGLE_MODULE

This is a thoroughly disgusting solution, but needs must. 😞

Hopefully macros will let us eventually replace this mess.
  • Loading branch information
lorentey committed Mar 23, 2023
1 parent 688dbdf commit c287334
Show file tree
Hide file tree
Showing 32 changed files with 4,276 additions and 136 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2021 Apple Inc. and the Swift project authors
// Copyright (c) 2021 - 2023 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
//
//===----------------------------------------------------------------------===//

%{
from gyb_utils import *
}%
${autogenerated_warning()}

extension Array {
/// Returns true if `Array.withContiguousStorageIfAvailable` is broken
/// in the stdlib we're currently running on.
Expand Down Expand Up @@ -53,11 +58,13 @@ extension Array {
}
}

% for modifier in visibility_levels:
${visibility_boilerplate(modifier)}
extension Sequence {
// An adjusted version of the standard `withContiguousStorageIfAvailable`
// method that works around https://bugs.swift.org/browse/SR-14663.
@inlinable @inline(__always)
public func _withContiguousStorageIfAvailable_SR14663<R>(
${modifier} func _withContiguousStorageIfAvailable_SR14663<R>(
_ body: (UnsafeBufferPointer<Element>) throws -> R
) rethrows -> R? {
if Self.self == Array<Element>.self && Array<Element>._isWCSIABroken() {
Expand All @@ -67,3 +74,5 @@ extension Sequence {
return try self.withContiguousStorageIfAvailable(body)
}
}
% end
${visibility_boilerplate("end")}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2022-2023 Apple Inc. and the Swift project authors
// Copyright (c) 2022 - 2023 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
Expand All @@ -11,6 +11,13 @@

// Note: These are adapted from SE-0370 in the Swift 5.8 Standard Library.

%{
from gyb_utils import *
}%
${autogenerated_warning()}

% for modifier in visibility_levels:
${visibility_boilerplate(modifier)}
#if swift(<5.8)
extension UnsafeMutableBufferPointer {
/// Deinitializes every instance in this buffer.
Expand All @@ -25,7 +32,7 @@ extension UnsafeMutableBufferPointer {
/// The range of memory is still bound to `Element`.
@discardableResult
@inlinable
public func deinitialize() -> UnsafeMutableRawBufferPointer {
${modifier} func deinitialize() -> UnsafeMutableRawBufferPointer {
guard let start = baseAddress else { return .init(start: nil, count: 0) }
start.deinitialize(count: count)
return .init(start: UnsafeMutableRawPointer(start),
Expand Down Expand Up @@ -63,7 +70,7 @@ extension UnsafeMutableBufferPointer {
/// - Returns: The index one past the last element of the buffer initialized
/// by this function.
@inlinable
public func initialize<C: Collection>(
${modifier} func initialize<C: Collection>(
fromContentsOf source: C
) -> Index
where C.Element == Element {
Expand Down Expand Up @@ -123,7 +130,7 @@ extension UnsafeMutableBufferPointer {
/// by this function.
@inlinable
@_alwaysEmitIntoClient
public func moveInitialize(fromContentsOf source: Self) -> Index {
${modifier} func moveInitialize(fromContentsOf source: Self) -> Index {
guard let sourceAddress = source.baseAddress, !source.isEmpty else {
return startIndex
}
Expand Down Expand Up @@ -165,7 +172,7 @@ extension UnsafeMutableBufferPointer {
/// by this function.
@inlinable
@_alwaysEmitIntoClient
public func moveInitialize(fromContentsOf source: Slice<Self>) -> Index {
${modifier} func moveInitialize(fromContentsOf source: Slice<Self>) -> Index {
return moveInitialize(fromContentsOf: Self(rebasing: source))
}

Expand All @@ -180,7 +187,7 @@ extension UnsafeMutableBufferPointer {
/// - index: The index of the element to initialize
@inlinable
@_alwaysEmitIntoClient
public func initializeElement(at index: Index, to value: Element) {
${modifier} func initializeElement(at index: Index, to value: Element) {
assert(startIndex <= index && index < endIndex)
let p = baseAddress.unsafelyUnwrapped.advanced(by: index)
p.initialize(to: value)
Expand All @@ -198,7 +205,7 @@ extension UnsafeMutableBufferPointer {
/// - Returns: The instance referenced by this index in this buffer.
@inlinable
@_alwaysEmitIntoClient
public func moveElement(from index: Index) -> Element {
${modifier} func moveElement(from index: Index) -> Element {
assert(startIndex <= index && index < endIndex)
return baseAddress.unsafelyUnwrapped.advanced(by: index).move()
}
Expand All @@ -213,7 +220,7 @@ extension UnsafeMutableBufferPointer {
/// - index: The index of the buffer element to deinitialize.
@inlinable
@_alwaysEmitIntoClient
public func deinitializeElement(at index: Index) {
${modifier} func deinitializeElement(at index: Index) {
assert(startIndex <= index && index < endIndex)
let p = baseAddress.unsafelyUnwrapped.advanced(by: index)
p.deinitialize(count: 1)
Expand Down Expand Up @@ -252,7 +259,7 @@ extension Slice {
/// initialized by this function.
@inlinable
@_alwaysEmitIntoClient
public func initialize<C: Collection>(
${modifier} func initialize<C: Collection>(
fromContentsOf source: C
) -> Index where Base == UnsafeMutableBufferPointer<C.Element> {
let buffer = Base(rebasing: self)
Expand Down Expand Up @@ -291,7 +298,7 @@ extension Slice {
/// initialized by this function.
@inlinable
@_alwaysEmitIntoClient
public func moveInitialize<Element>(
${modifier} func moveInitialize<Element>(
fromContentsOf source: UnsafeMutableBufferPointer<Element>
) -> Index where Base == UnsafeMutableBufferPointer<Element> {
let buffer = Base(rebasing: self)
Expand Down Expand Up @@ -330,7 +337,7 @@ extension Slice {
/// initialized by this function.
@inlinable
@_alwaysEmitIntoClient
public func moveInitialize<Element>(
${modifier} func moveInitialize<Element>(
fromContentsOf source: Slice<UnsafeMutableBufferPointer<Element>>
) -> Index where Base == UnsafeMutableBufferPointer<Element> {
let buffer = Base(rebasing: self)
Expand All @@ -352,7 +359,7 @@ extension Slice {
@discardableResult
@inlinable
@_alwaysEmitIntoClient
public func deinitialize<Element>() -> UnsafeMutableRawBufferPointer
${modifier} func deinitialize<Element>() -> UnsafeMutableRawBufferPointer
where Base == UnsafeMutableBufferPointer<Element> {
Base(rebasing: self).deinitialize()
}
Expand All @@ -368,7 +375,7 @@ extension Slice {
/// - index: The index of the element to initialize
@inlinable
@_alwaysEmitIntoClient
public func initializeElement<Element>(at index: Int, to value: Element)
${modifier} func initializeElement<Element>(at index: Int, to value: Element)
where Base == UnsafeMutableBufferPointer<Element> {
assert(startIndex <= index && index < endIndex)
base.baseAddress.unsafelyUnwrapped.advanced(by: index).initialize(to: value)
Expand All @@ -388,7 +395,7 @@ extension UnsafeMutableBufferPointer {
/// - Parameters:
/// - repeatedValue: The value used when updating this pointer's memory.
@_alwaysEmitIntoClient
public func update(repeating repeatedValue: Element) {
${modifier} func update(repeating repeatedValue: Element) {
guard let dstBase = baseAddress else { return }
dstBase.update(repeating: repeatedValue, count: count)
}
Expand All @@ -407,9 +414,11 @@ extension Slice {
/// - Parameters:
/// - repeatedValue: The value used when updating this pointer's memory.
@_alwaysEmitIntoClient
public func update<Element>(repeating repeatedValue: Element)
${modifier} func update<Element>(repeating repeatedValue: Element)
where Base == UnsafeMutableBufferPointer<Element> {
Base(rebasing: self).update(repeating: repeatedValue)
}
}
#endif
% end
${visibility_boilerplate("end")}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2022 Apple Inc. and the Swift project authors
// Copyright (c) 2022 - 2023 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
//
//===----------------------------------------------------------------------===//

%{
from gyb_utils import *
}%
${autogenerated_warning()}

% for modifier in visibility_levels:
${visibility_boilerplate(modifier)}
#if swift(<5.8)
extension UnsafeMutablePointer {
/// Update this pointer's initialized memory with the specified number of
Expand All @@ -24,11 +31,13 @@ extension UnsafeMutablePointer {
/// - count: The number of consecutive elements to update.
/// `count` must not be negative.
@_alwaysEmitIntoClient
public func update(repeating repeatedValue: Pointee, count: Int) {
${modifier} func update(repeating repeatedValue: Pointee, count: Int) {
assert(count >= 0, "UnsafeMutablePointer.update(repeating:count:) with negative count")
for i in 0 ..< count {
self[i] = repeatedValue
}
}
}
#endif
% end
${visibility_boilerplate("end")}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2022 Apple Inc. and the Swift project authors
// Copyright (c) 2022 - 2023 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
//
//===----------------------------------------------------------------------===//

%{
from gyb_utils import *
}%
${autogenerated_warning()}

% for modifier in visibility_levels:
${visibility_boilerplate(modifier)}
#if compiler(<5.7) || (os(macOS) && compiler(<5.8)) // SE-0334
extension UnsafeRawPointer {
/// Obtain the next pointer properly aligned to store a value of type `T`.
Expand All @@ -21,7 +28,7 @@ extension UnsafeRawPointer {
/// - Returns: a pointer properly aligned to store a value of type `T`.
@inlinable
@_alwaysEmitIntoClient
public func alignedUp<T>(for type: T.Type) -> Self {
${modifier} func alignedUp<T>(for type: T.Type) -> Self {
let mask = UInt(MemoryLayout<T>.alignment) &- 1
let bits = (UInt(bitPattern: self) &+ mask) & ~mask
return Self(bitPattern: bits)!
Expand All @@ -37,7 +44,7 @@ extension UnsafeRawPointer {
/// - Returns: a pointer properly aligned to store a value of type `T`.
@inlinable
@_alwaysEmitIntoClient
public func alignedDown<T>(for type: T.Type) -> Self {
${modifier} func alignedDown<T>(for type: T.Type) -> Self {
let mask = UInt(MemoryLayout<T>.alignment) &- 1
let bits = UInt(bitPattern: self) & ~mask
return Self(bitPattern: bits)!
Expand All @@ -55,7 +62,7 @@ extension UnsafeMutableRawPointer {
/// - Returns: a pointer properly aligned to store a value of type `T`.
@inlinable
@_alwaysEmitIntoClient
public func alignedUp<T>(for type: T.Type) -> Self {
${modifier} func alignedUp<T>(for type: T.Type) -> Self {
let mask = UInt(MemoryLayout<T>.alignment) &- 1
let bits = (UInt(bitPattern: self) &+ mask) & ~mask
return Self(bitPattern: bits)!
Expand All @@ -71,10 +78,12 @@ extension UnsafeMutableRawPointer {
/// - Returns: a pointer properly aligned to store a value of type `T`.
@inlinable
@_alwaysEmitIntoClient
public func alignedDown<T>(for type: T.Type) -> Self {
${modifier} func alignedDown<T>(for type: T.Type) -> Self {
let mask = UInt(MemoryLayout<T>.alignment) &- 1
let bits = UInt(bitPattern: self) & ~mask
return Self(bitPattern: bits)!
}
}
#endif
% end
${visibility_boilerplate("end")}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2021 - 2023 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
//
//===----------------------------------------------------------------------===//


// #############################################################################
// # #
// # DO NOT EDIT THIS FILE; IT IS AUTOGENERATED. #
// # #
// #############################################################################


extension Array {
/// Returns true if `Array.withContiguousStorageIfAvailable` is broken
/// in the stdlib we're currently running on.
///
/// See https://bugs.swift.org/browse/SR-14663.
@inlinable @inline(__always)
internal static func _isWCSIABroken() -> Bool {
#if _runtime(_ObjC)
guard _isBridgedVerbatimToObjectiveC(Element.self) else {
// SR-14663 only triggers on array values that are verbatim bridged
// from Objective-C, so it cannot ever trigger for element types
// that aren't verbatim bridged.
return false
}

// SR-14663 was introduced in Swift 5.1, and it was resolved in Swift 5.5.
// Check if we have a broken stdlib.

// The bug is caused by a bogus precondition inside a non-inlinable stdlib
// method, so to determine if we're affected, we need to check the currently
// running OS version.
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
if #available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) {
// The OS is too new to be affected by this bug. (>= 5.5 stdlib)
return false
}
// guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13, *) else {
// // The OS is too old to be affected by this bug. (< 5.1 stdlib)
// return false
// }
return true
#else
// Assume that other platforms aren't affected.
return false
#endif

#else
// Platforms that don't have an Objective-C runtime don't have verbatim
// bridged array values, so the bug doesn't apply to them.
return false
#endif
}
}


// In single module mode, we need these declarations to be internal,
// but in regular builds we want them to be public. Unfortunately
// the current best way to do this is to duplicate all definitions.
#if COLLECTIONS_SINGLE_MODULE
extension Sequence {
// An adjusted version of the standard `withContiguousStorageIfAvailable`
// method that works around https://bugs.swift.org/browse/SR-14663.
@inlinable @inline(__always)
internal func _withContiguousStorageIfAvailable_SR14663<R>(
_ body: (UnsafeBufferPointer<Element>) throws -> R
) rethrows -> R? {
if Self.self == Array<Element>.self && Array<Element>._isWCSIABroken() {
return nil
}

return try self.withContiguousStorageIfAvailable(body)
}
}
#else // !COLLECTIONS_SINGLE_MODULE
extension Sequence {
// An adjusted version of the standard `withContiguousStorageIfAvailable`
// method that works around https://bugs.swift.org/browse/SR-14663.
@inlinable @inline(__always)
public func _withContiguousStorageIfAvailable_SR14663<R>(
_ body: (UnsafeBufferPointer<Element>) throws -> R
) rethrows -> R? {
if Self.self == Array<Element>.self && Array<Element>._isWCSIABroken() {
return nil
}

return try self.withContiguousStorageIfAvailable(body)
}
}
#endif // COLLECTIONS_SINGLE_MODULE
Loading

0 comments on commit c287334

Please sign in to comment.