Skip to content

Commit 6272ad6

Browse files
committed
[span] address review feedback
1 parent c2abbbf commit 6272ad6

File tree

2 files changed

+205
-111
lines changed

2 files changed

+205
-111
lines changed

stdlib/public/core/Span/RawSpan.swift

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,57 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
// A RawSpan represents a span of initialized memory
14-
// of unspecified type.
13+
/// `RawSpan` represents a contiguous region of memory
14+
/// which contains initialized bytes.
15+
///
16+
/// A `RawSpan` instance is a non-owning, non-escaping view into memory.
17+
/// When a `RawSpan` is created, it inherits the lifetime of the container
18+
/// owning the contiguous memory, ensuring temporal safety and avoiding
19+
/// use-after-free errors. Operations on `RawSpan` are bounds-checked,
20+
/// ensuring spcial safety and avoiding buffer overflow errors.
1521
@_disallowFeatureSuppression(NonescapableTypes)
1622
@available(SwiftStdlib 6.1, *)
1723
@frozen
1824
public struct RawSpan: ~Escapable, Copyable, BitwiseCopyable {
19-
@usableFromInline internal let _pointer: UnsafeRawPointer?
25+
26+
/// The starting address of this `RawSpan`.
27+
///
28+
/// `_pointer` can be `nil` if and only if `_count` equals 0.
29+
/// Otherwise, `_pointer` must point to memory that will remain
30+
/// valid and not mutated as long as this `Span` exists.
31+
/// The memory at `_pointer` must consist of `_count` initialized bytes.
32+
@usableFromInline
33+
internal let _pointer: UnsafeRawPointer?
2034

2135
@_alwaysEmitIntoClient
2236
internal func _start() -> UnsafeRawPointer {
2337
_pointer._unsafelyUnwrappedUnchecked
2438
}
2539

26-
@usableFromInline internal let _count: Int
40+
/// The number of bytes in this `RawSpan`.
41+
///
42+
/// If `_count` equals 0, then `_pointer` may be either `nil` or valid.
43+
/// Any `_count` greater than 0 indicates a valid non-nil `_pointer`.
44+
/// Any `_count` less than 0 is invalid and is undefined behaviour.
45+
@usableFromInline
46+
internal let _count: Int
2747

48+
/// Unsafely create a `RawSpan` over initialized memory.
49+
///
50+
/// `pointer` must point to a region of `byteCount` initialized bytes,
51+
/// or may be `nil` if `count` is 0.
52+
///
53+
/// The region of `byteCount` bytes of memory starting at `pointer`
54+
/// must remain valid, initialized and immutable
55+
/// throughout the lifetime of the newly-created `Span`.
56+
/// Failure to maintain this invariant results in undefined behaviour.
57+
///
58+
/// - Parameters:
59+
/// - pointer: a pointer to the first initialized byte.
60+
/// - byteCount: the number of initialized bytes in the span.
2861
@_disallowFeatureSuppression(NonescapableTypes)
2962
@_alwaysEmitIntoClient
63+
@inline(__always)
3064
//FIXME: should be @lifetime(borrow pointer) rdar://138672380
3165
@lifetime(immortal)
3266
internal init(
@@ -298,11 +332,12 @@ extension RawSpan {
298332
/// - Complexity: O(1)
299333
@_disallowFeatureSuppression(NonescapableTypes)
300334
@_alwaysEmitIntoClient
335+
@lifetime(self)
301336
public func _extracting(_ bounds: Range<Int>) -> Self {
302337
_precondition(
303338
UInt(bitPattern: bounds.lowerBound) <= UInt(bitPattern: _count) &&
304339
UInt(bitPattern: bounds.upperBound) <= UInt(bitPattern: _count),
305-
"byte offset range out of bounds"
340+
"Byte offset range out of bounds"
306341
)
307342
return _extracting(unchecked: bounds)
308343
}
@@ -325,6 +360,7 @@ extension RawSpan {
325360
@_disallowFeatureSuppression(NonescapableTypes)
326361
@unsafe
327362
@_alwaysEmitIntoClient
363+
@lifetime(self)
328364
public func _extracting(unchecked bounds: Range<Int>) -> Self {
329365
RawSpan(
330366
_unchecked: _pointer?.advanced(by: bounds.lowerBound),
@@ -347,6 +383,7 @@ extension RawSpan {
347383
/// - Complexity: O(1)
348384
@_disallowFeatureSuppression(NonescapableTypes)
349385
@_alwaysEmitIntoClient
386+
@lifetime(self)
350387
public func _extracting(_ bounds: some RangeExpression<Int>) -> Self {
351388
_extracting(bounds.relative(to: byteOffsets))
352389
}
@@ -369,6 +406,7 @@ extension RawSpan {
369406
@_disallowFeatureSuppression(NonescapableTypes)
370407
@unsafe
371408
@_alwaysEmitIntoClient
409+
@lifetime(self)
372410
public func _extracting(
373411
unchecked bounds: some RangeExpression<Int>
374412
) -> Self {
@@ -386,6 +424,7 @@ extension RawSpan {
386424
/// - Complexity: O(1)
387425
@_disallowFeatureSuppression(NonescapableTypes)
388426
@_alwaysEmitIntoClient
427+
@lifetime(self)
389428
public func _extracting(_: UnboundedRange) -> Self {
390429
self
391430
}
@@ -479,7 +518,7 @@ extension RawSpan {
479518
_precondition(
480519
UInt(bitPattern: offset) <= UInt(bitPattern: _count) &&
481520
MemoryLayout<T>.size <= (_count &- offset),
482-
"byte offset range out of bounds"
521+
"Byte offset range out of bounds"
483522
)
484523
return unsafeLoad(fromUncheckedByteOffset: offset, as: T.self)
485524
}
@@ -536,7 +575,7 @@ extension RawSpan {
536575
_precondition(
537576
UInt(bitPattern: offset) <= UInt(bitPattern: _count) &&
538577
MemoryLayout<T>.size <= (_count &- offset),
539-
"byte offset range out of bounds"
578+
"Byte offset range out of bounds"
540579
)
541580
return unsafeLoadUnaligned(fromUncheckedByteOffset: offset, as: T.self)
542581
}
@@ -589,16 +628,16 @@ extension RawSpan {
589628
/// Returns: A range of offsets within `self`
590629
@_disallowFeatureSuppression(NonescapableTypes)
591630
@_alwaysEmitIntoClient
592-
public func byteOffsets(of span: borrowing Self) -> Range<Int>? {
593-
if span._count > _count { return nil }
594-
guard let spanStart = span._pointer, _count > 0 else {
595-
return _pointer == span._pointer ? Range(_uncheckedBounds: (0, 0)) : nil
631+
public func byteOffsets(of other: borrowing Self) -> Range<Int>? {
632+
if other._count > _count { return nil }
633+
guard let spanStart = other._pointer, _count > 0 else {
634+
return _pointer == other._pointer ? Range(_uncheckedBounds: (0, 0)) : nil
596635
}
597636
let start = _start()
598-
let spanEnd = spanStart + span._count
637+
let spanEnd = spanStart + other._count
599638
if spanStart < start || (start + _count) < spanEnd { return nil }
600639
let lower = start.distance(to: spanStart)
601-
return Range(_uncheckedBounds: (lower, lower &+ span._count))
640+
return Range(_uncheckedBounds: (lower, lower &+ other._count))
602641
}
603642
}
604643

@@ -624,8 +663,9 @@ extension RawSpan {
624663
/// - Complexity: O(1)
625664
@_disallowFeatureSuppression(NonescapableTypes)
626665
@_alwaysEmitIntoClient
666+
@lifetime(self)
627667
public func _extracting(first maxLength: Int) -> Self {
628-
_precondition(maxLength >= 0, "Can't have a prefix of negative length.")
668+
_precondition(maxLength >= 0, "Can't have a prefix of negative length")
629669
let newCount = min(maxLength, byteCount)
630670
return Self(_unchecked: _pointer, byteCount: newCount)
631671
}
@@ -646,8 +686,9 @@ extension RawSpan {
646686
/// - Complexity: O(1)
647687
@_disallowFeatureSuppression(NonescapableTypes)
648688
@_alwaysEmitIntoClient
689+
@lifetime(self)
649690
public func _extracting(droppingLast k: Int) -> Self {
650-
_precondition(k >= 0, "Can't drop a negative number of elements.")
691+
_precondition(k >= 0, "Can't drop a negative number of elements")
651692
let droppedCount = min(k, byteCount)
652693
return Self(_unchecked: _pointer, byteCount: byteCount &- droppedCount)
653694
}
@@ -669,8 +710,9 @@ extension RawSpan {
669710
/// - Complexity: O(1)
670711
@_disallowFeatureSuppression(NonescapableTypes)
671712
@_alwaysEmitIntoClient
713+
@lifetime(self)
672714
public func _extracting(last maxLength: Int) -> Self {
673-
_precondition(maxLength >= 0, "Can't have a suffix of negative length.")
715+
_precondition(maxLength >= 0, "Can't have a suffix of negative length")
674716
let newCount = min(maxLength, byteCount)
675717
let newStart = _pointer?.advanced(by: byteCount &- newCount)
676718
return Self(_unchecked: newStart, byteCount: newCount)
@@ -692,8 +734,9 @@ extension RawSpan {
692734
/// - Complexity: O(1)
693735
@_disallowFeatureSuppression(NonescapableTypes)
694736
@_alwaysEmitIntoClient
737+
@lifetime(self)
695738
public func _extracting(droppingFirst k: Int) -> Self {
696-
_precondition(k >= 0, "Can't drop a negative number of elements.")
739+
_precondition(k >= 0, "Can't drop a negative number of elements")
697740
let droppedCount = min(k, byteCount)
698741
let newStart = _pointer?.advanced(by: droppedCount)
699742
return Self(_unchecked: newStart, byteCount: byteCount &- droppedCount)

0 commit comments

Comments
 (0)