Skip to content

[DNM] OutputSpan prototype (updated) #81637

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

Draft
wants to merge 63 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
819a978
[stdlib] add `OutputSpan`
glessard Feb 28, 2025
14d0474
[stdlib] disable some initializers
glessard Feb 28, 2025
8c116e7
[test] OutputSpan tests
glessard Feb 28, 2025
5433e53
[test] abi accounting
glessard Feb 28, 2025
65663f6
[stdlib] add unsafe annotations for `OutputSpan`
glessard Mar 5, 2025
625fcae
[stdlib] rename some methods
glessard Mar 6, 2025
0f7d677
[test] update function names
glessard Mar 21, 2025
f56806e
[stdlib] update lifetime annotations for OutputSpan
glessard Mar 21, 2025
f33ffd3
[stdlib] add more unsafe annotations for `OutputSpan`
glessard Apr 4, 2025
98ee668
[stdlib] alignment-checking functions for pointers
glessard Apr 9, 2025
237848e
[stdlib] better alignment checks
glessard Apr 9, 2025
2ca8ba8
[stdlib] `OutputSpan` updates
glessard Apr 9, 2025
3c529bb
[stdlib] add OutputRawSpan
glessard Apr 9, 2025
73872a1
[stdlib] more outputspan tweaks
glessard Apr 10, 2025
e74f7d6
[stdlib] OutputSpan: follow our coding conventions for organization o…
lorentey Apr 10, 2025
6875ad9
[stdlib] OutputSpan.deinit: Make inlinable
lorentey Apr 10, 2025
69e1df4
[stdlib] OutputSpan API/implementation improvements
lorentey Apr 10, 2025
e0b9af6
[stdlib] alignment-checking functions for pointers
glessard Apr 9, 2025
a559a9c
[stdlib] better alignment checks
glessard Apr 12, 2025
10ee830
[stdlib] `OutputSpan` updates
glessard Apr 9, 2025
343ab78
[stdlib] add OutputRawSpan
glessard Apr 9, 2025
c517b8b
[stdlib] more outputspan tweaks
glessard Apr 10, 2025
cc9cc94
[stdlib] more OutputSpan tweaks
glessard Apr 11, 2025
4aa6924
[stdlib] conventional organization of type definition
lorentey Apr 10, 2025
6e780ad
[stdlib] OutputSpan.deinit: Make inlinable
lorentey Apr 10, 2025
29f46d8
[stdlib] OutputSpan review suggestions
glessard Apr 12, 2025
387b884
Merge branch 'rdar117099863-OutputSpan' into rdar147780495-OutputSpan
glessard Apr 12, 2025
b06955e
[test] more abi accounting
glessard Apr 13, 2025
3bca10f
[test] update OutputSpan tests
glessard Apr 14, 2025
2400703
Merge branch 'snapshot-20250412' into rdar147780495-OutputSpan
glessard Apr 14, 2025
8db3045
[stdlib] update lifetime syntax
glessard Apr 14, 2025
ee92648
Merge branch 'snapshot-20250412-augmented' into rdar147780495-OutputSpan
glessard Apr 15, 2025
044a630
Apply recommended changes from code review
lorentey Apr 17, 2025
9e229da
[stdlib] internal Unsafe{Raw}BufferPointer tweaks
glessard Apr 17, 2025
6908440
[stdlib] OutputSpan tweaks
glessard Apr 17, 2025
55e4512
[stdlib] updates to OutputRawSpan
glessard Apr 17, 2025
1cf0414
Merge branch 'rdar147780495-OutputSpan-karoy' into rdar147780495-Outp…
glessard Apr 18, 2025
9f813b6
[stdlib] in-place initializer for InlineArray
glessard Apr 18, 2025
1231891
[test] adjust spellings in OutputSpan tests
glessard Apr 18, 2025
b3fb519
[test] in-place InlineArray initialization
glessard Apr 18, 2025
49383a0
[stdlib] safe in-place initializer for Array
glessard Apr 18, 2025
71e49db
[stdlib] safe in-place initializer for String
glessard Apr 19, 2025
8840b5e
[test] failing (crashing) InlineArray tests
glessard Apr 19, 2025
b74f4cf
[test] skip crash test on wasi
glessard Apr 19, 2025
e1ed7ec
[stdlib] OutputSpan doc-comment tweaks
glessard Apr 22, 2025
c7675d3
[stdlib] tweak OutputRawSpan implementation
glessard Apr 22, 2025
e2ba770
[stdlib] OutputRawSpan doc-comment tweaks
glessard Apr 22, 2025
3013aa6
[stdlib] remove an unnecessary overload
glessard Apr 22, 2025
2acca1c
[stdlib] list files for cmake
glessard Apr 23, 2025
17aaa56
[test] disambiguate `InlineArray` initializers
glessard Apr 24, 2025
f4c4657
[stdlib] mark initializers inlinable
glessard Apr 24, 2025
c99d9c5
[test] disable a flaky test configuration
glessard Apr 25, 2025
137e966
[stdlib] remove a tweak
glessard Apr 25, 2025
eba0d59
[stdlib] fix OutputSpan.removeLast()
glessard Apr 25, 2025
ed8f939
Merge branch 'snapshot-20250508' into rdar147780495-OutputSpan
glessard May 9, 2025
564f022
[stdlib] Array initializer doc-comments
glessard May 13, 2025
a5378a4
[stdlib] Array.append(addingCapacity:initializingWith:)
glessard May 13, 2025
86a8186
[test] exercise non-consuming closure captures
glessard May 7, 2025
ffd0f89
[stdlib] Output[Raw]Span tweaks
glessard May 13, 2025
71cb1a7
[stdlib] add `InlineArray._consume()`
glessard May 16, 2025
dc3e084
[stdlib] deprecate `InlineArray._withU[M]BP`
glessard May 16, 2025
380af42
[test] improve bridged string substring span test
glessard May 16, 2025
dc6a01a
[test] update spellings in tests
glessard May 19, 2025
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
2 changes: 2 additions & 0 deletions Runtimes/Core/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ add_library(swiftCore
Span/RawSpan.swift
Span/MutableSpan.swift
Span/MutableRawSpan.swift
Span/OutputSpan.swift
Span/OutputRawSpan.swift
StaticString.swift
StaticPrint.swift
Stride.swift
Expand Down
59 changes: 59 additions & 0 deletions stdlib/public/core/Array.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,32 @@ extension Array: RangeReplaceableCollection {
}
}

/// Grows the array to ensure capacity for the specified number of elements,
/// then calls the closure with an OutputSpan covering the array's
/// uninitialized memory.
@_alwaysEmitIntoClient
@available(SwiftStdlib 6.2, *)
public mutating func append<E: Error>(
addingCapacity count: Int,
initializingWith initializer: (
_ span: inout OutputSpan<Element>
) throws(E) -> Void
) throws(E) {
_reserveCapacityImpl(
minimumCapacity: self.count + count, growForAppend: true
)
defer {
_endMutation()
}
let oldCount = _buffer.mutableCount
let newElements = unsafe _buffer.mutableFirstElementAddress + oldCount
let raw = unsafe UnsafeMutableBufferPointer(start: newElements, count: count)
var span = unsafe OutputSpan(buffer: raw, initializedCount: 0)
try initializer(&span)
let initialized = unsafe span.finalize(for: raw)
_buffer.mutableCount = oldCount + initialized
}

@inlinable
@_semantics("array.reserve_capacity_for_append")
@_effects(notEscaping self.**)
Expand Down Expand Up @@ -1578,6 +1604,39 @@ extension Array {
initializingWith: initializer)
}

//FIXME: typed throws
/// Creates an array with the specified capacity, then calls the given
/// closure with an OutputSpan covering the array's uninitialized memory.
///
/// - Note: While the resulting array may have a capacity larger than the
/// requested amount, the `OutputSpan` passed to the closure will cover
/// exactly the requested number of elements.
///
/// - Parameters:
/// - capacity: The number of elements to allocate
/// space for in the new array.
/// - initializer: A closure that initializes elements
/// - Parameters:
/// - span: An `OutputSpan` covering uninitialized memory with room
/// for the specified number of elements.
@_alwaysEmitIntoClient
@available(SwiftStdlib 6.2, *)
public init(
capacity: Int,
initializingWith initializer: (
_ span: inout OutputSpan<Element>
) throws -> Void
) rethrows {
try unsafe self.init(
unsafeUninitializedCapacity: capacity,
initializingWith: { (buffer, count) in
var output = unsafe OutputSpan(buffer: buffer, initializedCount: 0)
try initializer(&output)
count = unsafe output.finalize(for: buffer)
}
)
}

// Superseded by the typed-throws version of this function, but retained
// for ABI reasons.
@usableFromInline
Expand Down
2 changes: 2 additions & 0 deletions stdlib/public/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ split_embedded_sources(
EMBEDDED Sort.swift
EMBEDDED Span/MutableRawSpan.swift
EMBEDDED Span/MutableSpan.swift
EMBEDDED Span/OutputRawSpan.swift
EMBEDDED Span/OutputSpan.swift
EMBEDDED Span/RawSpan.swift
EMBEDDED Span/Span.swift
EMBEDDED StaticString.swift
Expand Down
17 changes: 17 additions & 0 deletions stdlib/public/core/ContiguousArray.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,23 @@ extension ContiguousArray {
initializingWith: initializer))
}

//FIXME: typed throws
@_alwaysEmitIntoClient
@available(SwiftStdlib 6.2, *)
public init(
capacity: Int,
initializingWith initializer: (inout OutputSpan<Element>) throws -> Void
) rethrows {
try unsafe self.init(
unsafeUninitializedCapacity: capacity,
initializingWith: { (buffer, count) in
var output = unsafe OutputSpan(buffer: buffer, initializedCount: 0)
try initializer(&output)
count = unsafe output.finalize(for: buffer)
}
)
}

// Superseded by the typed-throws version of this function, but retained
// for ABI reasons.
@usableFromInline
Expand Down
2 changes: 2 additions & 0 deletions stdlib/public/core/GroupInfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@
"Span": [
"MutableRawSpan.swift",
"MutableSpan.swift",
"OutputRawSpan.swift",
"OutputSpan.swift",
"RawSpan.swift",
"Span.swift"
],
Expand Down
43 changes: 41 additions & 2 deletions stdlib/public/core/InlineArray.swift
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,25 @@ extension InlineArray where Element: ~Copyable {
}
#else
fatalError()
#endif
}

@available(SwiftStdlib 6.2, *)
@_alwaysEmitIntoClient
public init<E: Error>(
initializingWith initializer: (inout OutputSpan<Element>) throws(E) -> Void
) throws(E) {
#if $BuiltinEmplaceTypedThrows
self = try Builtin.emplace { (rawPtr) throws(E) -> () in
let buffer = unsafe Self._initializationBuffer(start: rawPtr)
_internalInvariant(Self.count == buffer.count)
var output = unsafe OutputSpan(buffer: buffer, initializedCount: 0)
try initializer(&output)
let initialized = unsafe output.finalize(for: buffer)
_precondition(count == initialized, "InlineArray initialization underflow")
}
#else
fatalError()
#endif
}
}
Expand Down Expand Up @@ -483,13 +502,33 @@ extension InlineArray where Element: ~Copyable {
}
}

@available(SwiftStdlib 6.2, *)
extension InlineArray where Element: BitwiseCopyable {

@available(SwiftStdlib 6.2, *)
@_alwaysEmitIntoClient
public consuming func _consume<E: Error, Result: ~Copyable>(
_ body: (inout OutputSpan<Element>) throws(E) -> Result
) throws(E) -> Result {
var span = unsafe OutputSpan(
_uncheckedBuffer: _mutableBuffer, initializedCount: count
)
defer {
_precondition(span.count == 0, "must consume all elements")
}
//FIXME: discard self
return try body(&span)
}
}

//===----------------------------------------------------------------------===//
// MARK: - Unsafe APIs
//===----------------------------------------------------------------------===//

@available(SwiftStdlib 6.2, *)
extension InlineArray where Element: ~Copyable {
// FIXME: @available(*, deprecated, renamed: "span.withUnsafeBufferPointer(_:)")

@available(*, deprecated, renamed: "span.withUnsafeBufferPointer(_:)")
@available(SwiftStdlib 6.2, *)
@_alwaysEmitIntoClient
@_transparent
Expand All @@ -499,7 +538,7 @@ extension InlineArray where Element: ~Copyable {
try unsafe body(_buffer)
}

// FIXME: @available(*, deprecated, renamed: "mutableSpan.withUnsafeMutableBufferPointer(_:)")
@available(*, deprecated, renamed: "mutableSpan.withUnsafeMutableBufferPointer(_:)")
@available(SwiftStdlib 6.2, *)
@_alwaysEmitIntoClient
@_transparent
Expand Down
15 changes: 5 additions & 10 deletions stdlib/public/core/Span/MutableSpan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,7 @@ extension MutableSpan where Element: ~Copyable {
public init(
_unsafeElements buffer: UnsafeMutableBufferPointer<Element>
) {
_precondition(
((Int(bitPattern: buffer.baseAddress) &
(MemoryLayout<Element>.alignment &- 1)) == 0),
"baseAddress must be properly aligned to access Element"
)
_precondition(buffer._isWellAligned(), "Misaligned MutableSpan")
let ms = unsafe MutableSpan<Element>(_unchecked: buffer)
self = unsafe _overrideLifetime(ms, borrowing: buffer)
}
Expand Down Expand Up @@ -120,17 +116,16 @@ extension MutableSpan where Element: BitwiseCopyable {
public init(
_unsafeBytes buffer: UnsafeMutableRawBufferPointer
) {
let baseAddress = unsafe buffer.baseAddress?
.assumingMemoryBound(to: Element.self)
_precondition(
((Int(bitPattern: buffer.baseAddress) &
(MemoryLayout<Element>.alignment &- 1)) == 0),
"baseAddress must be properly aligned to access Element"
unsafe baseAddress?._isWellAligned() ?? true, "Misaligned MutableSpan"
)
let (byteCount, stride) = (buffer.count, MemoryLayout<Element>.stride)
let (count, remainder) = byteCount.quotientAndRemainder(dividingBy: stride)
_precondition(remainder == 0, "Span must contain a whole number of elements")
let elements = unsafe UnsafeMutableBufferPointer<Element>(
start: buffer.baseAddress?.assumingMemoryBound(to: Element.self),
count: count
start: baseAddress, count: count
)
let ms = unsafe MutableSpan(_unsafeElements: elements)
self = unsafe _overrideLifetime(ms, borrowing: buffer)
Expand Down
Loading