Skip to content

Commit 2ed85ad

Browse files
committed
[stdlib] add extracting() to MutableSpan and MutableRawSpan
1 parent fc9e574 commit 2ed85ad

File tree

2 files changed

+457
-0
lines changed

2 files changed

+457
-0
lines changed

stdlib/public/core/Span/MutableRawSpan.swift

+228
Original file line numberDiff line numberDiff line change
@@ -417,3 +417,231 @@ extension MutableRawSpan {
417417
update(startingAt: byteOffset, from: source.bytes)
418418
}
419419
}
420+
421+
// MARK: sub-spans
422+
@available(SwiftStdlib 6.2, *)
423+
extension MutableRawSpan {
424+
425+
/// Constructs a new span over the items within the supplied range of
426+
/// positions within this span.
427+
///
428+
/// The returned span's first item is always at offset 0; unlike buffer
429+
/// slices, extracted spans do not share their indices with the
430+
/// span from which they are extracted.
431+
///
432+
/// - Parameter bounds: A valid range of positions. Every position in
433+
/// this range must be within the bounds of this `MutableSpan`.
434+
///
435+
/// - Returns: A `MutableSpan` over the items within `bounds`
436+
///
437+
/// - Complexity: O(1)
438+
@_alwaysEmitIntoClient
439+
@lifetime(borrow self)
440+
mutating public func _extracting(_ bounds: Range<Int>) -> Self {
441+
_precondition(
442+
UInt(bitPattern: bounds.lowerBound) <= UInt(bitPattern: _count) &&
443+
UInt(bitPattern: bounds.upperBound) <= UInt(bitPattern: _count),
444+
"Index range out of bounds"
445+
)
446+
return _extracting(unchecked: bounds)
447+
}
448+
449+
/// Constructs a new span over the items within the supplied range of
450+
/// positions within this span.
451+
///
452+
/// The returned span's first item is always at offset 0; unlike buffer
453+
/// slices, extracted spans do not share their indices with the
454+
/// span from which they are extracted.
455+
///
456+
/// This function does not validate `bounds`; this is an unsafe operation.
457+
///
458+
/// - Parameter bounds: A valid range of positions. Every position in
459+
/// this range must be within the bounds of this `MutableSpan`.
460+
///
461+
/// - Returns: A `MutableSpan` over the items within `bounds`
462+
///
463+
/// - Complexity: O(1)
464+
@unsafe
465+
@_alwaysEmitIntoClient
466+
@lifetime(borrow self)
467+
mutating public func _extracting(unchecked bounds: Range<Int>) -> Self {
468+
let newStart = _pointer?.advanced(by: bounds.lowerBound)
469+
let newSpan = Self(_unchecked: newStart, byteCount: bounds.count)
470+
return _overrideLifetime(newSpan, mutating: &self)
471+
}
472+
473+
/// Constructs a new span over the items within the supplied range of
474+
/// positions within this span.
475+
///
476+
/// The returned span's first item is always at offset 0; unlike buffer
477+
/// slices, extracted spans do not share their indices with the
478+
/// span from which they are extracted.
479+
///
480+
/// - Parameter bounds: A valid range of positions. Every position in
481+
/// this range must be within the bounds of this `MutableSpan`.
482+
///
483+
/// - Returns: A `MutableSpan` over the items within `bounds`
484+
///
485+
/// - Complexity: O(1)
486+
@_alwaysEmitIntoClient
487+
@lifetime(borrow self)
488+
mutating public func _extracting(
489+
_ bounds: some RangeExpression<Int>
490+
) -> Self {
491+
_extracting(bounds.relative(to: byteOffsets).clamped(to: byteOffsets))
492+
}
493+
494+
/// Constructs a new span over the items within the supplied range of
495+
/// positions within this span.
496+
///
497+
/// The returned span's first item is always at offset 0; unlike buffer
498+
/// slices, extracted spans do not share their indices with the
499+
/// span from which they are extracted.
500+
///
501+
/// This function does not validate `bounds`; this is an unsafe operation.
502+
///
503+
/// - Parameter bounds: A valid range of positions. Every position in
504+
/// this range must be within the bounds of this `MutableSpan`.
505+
///
506+
/// - Returns: A `MutableSpan` over the items within `bounds`
507+
///
508+
/// - Complexity: O(1)
509+
@unsafe
510+
@_alwaysEmitIntoClient
511+
@lifetime(borrow self)
512+
mutating public func _extracting(
513+
unchecked bounds: some RangeExpression<Int>
514+
) -> Self {
515+
_extracting(
516+
unchecked: bounds.relative(to: byteOffsets).clamped(to: byteOffsets)
517+
)
518+
}
519+
520+
@_alwaysEmitIntoClient
521+
@lifetime(borrow self)
522+
mutating public func _extracting(
523+
unchecked bounds: ClosedRange<Int>
524+
) -> Self {
525+
let range = Range(
526+
_uncheckedBounds: (bounds.lowerBound, bounds.upperBound&+1)
527+
)
528+
return _extracting(unchecked: range)
529+
}
530+
531+
/// Constructs a new span over all the items of this span.
532+
///
533+
/// The returned span's first item is always at offset 0; unlike buffer
534+
/// slices, extracted spans do not share their indices with the
535+
/// span from which they are extracted.
536+
///
537+
/// - Returns: A `MutableSpan` over all the items of this span.
538+
///
539+
/// - Complexity: O(1)
540+
@_alwaysEmitIntoClient
541+
@lifetime(borrow self)
542+
mutating public func _extracting(_: UnboundedRange) -> Self {
543+
let newSpan = Self(_unchecked: _start(), byteCount: _count)
544+
return _overrideLifetime(newSpan, mutating: &self)
545+
}
546+
}
547+
548+
// MARK: prefixes and suffixes
549+
@available(SwiftStdlib 6.2, *)
550+
extension MutableRawSpan {
551+
552+
/// Returns a span containing the initial elements of this span,
553+
/// up to the specified maximum length.
554+
///
555+
/// If the maximum length exceeds the length of this span,
556+
/// the result contains all the elements.
557+
///
558+
/// The returned span's first item is always at offset 0; unlike buffer
559+
/// slices, extracted spans do not share their indices with the
560+
/// span from which they are extracted.
561+
///
562+
/// - Parameter maxLength: The maximum number of elements to return.
563+
/// `maxLength` must be greater than or equal to zero.
564+
/// - Returns: A span with at most `maxLength` elements.
565+
///
566+
/// - Complexity: O(1)
567+
@_alwaysEmitIntoClient
568+
@lifetime(borrow self)
569+
mutating public func _extracting(first maxLength: Int) -> Self {
570+
_precondition(maxLength >= 0, "Can't have a prefix of negative length")
571+
let newCount = min(maxLength, byteCount)
572+
let newSpan = Self(_unchecked: _pointer, byteCount: newCount)
573+
return _overrideLifetime(newSpan, mutating: &self)
574+
}
575+
576+
/// Returns a span over all but the given number of trailing elements.
577+
///
578+
/// If the number of elements to drop exceeds the number of elements in
579+
/// the span, the result is an empty span.
580+
///
581+
/// The returned span's first item is always at offset 0; unlike buffer
582+
/// slices, extracted spans do not share their indices with the
583+
/// span from which they are extracted.
584+
///
585+
/// - Parameter k: The number of elements to drop off the end of
586+
/// the span. `k` must be greater than or equal to zero.
587+
/// - Returns: A span leaving off the specified number of elements at the end.
588+
///
589+
/// - Complexity: O(1)
590+
@_alwaysEmitIntoClient
591+
@lifetime(borrow self)
592+
mutating public func _extracting(droppingLast k: Int) -> Self {
593+
_precondition(k >= 0, "Can't drop a negative number of elements")
594+
let dropped = min(k, byteCount)
595+
let newSpan = Self(_unchecked: _pointer, byteCount: byteCount &- dropped)
596+
return _overrideLifetime(newSpan, mutating: &self)
597+
}
598+
599+
/// Returns a span containing the final elements of the span,
600+
/// up to the given maximum length.
601+
///
602+
/// If the maximum length exceeds the length of this span,
603+
/// the result contains all the elements.
604+
///
605+
/// The returned span's first item is always at offset 0; unlike buffer
606+
/// slices, extracted spans do not share their indices with the
607+
/// span from which they are extracted.
608+
///
609+
/// - Parameter maxLength: The maximum number of elements to return.
610+
/// `maxLength` must be greater than or equal to zero.
611+
/// - Returns: A span with at most `maxLength` elements.
612+
///
613+
/// - Complexity: O(1)
614+
@_alwaysEmitIntoClient
615+
@lifetime(borrow self)
616+
mutating public func _extracting(last maxLength: Int) -> Self {
617+
_precondition(maxLength >= 0, "Can't have a suffix of negative length")
618+
let newCount = min(maxLength, byteCount)
619+
let newStart = _pointer?.advanced(by: byteCount &- newCount)
620+
let newSpan = Self(_unchecked: newStart, byteCount: newCount)
621+
return _overrideLifetime(newSpan, copying: self)
622+
}
623+
624+
/// Returns a span over all but the given number of initial elements.
625+
///
626+
/// If the number of elements to drop exceeds the number of elements in
627+
/// the span, the result is an empty span.
628+
///
629+
/// The returned span's first item is always at offset 0; unlike buffer
630+
/// slices, extracted spans do not share their indices with the
631+
/// span from which they are extracted.
632+
///
633+
/// - Parameter k: The number of elements to drop from the beginning of
634+
/// the span. `k` must be greater than or equal to zero.
635+
/// - Returns: A span starting after the specified number of elements.
636+
///
637+
/// - Complexity: O(1)
638+
@_alwaysEmitIntoClient
639+
@lifetime(borrow self)
640+
mutating public func _extracting(droppingFirst k: Int) -> Self {
641+
_precondition(k >= 0, "Can't drop a negative number of bytes")
642+
let dropped = min(k, byteCount)
643+
let newStart = _pointer?.advanced(by: dropped)
644+
let newSpan = Self(_unchecked: newStart, byteCount: byteCount &- dropped)
645+
return _overrideLifetime(newSpan, mutating: &self)
646+
}
647+
}

0 commit comments

Comments
 (0)