Skip to content

Commit 5f5e6b6

Browse files
committed
[stdlib] make OutputSpan changes from SE-0485
1 parent 5895a64 commit 5f5e6b6

File tree

2 files changed

+52
-300
lines changed

2 files changed

+52
-300
lines changed

stdlib/public/core/Span/OutputSpan.swift

Lines changed: 52 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,6 @@ public struct OutputSpan<Element: ~Copyable>: ~Copyable, ~Escapable {
4747
capacity = 0
4848
_count = 0
4949
}
50-
51-
@unsafe
52-
@_alwaysEmitIntoClient
53-
@lifetime(borrow start)
54-
public init(
55-
_uncheckedStart start: UnsafeMutableRawPointer?,
56-
capacity: Int,
57-
initializedCount: Int
58-
) {
59-
unsafe _pointer = start
60-
self.capacity = capacity
61-
_count = initializedCount
62-
}
6350
}
6451

6552
@available(SwiftStdlib 6.2, *)
@@ -68,6 +55,8 @@ extension OutputSpan: @unchecked Sendable where Element: Sendable & ~Copyable {}
6855
@available(SwiftStdlib 6.2, *)
6956
extension OutputSpan where Element: ~Copyable {
7057
@_alwaysEmitIntoClient
58+
@_transparent
59+
@unsafe
7160
internal func _start() -> UnsafeMutableRawPointer {
7261
unsafe _pointer._unsafelyUnwrappedUnchecked
7362
}
@@ -79,16 +68,23 @@ extension OutputSpan where Element: ~Copyable {
7968
// NOTE: `_pointer` must be known to be not-nil.
8069
unsafe _start().advanced(by: _count &* MemoryLayout<Element>.stride)
8170
}
71+
}
8272

73+
@available(SwiftStdlib 6.2, *)
74+
extension OutputSpan where Element: ~Copyable {
75+
/// The number of initialized elements in this span.
8376
@_alwaysEmitIntoClient
84-
public var freeCapacity: Int { capacity &- _count }
77+
public var count: Int { _count }
8578

79+
/// The number of additional elements that can be added to this span.
8680
@_alwaysEmitIntoClient
87-
public var count: Int { _count }
81+
public var freeCapacity: Int { capacity &- _count }
8882

83+
/// A Boolean value indicating whether the span is empty.
8984
@_alwaysEmitIntoClient
9085
public var isEmpty: Bool { _count == 0 }
9186

87+
/// A Boolean value indicating whether the span is full.
9288
@_alwaysEmitIntoClient
9389
public var isFull: Bool { _count == capacity }
9490
}
@@ -99,7 +95,8 @@ extension OutputSpan where Element: ~Copyable {
9995
@unsafe
10096
@_alwaysEmitIntoClient
10197
@lifetime(borrow buffer)
102-
public init(
98+
@usableFromInline
99+
internal init(
103100
_uncheckedBuffer buffer: UnsafeMutableBufferPointer<Element>,
104101
initializedCount: Int
105102
) {
@@ -176,63 +173,66 @@ extension OutputSpan {
176173

177174
@available(SwiftStdlib 6.2, *)
178175
extension OutputSpan where Element: ~Copyable {
179-
176+
/// The type that represents an initialized position in an `OutputSpan`.
180177
public typealias Index = Int
181178

179+
/// The range of initialized positions for this `OutputSpan`.
182180
@_alwaysEmitIntoClient
183181
public var indices: Range<Index> {
184182
unsafe Range(_uncheckedBounds: (0, _count))
185183
}
186184

187185
/// Accesses the element at the specified position.
188186
///
189-
/// - Parameter position: The offset of the element to access. `position`
190-
/// must be greater or equal to zero, and less than `count`.
187+
/// - Parameter index: A valid index into this span.
191188
///
192189
/// - Complexity: O(1)
193190
@_alwaysEmitIntoClient
194-
public subscript(_ position: Index) -> Element {
191+
public subscript(_ index: Index) -> Element {
195192
unsafeAddress {
196-
_precondition(indices.contains(position), "index out of bounds")
197-
return unsafe UnsafePointer(_unsafeAddressOfElement(unchecked: position))
193+
_precondition(indices.contains(index), "index out of bounds")
194+
return unsafe UnsafePointer(_unsafeAddressOfElement(unchecked: index))
198195
}
199196
@lifetime(self: copy self)
200197
unsafeMutableAddress {
201-
_precondition(indices.contains(position), "index out of bounds")
202-
return unsafe _unsafeAddressOfElement(unchecked: position)
198+
_precondition(indices.contains(index), "index out of bounds")
199+
return unsafe _unsafeAddressOfElement(unchecked: index)
203200
}
204201
}
205202

206203
/// Accesses the element at the specified position.
207204
///
208205
/// This subscript does not validate `position`; this is an unsafe operation.
209206
///
210-
/// - Parameter position: The offset of the element to access. `position`
211-
/// must be greater or equal to zero, and less than `count`.
207+
/// - Parameter index: A valid index into this span.
212208
///
213209
/// - Complexity: O(1)
214210
@unsafe
215211
@_alwaysEmitIntoClient
216-
public subscript(unchecked position: Index) -> Element {
212+
public subscript(unchecked index: Index) -> Element {
217213
unsafeAddress {
218-
unsafe UnsafePointer(_unsafeAddressOfElement(unchecked: position))
214+
unsafe UnsafePointer(_unsafeAddressOfElement(unchecked: index))
219215
}
220216
@lifetime(self: copy self)
221217
unsafeMutableAddress {
222-
unsafe _unsafeAddressOfElement(unchecked: position)
218+
unsafe _unsafeAddressOfElement(unchecked: index)
223219
}
224220
}
225221

226222
@unsafe
227223
@_alwaysEmitIntoClient
228224
internal func _unsafeAddressOfElement(
229-
unchecked position: Index
225+
unchecked index: Index
230226
) -> UnsafeMutablePointer<Element> {
231-
let elementOffset = position &* MemoryLayout<Element>.stride
227+
let elementOffset = index &* MemoryLayout<Element>.stride
232228
let address = unsafe _start().advanced(by: elementOffset)
233229
return unsafe address.assumingMemoryBound(to: Element.self)
234230
}
235231

232+
/// Exchange the elements at the two given offsets
233+
///
234+
/// - Parameter i: A valid index into this span.
235+
/// - Parameter j: A valid index into this span.
236236
@_alwaysEmitIntoClient
237237
@lifetime(self: copy self)
238238
public mutating func swapAt(_ i: Index, _ j: Index) {
@@ -241,6 +241,12 @@ extension OutputSpan where Element: ~Copyable {
241241
unsafe swapAt(unchecked: i, unchecked: j)
242242
}
243243

244+
/// Exchange the elements at the two given offsets
245+
///
246+
/// This subscript does not validate `i` or `j`; this is an unsafe operation.
247+
///
248+
/// - Parameter i: A valid index into this span.
249+
/// - Parameter j: A valid index into this span.
244250
@unsafe
245251
@_alwaysEmitIntoClient
246252
@lifetime(self: copy self)
@@ -255,7 +261,7 @@ extension OutputSpan where Element: ~Copyable {
255261

256262
@available(SwiftStdlib 6.2, *)
257263
extension OutputSpan where Element: ~Copyable {
258-
264+
/// Append a single element to this span.
259265
@_alwaysEmitIntoClient
260266
@lifetime(self: copy self)
261267
public mutating func append(_ value: consuming Element) {
@@ -264,6 +270,9 @@ extension OutputSpan where Element: ~Copyable {
264270
_count &+= 1
265271
}
266272

273+
/// Remove the last initialized element from this span.
274+
///
275+
/// Returns the last element. The `OutputSpan` must not be empty.
267276
@_alwaysEmitIntoClient
268277
@lifetime(self: copy self)
269278
public mutating func removeLast() -> Element {
@@ -274,6 +283,10 @@ extension OutputSpan where Element: ~Copyable {
274283
}
275284
}
276285

286+
/// Remove the last N elements of this span, returning the memory they occupy
287+
/// to the uninitialized state.
288+
///
289+
/// `n` must not be greater than `count`
277290
@_alwaysEmitIntoClient
278291
@lifetime(self: copy self)
279292
public mutating func removeLast(_ k: Int) {
@@ -285,6 +298,8 @@ extension OutputSpan where Element: ~Copyable {
285298
}
286299
}
287300

301+
/// Remove all this span's elements and return its memory
302+
/// to the uninitialized state.
288303
@_alwaysEmitIntoClient
289304
@lifetime(self: copy self)
290305
public mutating func removeAll() {
@@ -299,7 +314,7 @@ extension OutputSpan where Element: ~Copyable {
299314
@available(SwiftStdlib 6.2, *)
300315
extension OutputSpan {
301316

302-
/// Initialize this span's suffix to the repetitions of the given value.
317+
/// Repeatedly append an element to this span.
303318
@_alwaysEmitIntoClient
304319
@lifetime(self: copy self)
305320
public mutating func append(repeating repeatedValue: Element, count: Int) {
@@ -309,137 +324,11 @@ extension OutputSpan {
309324
)
310325
_count &+= count
311326
}
312-
313-
/// Returns true if the iterator has filled all the free capacity in the span.
314-
@_alwaysEmitIntoClient
315-
@lifetime(self: copy self)
316-
@discardableResult
317-
public mutating func append(
318-
from elements: inout some IteratorProtocol<Element>
319-
) -> Bool {
320-
// FIXME: It may be best to delay this API until
321-
// we have designed a chunking IteratorProtocol
322-
var p = unsafe _tail()
323-
while _count < capacity {
324-
guard let element = elements.next() else { return false }
325-
unsafe p.initializeMemory(as: Element.self, to: element)
326-
unsafe p = p.advanced(by: MemoryLayout<Element>.stride)
327-
_count &+= 1
328-
}
329-
return true
330-
}
331-
332-
@_alwaysEmitIntoClient
333-
@lifetime(self: copy self)
334-
public mutating func append(
335-
contentsOf source: consuming some Sequence<Element>
336-
) {
337-
let done: Void? = source.withContiguousStorageIfAvailable {
338-
unsafe append(contentsOf: $0)
339-
}
340-
if done != nil {
341-
return
342-
}
343-
344-
let freeCapacity = freeCapacity
345-
let tail = unsafe _tail()._rawValue
346-
// rebind memory manually to get around closure issues
347-
// see https://github.com/swiftlang/swift/issues/81525
348-
let binding = Builtin.bindMemory(
349-
tail, freeCapacity._builtinWordValue, Element.self
350-
)
351-
defer { Builtin.rebindMemory(tail, binding) }
352-
let suffix = unsafe UnsafeMutableBufferPointer<Element>(
353-
start: .init(tail), count: freeCapacity
354-
)
355-
var (iterator, copied) = unsafe source._copyContents(initializing: suffix)
356-
357-
_precondition(iterator.next() == nil, "OutputSpan capacity overflow")
358-
_precondition(_count + copied <= capacity, "Invalid Sequence._copyContents")
359-
_count &+= copied
360-
}
361-
362-
@_alwaysEmitIntoClient
363-
@lifetime(self: copy self)
364-
public mutating func append(
365-
contentsOf source: UnsafeBufferPointer<Element>
366-
) {
367-
guard !source.isEmpty else { return }
368-
_precondition(source.count <= freeCapacity, "OutputSpan capacity overflow")
369-
unsafe _tail().initializeMemory(
370-
as: Element.self, from: source.baseAddress!, count: source.count)
371-
_count += source.count
372-
}
373-
374-
@_alwaysEmitIntoClient
375-
@lifetime(self: copy self)
376-
public mutating func append(
377-
copying source: borrowing Span<Element>
378-
) {
379-
unsafe source.withUnsafeBufferPointer { unsafe append(contentsOf: $0) }
380-
}
381-
}
382-
383-
@available(SwiftStdlib 6.2, *)
384-
extension OutputSpan where Element: ~Copyable {
385-
/// Append to this output span by moving elements out of the given output
386-
/// span, leaving it empty. The elements are appended in the order they appear
387-
/// in the source.
388-
@_alwaysEmitIntoClient
389-
@lifetime(self: copy self)
390-
public mutating func append(
391-
moving source: inout Self
392-
) {
393-
guard !source.isEmpty else { return }
394-
unsafe source.withUnsafeMutableBufferPointer {
395-
unsafe self.append(consuming: $0.extracting(..<$1))
396-
$1 = 0
397-
}
398-
}
399-
}
400-
401-
@available(SwiftStdlib 6.2, *)
402-
extension OutputSpan where Element: BitwiseCopyable {
403-
//FIXME: We need this for Element: ~Copyable
404-
@_alwaysEmitIntoClient
405-
@lifetime(self: copy self)
406-
public mutating func append<let N: Int>(
407-
consuming source: consuming InlineArray<N, Element>
408-
) {
409-
source._consume { append(moving: &$0) }
410-
}
411-
}
412-
413-
@available(SwiftStdlib 6.2, *)
414-
extension OutputSpan where Element: ~Copyable {
415-
@_alwaysEmitIntoClient
416-
@lifetime(self: copy self)
417-
public mutating func append(
418-
consuming source: UnsafeMutableBufferPointer<Element>
419-
) {
420-
guard !source.isEmpty else { return }
421-
_precondition(source.count <= freeCapacity, "OutputSpan capacity overflow")
422-
unsafe _tail().moveInitializeMemory(
423-
as: Element.self, from: source.baseAddress!, count: source.count
424-
)
425-
_count += source.count
426-
}
427-
}
428-
429-
@available(SwiftStdlib 6.2, *)
430-
extension OutputSpan {
431-
@_alwaysEmitIntoClient
432-
@lifetime(self: copy self)
433-
public mutating func append(
434-
consuming source: Slice<UnsafeMutableBufferPointer<Element>>
435-
) {
436-
unsafe append(consuming: UnsafeMutableBufferPointer(rebasing: source))
437-
}
438327
}
439328

440329
@available(SwiftStdlib 6.2, *)
441330
extension OutputSpan where Element: ~Copyable {
442-
331+
/// Borrow the underlying initialized memory for read-only access.
443332
@_alwaysEmitIntoClient
444333
public var span: Span<Element> {
445334
@lifetime(borrow self)
@@ -451,6 +340,7 @@ extension OutputSpan where Element: ~Copyable {
451340
}
452341
}
453342

343+
/// Exclusively borrow the underlying initialized memory for mutation.
454344
@_alwaysEmitIntoClient
455345
public var mutableSpan: MutableSpan<Element> {
456346
@lifetime(&self)
@@ -526,8 +416,7 @@ extension OutputSpan where Element: ~Copyable {
526416

527417
@available(SwiftStdlib 6.2, *)
528418
extension OutputSpan where Element: ~Copyable {
529-
/// Consume the output span (relinquishing its control over the buffer it is
530-
/// addressing), and return the number of initialized elements in it.
419+
/// Consume the output span and return the number of initialized elements.
531420
///
532421
/// This method should be invoked in the scope where the `OutputSpan` was
533422
/// created, when it is time to commit the contents of the updated buffer
@@ -560,8 +449,7 @@ extension OutputSpan where Element: ~Copyable {
560449

561450
@available(SwiftStdlib 6.2, *)
562451
extension OutputSpan {
563-
/// Consume the output span (relinquishing its control over the buffer it is
564-
/// addressing), and return the number of initialized elements in it.
452+
/// Consume the output span and return the number of initialized elements.
565453
///
566454
/// This method should be invoked in the scope where the `OutputSpan` was
567455
/// created, when it is time to commit the contents of the updated buffer

0 commit comments

Comments
 (0)