mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #83000 from glessard/rdar147780495-OutputSpan-updates-62
[SE-0485, 6.2] OutputSpan and OutputRawSpan
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -202,6 +202,8 @@
|
||||
"Span": [
|
||||
"MutableRawSpan.swift",
|
||||
"MutableSpan.swift",
|
||||
"OutputRawSpan.swift",
|
||||
"OutputSpan.swift",
|
||||
"RawSpan.swift",
|
||||
"Span.swift"
|
||||
],
|
||||
|
||||
@@ -296,6 +296,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
|
||||
_storage = 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,108 +360,6 @@ extension MutableRawSpan {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: The functions in this extension crash the SIL optimizer when built inside
|
||||
// the stub. But these declarations don't generate a public symbol anyway.
|
||||
#if !SPAN_COMPATIBILITY_STUB
|
||||
|
||||
//MARK: copyMemory
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension MutableRawSpan {
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update<S: Sequence>(
|
||||
from source: S
|
||||
) -> (unwritten: S.Iterator, byteOffset: Int) where S.Element: BitwiseCopyable {
|
||||
var iterator = source.makeIterator()
|
||||
let offset = update(from: &iterator)
|
||||
return (iterator, offset)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update<Element: BitwiseCopyable>(
|
||||
from elements: inout some IteratorProtocol<Element>
|
||||
) -> Int {
|
||||
var offset = 0
|
||||
while offset + MemoryLayout<Element>.stride <= _count {
|
||||
guard let element = elements.next() else { break }
|
||||
unsafe storeBytes(
|
||||
of: element, toUncheckedByteOffset: offset, as: Element.self
|
||||
)
|
||||
offset &+= MemoryLayout<Element>.stride
|
||||
}
|
||||
return offset
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update<C: Collection>(
|
||||
fromContentsOf source: C
|
||||
) -> Int where C.Element: BitwiseCopyable {
|
||||
let newOffset = source.withContiguousStorageIfAvailable {
|
||||
self.update(fromContentsOf: unsafe RawSpan(_unsafeElements: $0))
|
||||
}
|
||||
if let newOffset { return newOffset }
|
||||
|
||||
var elements = source.makeIterator()
|
||||
let lastOffset = update(from: &elements)
|
||||
_precondition(
|
||||
elements.next() == nil,
|
||||
"destination span cannot contain every element from source."
|
||||
)
|
||||
return lastOffset
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update<Element: BitwiseCopyable>(
|
||||
fromContentsOf source: Span<Element>
|
||||
) -> Int {
|
||||
// update(from: source.bytes)
|
||||
unsafe source.withUnsafeBytes {
|
||||
unsafe update(fromContentsOf: $0)
|
||||
}
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update<Element: BitwiseCopyable>(
|
||||
fromContentsOf source: borrowing MutableSpan<Element>
|
||||
) -> Int {
|
||||
// update(from: source.span.bytes)
|
||||
unsafe source.withUnsafeBytes {
|
||||
unsafe update(fromContentsOf: $0)
|
||||
}
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update(
|
||||
fromContentsOf source: RawSpan
|
||||
) -> Int {
|
||||
_precondition(
|
||||
source.byteCount <= self.byteCount,
|
||||
"destination span cannot contain every byte from source."
|
||||
)
|
||||
if source.byteCount == 0 { return 0 }
|
||||
unsafe source.withUnsafeBytes {
|
||||
unsafe _start().copyMemory(from: $0.baseAddress!, byteCount: $0.count)
|
||||
}
|
||||
return source.byteCount
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update(
|
||||
fromContentsOf source: borrowing MutableRawSpan
|
||||
) -> Int {
|
||||
update(fromContentsOf: source.bytes)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// MARK: sub-spans
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
@@ -482,13 +380,31 @@ extension MutableRawSpan {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(_ bounds: Range<Int>) -> Self {
|
||||
mutating public func _mutatingExtracting(_ bounds: Range<Int>) -> Self {
|
||||
_precondition(
|
||||
UInt(bitPattern: bounds.lowerBound) <= UInt(bitPattern: _count) &&
|
||||
UInt(bitPattern: bounds.upperBound) <= UInt(bitPattern: _count),
|
||||
"Index range out of bounds"
|
||||
)
|
||||
return unsafe extracting(unchecked: bounds)
|
||||
return unsafe _mutatingExtracting(unchecked: bounds)
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(_:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(_ bounds: Range<Int>) -> Self {
|
||||
_mutatingExtracting(bounds)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(_ bounds: Range<Int>) -> Self {
|
||||
_precondition(
|
||||
UInt(bitPattern: bounds.lowerBound) <= UInt(bitPattern: _count) &&
|
||||
UInt(bitPattern: bounds.upperBound) <= UInt(bitPattern: _count),
|
||||
"Index range out of bounds"
|
||||
)
|
||||
return unsafe _consumingExtracting(unchecked: bounds)
|
||||
}
|
||||
|
||||
/// Constructs a new span over the items within the supplied range of
|
||||
@@ -509,12 +425,29 @@ extension MutableRawSpan {
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(unchecked bounds: Range<Int>) -> Self {
|
||||
mutating public func _mutatingExtracting(unchecked bounds: Range<Int>) -> Self {
|
||||
let newStart = unsafe _pointer?.advanced(by: bounds.lowerBound)
|
||||
let newSpan = unsafe Self(_unchecked: newStart, byteCount: bounds.count)
|
||||
return unsafe _overrideLifetime(newSpan, mutating: &self)
|
||||
}
|
||||
|
||||
@unsafe
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(unchecked:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(unchecked bounds: Range<Int>) -> Self {
|
||||
unsafe _mutatingExtracting(unchecked: bounds)
|
||||
}
|
||||
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(unchecked bounds: Range<Int>) -> Self {
|
||||
let newStart = unsafe _pointer?.advanced(by: bounds.lowerBound)
|
||||
let newSpan = unsafe Self(_unchecked: newStart, byteCount: bounds.count)
|
||||
return unsafe _overrideLifetime(newSpan, copying: self)
|
||||
}
|
||||
|
||||
/// Constructs a new span over the items within the supplied range of
|
||||
/// positions within this span.
|
||||
///
|
||||
@@ -530,10 +463,27 @@ extension MutableRawSpan {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func _mutatingExtracting(
|
||||
_ bounds: some RangeExpression<Int>
|
||||
) -> Self {
|
||||
_mutatingExtracting(bounds.relative(to: byteOffsets))
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(_:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(
|
||||
_ bounds: some RangeExpression<Int>
|
||||
) -> Self {
|
||||
extracting(bounds.relative(to: byteOffsets))
|
||||
_mutatingExtracting(bounds)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(
|
||||
_ bounds: some RangeExpression<Int>
|
||||
) -> Self {
|
||||
_consumingExtracting(bounds.relative(to: byteOffsets))
|
||||
}
|
||||
|
||||
/// Constructs a new span over the items within the supplied range of
|
||||
@@ -554,11 +504,35 @@ extension MutableRawSpan {
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(unchecked bounds: ClosedRange<Int>) -> Self {
|
||||
mutating public func _mutatingExtracting(
|
||||
unchecked bounds: ClosedRange<Int>
|
||||
) -> Self {
|
||||
let range = unsafe Range(
|
||||
_uncheckedBounds: (bounds.lowerBound, bounds.upperBound+1)
|
||||
_uncheckedBounds: (bounds.lowerBound, bounds.upperBound + 1)
|
||||
)
|
||||
return unsafe extracting(unchecked: range)
|
||||
return unsafe _mutatingExtracting(unchecked: range)
|
||||
}
|
||||
|
||||
@unsafe
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(unchecked:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(
|
||||
unchecked bounds: ClosedRange<Int>
|
||||
) -> Self {
|
||||
unsafe _mutatingExtracting(unchecked: bounds)
|
||||
}
|
||||
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(
|
||||
unchecked bounds: ClosedRange<Int>
|
||||
) -> Self {
|
||||
let range = unsafe Range(
|
||||
_uncheckedBounds: (bounds.lowerBound, bounds.upperBound + 1)
|
||||
)
|
||||
return unsafe _consumingExtracting(unchecked: range)
|
||||
}
|
||||
|
||||
/// Constructs a new span over all the items of this span.
|
||||
@@ -572,10 +546,23 @@ extension MutableRawSpan {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(_: UnboundedRange) -> Self {
|
||||
mutating public func _mutatingExtracting(_: UnboundedRange) -> Self {
|
||||
let newSpan = unsafe Self(_unchecked: _pointer, byteCount: _count)
|
||||
return unsafe _overrideLifetime(newSpan, mutating: &self)
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(_:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(_: UnboundedRange) -> Self {
|
||||
_mutatingExtracting(...)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(_: UnboundedRange) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: prefixes and suffixes
|
||||
@@ -600,7 +587,7 @@ extension MutableRawSpan {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(first maxLength: Int) -> Self {
|
||||
mutating public func _mutatingExtracting(first maxLength: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(maxLength >= 0, "Can't have a prefix of negative length")
|
||||
let newCount = min(maxLength, byteCount)
|
||||
@@ -611,6 +598,26 @@ extension MutableRawSpan {
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(first:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(first maxLength: Int) -> Self {
|
||||
_mutatingExtracting(first: maxLength)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(first maxLength: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(maxLength >= 0, "Can't have a prefix of negative length")
|
||||
let newCount = min(maxLength, byteCount)
|
||||
let newSpan = unsafe Self(_unchecked: _pointer, byteCount: newCount)
|
||||
return unsafe _overrideLifetime(newSpan, copying: self)
|
||||
#else
|
||||
fatalError("Unsupported compiler")
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns a span over all but the given number of trailing elements.
|
||||
///
|
||||
/// If the number of elements to drop exceeds the number of elements in
|
||||
@@ -627,7 +634,7 @@ extension MutableRawSpan {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(droppingLast k: Int) -> Self {
|
||||
mutating public func _mutatingExtracting(droppingLast k: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(k >= 0, "Can't drop a negative number of elements")
|
||||
let droppedCount = min(k, byteCount)
|
||||
@@ -639,6 +646,27 @@ extension MutableRawSpan {
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(droppingLast:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(droppingLast k: Int) -> Self {
|
||||
_mutatingExtracting(droppingLast: k)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(droppingLast k: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(k >= 0, "Can't drop a negative number of elements")
|
||||
let droppedCount = min(k, byteCount)
|
||||
let newCount = byteCount &- droppedCount
|
||||
let newSpan = unsafe Self(_unchecked: _pointer, byteCount: newCount)
|
||||
return unsafe _overrideLifetime(newSpan, copying: self)
|
||||
#else
|
||||
fatalError("Unsupported compiler")
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns a span containing the final elements of the span,
|
||||
/// up to the given maximum length.
|
||||
///
|
||||
@@ -656,12 +684,37 @@ extension MutableRawSpan {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func _mutatingExtracting(last maxLength: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(maxLength >= 0, "Can't have a suffix of negative length")
|
||||
let newCount = min(maxLength, byteCount)
|
||||
let newStart = unsafe _pointer?.advanced(by: byteCount &- newCount)
|
||||
let newSpan = unsafe Self(_unchecked: newStart, byteCount: newCount)
|
||||
return unsafe _overrideLifetime(newSpan, mutating: &self)
|
||||
#else
|
||||
fatalError("Unsupported compiler")
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(last:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(last maxLength: Int) -> Self {
|
||||
_mutatingExtracting(last: maxLength)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(last maxLength: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(maxLength >= 0, "Can't have a suffix of negative length")
|
||||
let newCount = min(maxLength, byteCount)
|
||||
let newStart = unsafe _pointer?.advanced(by: byteCount &- newCount)
|
||||
let newSpan = unsafe Self(_unchecked: newStart, byteCount: newCount)
|
||||
return unsafe _overrideLifetime(newSpan, copying: self)
|
||||
#else
|
||||
fatalError("Unsupported compiler")
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns a span over all but the given number of initial elements.
|
||||
@@ -680,7 +733,7 @@ extension MutableRawSpan {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(droppingFirst k: Int) -> Self {
|
||||
mutating public func _mutatingExtracting(droppingFirst k: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(k >= 0, "Can't drop a negative number of bytes")
|
||||
let droppedCount = min(k, byteCount)
|
||||
@@ -690,6 +743,28 @@ extension MutableRawSpan {
|
||||
return unsafe _overrideLifetime(newSpan, mutating: &self)
|
||||
#else
|
||||
fatalError("Unsupported compiler")
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(droppingFirst:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(droppingFirst k: Int) -> Self {
|
||||
_mutatingExtracting(droppingFirst: k)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(droppingFirst k: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(k >= 0, "Can't drop a negative number of bytes")
|
||||
let droppedCount = min(k, byteCount)
|
||||
let newStart = unsafe _pointer?.advanced(by: droppedCount)
|
||||
let newCount = byteCount &- droppedCount
|
||||
let newSpan = unsafe Self(_unchecked: newStart, byteCount: newCount)
|
||||
return unsafe _overrideLifetime(newSpan, copying: self)
|
||||
#else
|
||||
fatalError("Unsupported compiler")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,56 +355,6 @@ extension MutableSpan where Element: ~Copyable {
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension MutableSpan where Element: BitwiseCopyable {
|
||||
|
||||
/// Accesses the element at the specified position in the `Span`.
|
||||
///
|
||||
/// - Parameter position: The offset of the element to access. `position`
|
||||
/// must be greater or equal to zero, and less than `count`.
|
||||
///
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
public subscript(_ position: Index) -> Element {
|
||||
get {
|
||||
_precondition(indices.contains(position), "index out of bounds")
|
||||
return unsafe self[unchecked: position]
|
||||
}
|
||||
@lifetime(self: copy self)
|
||||
set {
|
||||
_precondition(indices.contains(position), "index out of bounds")
|
||||
unsafe self[unchecked: position] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/// Accesses the element at the specified position in the `Span`.
|
||||
///
|
||||
/// This subscript does not validate `position`; this is an unsafe operation.
|
||||
///
|
||||
/// - Parameter position: The offset of the element to access. `position`
|
||||
/// must be greater or equal to zero, and less than `count`.
|
||||
///
|
||||
/// - Complexity: O(1)
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
public subscript(unchecked position: Index) -> Element {
|
||||
get {
|
||||
let offset = position&*MemoryLayout<Element>.stride
|
||||
return unsafe _start().loadUnaligned(
|
||||
fromByteOffset: offset, as: Element.self
|
||||
)
|
||||
}
|
||||
@lifetime(self: copy self)
|
||||
set {
|
||||
let offset = position&*MemoryLayout<Element>.stride
|
||||
unsafe _start().storeBytes(
|
||||
of: newValue, toByteOffset: offset, as: Element.self
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension MutableSpan where Element: ~Copyable {
|
||||
@@ -476,220 +426,6 @@ extension MutableSpan {
|
||||
unsafe $0.update(repeating: repeatedValue, count: count)
|
||||
}
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update<S: Sequence>(
|
||||
from source: S
|
||||
) -> (unwritten: S.Iterator, index: Index) where S.Element == Element {
|
||||
var iterator = source.makeIterator()
|
||||
let index = update(from: &iterator)
|
||||
return (iterator, index)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update(
|
||||
from elements: inout some IteratorProtocol<Element>
|
||||
) -> Index {
|
||||
var index = 0
|
||||
while index < _count {
|
||||
guard let element = elements.next() else { break }
|
||||
unsafe self[unchecked: index] = element
|
||||
index &+= 1
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update(
|
||||
fromContentsOf source: some Collection<Element>
|
||||
) -> Index {
|
||||
let updated = source.withContiguousStorageIfAvailable {
|
||||
self.update(fromContentsOf: unsafe Span(_unsafeElements: $0))
|
||||
}
|
||||
if let updated {
|
||||
return updated
|
||||
}
|
||||
|
||||
//TODO: use _copyContents here
|
||||
|
||||
var iterator = source.makeIterator()
|
||||
let index = update(from: &iterator)
|
||||
_precondition(
|
||||
iterator.next() == nil,
|
||||
"destination buffer view cannot contain every element from source."
|
||||
)
|
||||
return index
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update(fromContentsOf source: Span<Element>) -> Index {
|
||||
guard !source.isEmpty else { return 0 }
|
||||
_precondition(
|
||||
source.count <= self.count,
|
||||
"destination span cannot contain every element from source."
|
||||
)
|
||||
unsafe _start().withMemoryRebound(
|
||||
to: Element.self, capacity: source.count
|
||||
) { dest in
|
||||
unsafe source.withUnsafeBufferPointer {
|
||||
unsafe dest.update(from: $0.baseAddress!, count: $0.count)
|
||||
}
|
||||
}
|
||||
return source.count
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update(
|
||||
fromContentsOf source: borrowing MutableSpan<Element>
|
||||
) -> Index {
|
||||
update(fromContentsOf: source.span)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension MutableSpan where Element: ~Copyable {
|
||||
|
||||
// @_alwaysEmitIntoClient
|
||||
// public mutating func moveUpdate(
|
||||
// fromContentsOf source: consuming OutputSpan<Element>
|
||||
// ) -> Index {
|
||||
// guard !source.isEmpty else { return 0 }
|
||||
// _precondition(
|
||||
// source.count <= self.count,
|
||||
// "destination span cannot contain every element from source."
|
||||
// )
|
||||
// let buffer = unsafe source.relinquishBorrowedMemory()
|
||||
// // we must now deinitialize the returned UMBP
|
||||
// unsafe _start().moveInitializeMemory(
|
||||
// as: Element.self, from: buffer.baseAddress!, count: buffer.count
|
||||
// )
|
||||
// return buffer.count
|
||||
// }
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func moveUpdate(
|
||||
fromContentsOf source: UnsafeMutableBufferPointer<Element>
|
||||
) -> Index {
|
||||
// let source = OutputSpan(_initializing: source, initialized: source.count)
|
||||
// return self.moveUpdate(fromContentsOf: source)
|
||||
unsafe withUnsafeMutableBufferPointer {
|
||||
unsafe $0.moveUpdate(fromContentsOf: source)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension MutableSpan {
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func moveUpdate(
|
||||
fromContentsOf source: Slice<UnsafeMutableBufferPointer<Element>>
|
||||
) -> Index {
|
||||
unsafe moveUpdate(fromContentsOf: .init(rebasing: source))
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension MutableSpan where Element: BitwiseCopyable {
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update(
|
||||
repeating repeatedValue: Element
|
||||
) where Element: BitwiseCopyable {
|
||||
guard count > 0 else { return }
|
||||
// rebind _start manually in order to avoid assumptions about alignment.
|
||||
let rp = unsafe _start()._rawValue
|
||||
let binding = Builtin.bindMemory(rp, count._builtinWordValue, Element.self)
|
||||
let rebound = unsafe UnsafeMutablePointer<Element>(rp)
|
||||
unsafe rebound.update(repeating: repeatedValue, count: count)
|
||||
Builtin.rebindMemory(rp, binding)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update<S: Sequence>(
|
||||
from source: S
|
||||
) -> (unwritten: S.Iterator, index: Index)
|
||||
where S.Element == Element, Element: BitwiseCopyable {
|
||||
var iterator = source.makeIterator()
|
||||
let index = update(from: &iterator)
|
||||
return (iterator, index)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update(
|
||||
from elements: inout some IteratorProtocol<Element>
|
||||
) -> Index {
|
||||
var index = 0
|
||||
while index < _count {
|
||||
guard let element = elements.next() else { break }
|
||||
unsafe self[unchecked: index] = element
|
||||
index &+= 1
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update(
|
||||
fromContentsOf source: some Collection<Element>
|
||||
) -> Index where Element: BitwiseCopyable {
|
||||
let updated = source.withContiguousStorageIfAvailable {
|
||||
self.update(fromContentsOf: unsafe Span(_unsafeElements: $0))
|
||||
}
|
||||
if let updated {
|
||||
return updated
|
||||
}
|
||||
|
||||
//TODO: use _copyContents here
|
||||
|
||||
var iterator = source.makeIterator()
|
||||
let index = update(from: &iterator)
|
||||
_precondition(
|
||||
iterator.next() == nil,
|
||||
"destination buffer view cannot contain every element from source."
|
||||
)
|
||||
return index
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update(
|
||||
fromContentsOf source: Span<Element>
|
||||
) -> Index where Element: BitwiseCopyable {
|
||||
guard !source.isEmpty else { return 0 }
|
||||
_precondition(
|
||||
source.count <= self.count,
|
||||
"destination span cannot contain every element from source."
|
||||
)
|
||||
unsafe source.withUnsafeBufferPointer {
|
||||
unsafe _start().copyMemory(
|
||||
from: $0.baseAddress!,
|
||||
byteCount: $0.count &* MemoryLayout<Element>.stride
|
||||
)
|
||||
}
|
||||
return source.count
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func update(
|
||||
fromContentsOf source: borrowing MutableSpan<Element>
|
||||
) -> Index where Element: BitwiseCopyable {
|
||||
update(fromContentsOf: source.span)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: sub-spans
|
||||
@@ -712,13 +448,31 @@ extension MutableSpan where Element: ~Copyable {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(_ bounds: Range<Index>) -> Self {
|
||||
mutating public func _mutatingExtracting(_ bounds: Range<Index>) -> Self {
|
||||
_precondition(
|
||||
UInt(bitPattern: bounds.lowerBound) <= UInt(bitPattern: _count) &&
|
||||
UInt(bitPattern: bounds.upperBound) <= UInt(bitPattern: _count),
|
||||
"Index range out of bounds"
|
||||
)
|
||||
return unsafe extracting(unchecked: bounds)
|
||||
return unsafe _mutatingExtracting(unchecked: bounds)
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(_:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(_ bounds: Range<Index>) -> Self {
|
||||
_mutatingExtracting(bounds)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(_ bounds: Range<Index>) -> Self {
|
||||
_precondition(
|
||||
UInt(bitPattern: bounds.lowerBound) <= UInt(bitPattern: _count) &&
|
||||
UInt(bitPattern: bounds.upperBound) <= UInt(bitPattern: _count),
|
||||
"Index range out of bounds"
|
||||
)
|
||||
return unsafe _consumingExtracting(unchecked: bounds)
|
||||
}
|
||||
|
||||
/// Constructs a new span over the items within the supplied range of
|
||||
@@ -739,13 +493,31 @@ extension MutableSpan where Element: ~Copyable {
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(unchecked bounds: Range<Index>) -> Self {
|
||||
mutating public func _mutatingExtracting(unchecked bounds: Range<Index>) -> Self {
|
||||
let delta = bounds.lowerBound &* MemoryLayout<Element>.stride
|
||||
let newStart = unsafe _pointer?.advanced(by: delta)
|
||||
let newSpan = unsafe Self(_unchecked: newStart, count: bounds.count)
|
||||
return unsafe _overrideLifetime(newSpan, mutating: &self)
|
||||
}
|
||||
|
||||
@unsafe
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(unchecked:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(unchecked bounds: Range<Index>) -> Self {
|
||||
unsafe _mutatingExtracting(unchecked: bounds)
|
||||
}
|
||||
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(unchecked bounds: Range<Index>) -> Self {
|
||||
let delta = bounds.lowerBound &* MemoryLayout<Element>.stride
|
||||
let newStart = unsafe _pointer?.advanced(by: delta)
|
||||
let newSpan = unsafe Self(_unchecked: newStart, count: bounds.count)
|
||||
return unsafe _overrideLifetime(newSpan, copying: self)
|
||||
}
|
||||
|
||||
/// Constructs a new span over the items within the supplied range of
|
||||
/// positions within this span.
|
||||
///
|
||||
@@ -761,10 +533,27 @@ extension MutableSpan where Element: ~Copyable {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func _mutatingExtracting(
|
||||
_ bounds: some RangeExpression<Index>
|
||||
) -> Self {
|
||||
_mutatingExtracting(bounds.relative(to: indices))
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(_:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(
|
||||
_ bounds: some RangeExpression<Index>
|
||||
) -> Self {
|
||||
extracting(bounds.relative(to: indices))
|
||||
_mutatingExtracting(bounds)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(
|
||||
_ bounds: some RangeExpression<Index>
|
||||
) -> Self {
|
||||
_consumingExtracting(bounds.relative(to: indices))
|
||||
}
|
||||
|
||||
/// Constructs a new span over the items within the supplied range of
|
||||
@@ -785,13 +574,35 @@ extension MutableSpan where Element: ~Copyable {
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(
|
||||
mutating public func _mutatingExtracting(
|
||||
unchecked bounds: ClosedRange<Index>
|
||||
) -> Self {
|
||||
let range = unsafe Range(
|
||||
_uncheckedBounds: (bounds.lowerBound, bounds.upperBound&+1)
|
||||
_uncheckedBounds: (bounds.lowerBound, bounds.upperBound + 1)
|
||||
)
|
||||
return unsafe extracting(unchecked: range)
|
||||
return unsafe _mutatingExtracting(unchecked: range)
|
||||
}
|
||||
|
||||
@unsafe
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(unchecked:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(
|
||||
unchecked bounds: ClosedRange<Index>
|
||||
) -> Self {
|
||||
unsafe _mutatingExtracting(unchecked: bounds)
|
||||
}
|
||||
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(
|
||||
unchecked bounds: ClosedRange<Index>
|
||||
) -> Self {
|
||||
let range = unsafe Range(
|
||||
_uncheckedBounds: (bounds.lowerBound, bounds.upperBound + 1)
|
||||
)
|
||||
return unsafe _consumingExtracting(unchecked: range)
|
||||
}
|
||||
|
||||
/// Constructs a new span over all the items of this span.
|
||||
@@ -805,10 +616,23 @@ extension MutableSpan where Element: ~Copyable {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(_: UnboundedRange) -> Self {
|
||||
mutating public func _mutatingExtracting(_: UnboundedRange) -> Self {
|
||||
let newSpan = unsafe Self(_unchecked: _pointer, count: _count)
|
||||
return unsafe _overrideLifetime(newSpan, mutating: &self)
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(_:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(_: UnboundedRange) -> Self {
|
||||
_mutatingExtracting(...)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(_: UnboundedRange) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: prefixes and suffixes
|
||||
@@ -833,7 +657,7 @@ extension MutableSpan where Element: ~Copyable {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(first maxLength: Int) -> Self {
|
||||
mutating public func _mutatingExtracting(first maxLength: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(maxLength >= 0, "Can't have a prefix of negative length")
|
||||
let newCount = min(maxLength, count)
|
||||
@@ -844,6 +668,26 @@ extension MutableSpan where Element: ~Copyable {
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(first:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(first maxLength: Int) -> Self {
|
||||
_mutatingExtracting(first: maxLength)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(first maxLength: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(maxLength >= 0, "Can't have a prefix of negative length")
|
||||
let newCount = min(maxLength, count)
|
||||
let newSpan = unsafe Self(_unchecked: _pointer, count: newCount)
|
||||
return unsafe _overrideLifetime(newSpan, copying: self)
|
||||
#else
|
||||
fatalError("Unsupported compiler")
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns a span over all but the given number of trailing elements.
|
||||
///
|
||||
/// If the number of elements to drop exceeds the number of elements in
|
||||
@@ -860,7 +704,7 @@ extension MutableSpan where Element: ~Copyable {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(droppingLast k: Int) -> Self {
|
||||
mutating public func _mutatingExtracting(droppingLast k: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(k >= 0, "Can't drop a negative number of elements")
|
||||
let droppedCount = min(k, count)
|
||||
@@ -872,6 +716,27 @@ extension MutableSpan where Element: ~Copyable {
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(droppingLast:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(droppingLast k: Int) -> Self {
|
||||
_mutatingExtracting(droppingLast: k)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(droppingLast k: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(k >= 0, "Can't drop a negative number of elements")
|
||||
let droppedCount = min(k, count)
|
||||
let newCount = count &- droppedCount
|
||||
let newSpan = unsafe Self(_unchecked: _pointer, count: newCount)
|
||||
return unsafe _overrideLifetime(newSpan, copying: self)
|
||||
#else
|
||||
fatalError("Unsupported compiler")
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns a span containing the final elements of the span,
|
||||
/// up to the given maximum length.
|
||||
///
|
||||
@@ -889,7 +754,7 @@ extension MutableSpan where Element: ~Copyable {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(last maxLength: Int) -> Self {
|
||||
mutating public func _mutatingExtracting(last maxLength: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(maxLength >= 0, "Can't have a suffix of negative length")
|
||||
let newCount = min(maxLength, count)
|
||||
@@ -902,6 +767,28 @@ extension MutableSpan where Element: ~Copyable {
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(last:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(last maxLength: Int) -> Self {
|
||||
_mutatingExtracting(last: maxLength)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(last maxLength: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(maxLength >= 0, "Can't have a suffix of negative length")
|
||||
let newCount = min(maxLength, count)
|
||||
let offset = (count &- newCount) * MemoryLayout<Element>.stride
|
||||
let newStart = unsafe _pointer?.advanced(by: offset)
|
||||
let newSpan = unsafe Self(_unchecked: newStart, count: newCount)
|
||||
return unsafe _overrideLifetime(newSpan, copying: self)
|
||||
#else
|
||||
fatalError("Unsupported compiler")
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns a span over all but the given number of initial elements.
|
||||
///
|
||||
/// If the number of elements to drop exceeds the number of elements in
|
||||
@@ -918,7 +805,7 @@ extension MutableSpan where Element: ~Copyable {
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(droppingFirst k: Int) -> Self {
|
||||
mutating public func _mutatingExtracting(droppingFirst k: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(k >= 0, "Can't drop a negative number of elements")
|
||||
let droppedCount = min(k, count)
|
||||
@@ -929,6 +816,29 @@ extension MutableSpan where Element: ~Copyable {
|
||||
return unsafe _overrideLifetime(newSpan, mutating: &self)
|
||||
#else
|
||||
fatalError("Unsupported compiler")
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "_mutatingExtracting(droppingFirst:)")
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(&self)
|
||||
mutating public func extracting(droppingFirst k: Int) -> Self {
|
||||
_mutatingExtracting(droppingFirst: k)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(copy self)
|
||||
consuming public func _consumingExtracting(droppingFirst k: Int) -> Self {
|
||||
#if compiler(>=5.3) && hasFeature(SendableCompletionHandlers)
|
||||
_precondition(k >= 0, "Can't drop a negative number of elements")
|
||||
let droppedCount = min(k, count)
|
||||
let offset = droppedCount * MemoryLayout<Element>.stride
|
||||
let newStart = unsafe _pointer?.advanced(by: offset)
|
||||
let newCount = count &- droppedCount
|
||||
let newSpan = unsafe Self(_unchecked: newStart, count: newCount)
|
||||
return unsafe _overrideLifetime(newSpan, copying: self)
|
||||
#else
|
||||
fatalError("Unsupported compiler")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
380
stdlib/public/core/Span/OutputRawSpan.swift
Normal file
380
stdlib/public/core/Span/OutputRawSpan.swift
Normal file
@@ -0,0 +1,380 @@
|
||||
//===--- OutputRawSpan.swift ----------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2025 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
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if SPAN_COMPATIBILITY_STUB
|
||||
import Swift
|
||||
#endif
|
||||
|
||||
// OutputRawSpan is a reference to a contiguous region of memory which starts
|
||||
// some number of initialized bytes, followed by uninitialized memory.
|
||||
@safe
|
||||
@frozen
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
public struct OutputRawSpan: ~Copyable, ~Escapable {
|
||||
@usableFromInline
|
||||
internal let _pointer: UnsafeMutableRawPointer?
|
||||
|
||||
public let capacity: Int
|
||||
|
||||
@usableFromInline
|
||||
internal var _count: Int
|
||||
|
||||
/// Create an OutputRawSpan with zero capacity
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(immortal)
|
||||
public init() {
|
||||
unsafe _pointer = nil
|
||||
capacity = 0
|
||||
_count = 0
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputRawSpan: @unchecked Sendable {}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputRawSpan {
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
@unsafe
|
||||
internal func _start() -> UnsafeMutableRawPointer {
|
||||
unsafe _pointer._unsafelyUnwrappedUnchecked
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
@unsafe
|
||||
internal func _tail() -> UnsafeMutableRawPointer {
|
||||
// NOTE: `_pointer` must be known to be not-nil.
|
||||
unsafe _start().advanced(by: _count)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputRawSpan {
|
||||
/// The number of initialized bytes in this span.
|
||||
@_alwaysEmitIntoClient
|
||||
public var byteCount: Int { _count }
|
||||
|
||||
/// The number of additional bytes that can be appended to this span.
|
||||
@_alwaysEmitIntoClient
|
||||
public var freeCapacity: Int { capacity &- _count }
|
||||
|
||||
/// A Boolean value indicating whether the span is empty.
|
||||
@_alwaysEmitIntoClient
|
||||
public var isEmpty: Bool { _count == 0 }
|
||||
|
||||
/// A Boolean value indicating whether the span is full.
|
||||
@_alwaysEmitIntoClient
|
||||
public var isFull: Bool { _count == capacity }
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputRawSpan {
|
||||
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(borrow buffer)
|
||||
internal init(
|
||||
_uncheckedBuffer buffer: UnsafeMutableRawBufferPointer,
|
||||
initializedCount: Int
|
||||
) {
|
||||
unsafe _pointer = .init(buffer.baseAddress)
|
||||
capacity = buffer.count
|
||||
_count = initializedCount
|
||||
}
|
||||
|
||||
/// Unsafely create an OutputRawSpan over partly-initialized memory.
|
||||
///
|
||||
/// The memory in `buffer` must remain valid throughout the lifetime
|
||||
/// of the newly-created `OutputRawSpan`. Its prefix must contain
|
||||
/// `initializedCount` initialized bytes, followed by uninitialized
|
||||
/// memory.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - buffer: an `UnsafeMutableBufferPointer` to be initialized
|
||||
/// - initializedCount: the number of initialized bytes
|
||||
/// at the beginning of `buffer`.
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(borrow buffer)
|
||||
public init(
|
||||
buffer: UnsafeMutableRawBufferPointer,
|
||||
initializedCount: Int
|
||||
) {
|
||||
if let baseAddress = buffer.baseAddress {
|
||||
_precondition(
|
||||
unsafe baseAddress.advanced(by: buffer.count) >= baseAddress,
|
||||
"Buffer must not wrap around the address space"
|
||||
)
|
||||
}
|
||||
_precondition(
|
||||
0 <= initializedCount && initializedCount <= buffer.count,
|
||||
"OutputSpan count is not within capacity"
|
||||
)
|
||||
unsafe self.init(
|
||||
_uncheckedBuffer: buffer, initializedCount: initializedCount
|
||||
)
|
||||
}
|
||||
|
||||
/// Unsafely create an OutputRawSpan over partly-initialized memory.
|
||||
///
|
||||
/// The memory in `buffer` must remain valid throughout the lifetime
|
||||
/// of the newly-created `OutputRawSpan`. Its prefix must contain
|
||||
/// `initializedCount` initialized bytes, followed by uninitialized
|
||||
/// memory.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - buffer: an `UnsafeMutableBufferPointer` to be initialized
|
||||
/// - initializedCount: the number of initialized bytes
|
||||
/// at the beginning of `buffer`.
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(borrow buffer)
|
||||
public init(
|
||||
buffer: borrowing Slice<UnsafeMutableRawBufferPointer>,
|
||||
initializedCount: Int
|
||||
) {
|
||||
let rebased = unsafe UnsafeMutableRawBufferPointer(rebasing: buffer)
|
||||
let os = unsafe OutputRawSpan(
|
||||
buffer: rebased, initializedCount: initializedCount
|
||||
)
|
||||
self = unsafe _overrideLifetime(os, borrowing: buffer)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputRawSpan {
|
||||
|
||||
/// Append a single byte to this span.
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func append(_ value: UInt8) {
|
||||
_precondition(_count < capacity, "OutputRawSpan capacity overflow")
|
||||
unsafe _tail().storeBytes(of: value, as: UInt8.self)
|
||||
_count &+= 1
|
||||
}
|
||||
|
||||
/// Remove the last byte from this span.
|
||||
@_alwaysEmitIntoClient
|
||||
@discardableResult
|
||||
@lifetime(self: copy self)
|
||||
public mutating func removeLast() -> UInt8 {
|
||||
_precondition(!isEmpty, "OutputRawSpan underflow")
|
||||
_count &-= 1
|
||||
return unsafe _tail().load(as: UInt8.self)
|
||||
}
|
||||
|
||||
/// Remove the last N elements, returning the memory they occupy
|
||||
/// to the uninitialized state.
|
||||
///
|
||||
/// `n` must not be greater than `count`
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func removeLast(_ k: Int) {
|
||||
_precondition(k >= 0, "Can't remove a negative number of bytes")
|
||||
_precondition(k <= _count, "OutputRawSpan underflow")
|
||||
_count &-= k
|
||||
}
|
||||
|
||||
/// Remove all this span's elements and return its memory
|
||||
/// to the uninitialized state.
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func removeAll() {
|
||||
// TODO: Consider an option to zero the `_count` bytes being removed.
|
||||
_count = 0
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: bulk-append functions
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputRawSpan {
|
||||
/// Appends the given value's bytes to this span's bytes.
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func append<T: BitwiseCopyable>(_ value: T, as type: T.Type) {
|
||||
_precondition(
|
||||
MemoryLayout<T>.size <= freeCapacity, "OutputRawSpan capacity overflow"
|
||||
)
|
||||
unsafe _tail().initializeMemory(as: T.self, to: value)
|
||||
_count &+= MemoryLayout<T>.size
|
||||
}
|
||||
|
||||
/// Appends the given value's bytes repeatedly to this span's bytes.
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func append<T: BitwiseCopyable>(
|
||||
repeating repeatedValue: T, count: Int, as type: T.Type
|
||||
) {
|
||||
let total = count * MemoryLayout<T>.stride
|
||||
_precondition(total <= freeCapacity, "OutputRawSpan capacity overflow")
|
||||
unsafe _tail().initializeMemory(
|
||||
as: T.self, repeating: repeatedValue, count: count
|
||||
)
|
||||
_count &+= total
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputRawSpan {
|
||||
/// Borrow the underlying initialized memory for read-only access.
|
||||
@_alwaysEmitIntoClient
|
||||
public var bytes: RawSpan {
|
||||
@lifetime(borrow self)
|
||||
borrowing get {
|
||||
let buffer = unsafe UnsafeRawBufferPointer(start: _pointer, count: _count)
|
||||
let span = unsafe RawSpan(_unsafeBytes: buffer)
|
||||
return unsafe _overrideLifetime(span, borrowing: self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Exclusively borrow the underlying initialized memory for mutation.
|
||||
@_alwaysEmitIntoClient
|
||||
public var mutableBytes: MutableRawSpan {
|
||||
@lifetime(&self)
|
||||
mutating get {
|
||||
let buffer = unsafe UnsafeMutableRawBufferPointer(
|
||||
start: _pointer, count: _count
|
||||
)
|
||||
let span = unsafe MutableRawSpan(_unsafeBytes: buffer)
|
||||
return unsafe _overrideLifetime(span, mutating: &self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputRawSpan {
|
||||
|
||||
/// Call the given closure with the unsafe buffer pointer addressed by this
|
||||
/// OutputRawSpan and a mutable reference to its count of initialized bytes.
|
||||
///
|
||||
/// This method provides a way to process or populate an `OutputRawSpan` using
|
||||
/// unsafe operations, such as dispatching to code written in legacy
|
||||
/// (memory-unsafe) languages.
|
||||
///
|
||||
/// The supplied closure may process the buffer in any way it wants; however,
|
||||
/// when it finishes (whether by returning or throwing), it must leave the
|
||||
/// buffer in a state that satisfies the invariants of the output span:
|
||||
///
|
||||
/// 1. The inout integer passed in as the second argument must be the exact
|
||||
/// number of initialized bytes in the buffer passed in as the first
|
||||
/// argument.
|
||||
/// 2. These initialized elements must be located in a single contiguous
|
||||
/// region starting at the beginning of the buffer. The rest of the buffer
|
||||
/// must hold uninitialized memory.
|
||||
///
|
||||
/// This function cannot verify these two invariants, and therefore
|
||||
/// this is an unsafe operation. Violating the invariants of `OutputRawSpan`
|
||||
/// may result in undefined behavior.
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func withUnsafeMutableBytes<E: Error, R: ~Copyable>(
|
||||
_ body: (
|
||||
UnsafeMutableRawBufferPointer,
|
||||
_ initializedCount: inout Int
|
||||
) throws(E) -> R
|
||||
) throws(E) -> R {
|
||||
guard let start = unsafe _pointer, capacity > 0 else {
|
||||
let buffer = UnsafeMutableRawBufferPointer(_empty: ())
|
||||
var initializedCount = 0
|
||||
defer {
|
||||
_precondition(initializedCount == 0, "OutputRawSpan capacity overflow")
|
||||
}
|
||||
return unsafe try body(buffer, &initializedCount)
|
||||
}
|
||||
#if SPAN_COMPATIBILITY_STUB
|
||||
let buffer = unsafe UnsafeMutableRawBufferPointer(
|
||||
start: start, count: capacity
|
||||
)
|
||||
#else
|
||||
let buffer = unsafe UnsafeMutableRawBufferPointer(
|
||||
_uncheckedStart: start, count: capacity
|
||||
)
|
||||
#endif
|
||||
var initializedCount = _count
|
||||
defer {
|
||||
_precondition(
|
||||
0 <= initializedCount && initializedCount <= capacity,
|
||||
"OutputRawSpan capacity overflow"
|
||||
)
|
||||
_count = initializedCount
|
||||
}
|
||||
return unsafe try body(buffer, &initializedCount)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputRawSpan {
|
||||
/// Consume the output span (relinquishing its control over the buffer it is
|
||||
/// addressing), and return the number of initialized bytes in it.
|
||||
///
|
||||
/// This method should be invoked in the scope where the `OutputRawSpan` was
|
||||
/// created, when it is time to commit the contents of the updated buffer
|
||||
/// back into the construct being initialized.
|
||||
///
|
||||
/// The context that created the output span is expected to remember what
|
||||
/// memory region the span is addressing. This consuming method expects to
|
||||
/// receive a copy of the same buffer pointer as a (loose) proof of ownership.
|
||||
///
|
||||
/// - Parameter buffer: The buffer we expect the `OutputRawSpan` to reference.
|
||||
/// This must be the same region of memory passed to
|
||||
/// the `OutputRawSpan` initializer.
|
||||
/// - Returns: The number of initialized bytes in the same buffer, as
|
||||
/// tracked by the consumed `OutputRawSpan` instance.
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
public consuming func finalize(
|
||||
for buffer: UnsafeMutableRawBufferPointer
|
||||
) -> Int {
|
||||
_precondition(
|
||||
unsafe buffer.baseAddress == self._pointer
|
||||
&& buffer.count == self.capacity,
|
||||
"OutputRawSpan identity mismatch")
|
||||
return _count
|
||||
}
|
||||
|
||||
/// Consume the output span (relinquishing its control over the buffer it is
|
||||
/// addressing), and return the number of initialized bytes in it.
|
||||
///
|
||||
/// This method should be invoked in the scope where the `OutputRawSpan` was
|
||||
/// created, when it is time to commit the contents of the updated buffer
|
||||
/// back into the construct being initialized.
|
||||
///
|
||||
/// The context that created the output span is expected to remember what
|
||||
/// memory region the span is addressing. This consuming method expects to
|
||||
/// receive a copy of the same buffer pointer as a (loose) proof of ownership.
|
||||
///
|
||||
/// - Parameter buffer: The buffer we expect the `OutputRawSpan` to reference.
|
||||
/// This must be the same region of memory passed to
|
||||
/// the `OutputRawSpan` initializer.
|
||||
/// - Returns: The number of initialized bytes in the same buffer, as
|
||||
/// tracked by the consumed `OutputRawSpan` instance.
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
public consuming func finalize(
|
||||
for buffer: Slice<UnsafeMutableRawBufferPointer>
|
||||
) -> Int {
|
||||
let rebased = unsafe UnsafeMutableRawBufferPointer(rebasing: buffer)
|
||||
return unsafe self.finalize(for: rebased)
|
||||
}
|
||||
}
|
||||
497
stdlib/public/core/Span/OutputSpan.swift
Normal file
497
stdlib/public/core/Span/OutputSpan.swift
Normal file
@@ -0,0 +1,497 @@
|
||||
//===--- OutputSpan.swift -------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2024 - 2025 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
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if SPAN_COMPATIBILITY_STUB
|
||||
import Swift
|
||||
#endif
|
||||
|
||||
// `OutputSpan` is a reference to a contiguous region of memory that starts with
|
||||
// some number of initialized `Element` instances followed by uninitialized
|
||||
// memory. It provides operations to access the items it stores, as well as to
|
||||
// add new elements and to remove existing ones.
|
||||
@safe
|
||||
@frozen
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
public struct OutputSpan<Element: ~Copyable>: ~Copyable, ~Escapable {
|
||||
@usableFromInline
|
||||
internal let _pointer: UnsafeMutableRawPointer?
|
||||
|
||||
public let capacity: Int
|
||||
|
||||
@usableFromInline
|
||||
internal var _count: Int
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
deinit {
|
||||
if _count > 0 {
|
||||
unsafe _start().withMemoryRebound(
|
||||
to: Element.self, capacity: _count
|
||||
) {
|
||||
[ workaround = _count ] in
|
||||
_ = unsafe $0.deinitialize(count: workaround)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an OutputSpan with zero capacity
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(immortal)
|
||||
public init() {
|
||||
unsafe _pointer = nil
|
||||
capacity = 0
|
||||
_count = 0
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputSpan: @unchecked Sendable where Element: Sendable & ~Copyable {}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputSpan where Element: ~Copyable {
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
@unsafe
|
||||
internal func _start() -> UnsafeMutableRawPointer {
|
||||
unsafe _pointer._unsafelyUnwrappedUnchecked
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
@unsafe
|
||||
internal func _tail() -> UnsafeMutableRawPointer {
|
||||
// NOTE: `_pointer` must be known to be not-nil.
|
||||
unsafe _start().advanced(by: _count &* MemoryLayout<Element>.stride)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputSpan where Element: ~Copyable {
|
||||
/// The number of initialized elements in this span.
|
||||
@_alwaysEmitIntoClient
|
||||
public var count: Int { _count }
|
||||
|
||||
/// The number of additional elements that can be added to this span.
|
||||
@_alwaysEmitIntoClient
|
||||
public var freeCapacity: Int { capacity &- _count }
|
||||
|
||||
/// A Boolean value indicating whether the span is empty.
|
||||
@_alwaysEmitIntoClient
|
||||
public var isEmpty: Bool { _count == 0 }
|
||||
|
||||
/// A Boolean value indicating whether the span is full.
|
||||
@_alwaysEmitIntoClient
|
||||
public var isFull: Bool { _count == capacity }
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputSpan where Element: ~Copyable {
|
||||
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(borrow buffer)
|
||||
@usableFromInline
|
||||
internal init(
|
||||
_uncheckedBuffer buffer: UnsafeMutableBufferPointer<Element>,
|
||||
initializedCount: Int
|
||||
) {
|
||||
unsafe _pointer = .init(buffer.baseAddress)
|
||||
capacity = buffer.count
|
||||
_count = initializedCount
|
||||
}
|
||||
|
||||
/// Unsafely create an OutputSpan over partly-initialized memory.
|
||||
///
|
||||
/// The memory in `buffer` must remain valid throughout the lifetime
|
||||
/// of the newly-created `OutputSpan`. Its prefix must contain
|
||||
/// `initializedCount` initialized instances, followed by uninitialized
|
||||
/// memory. The default value of `initializedCount` is 0, representing
|
||||
/// the common case of a completely uninitialized `buffer`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - buffer: an `UnsafeMutableBufferPointer` to be initialized
|
||||
/// - initializedCount: the number of initialized elements
|
||||
/// at the beginning of `buffer`.
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(borrow buffer)
|
||||
public init(
|
||||
buffer: UnsafeMutableBufferPointer<Element>,
|
||||
initializedCount: Int
|
||||
) {
|
||||
_precondition(buffer._isWellAligned(), "Misaligned OutputSpan")
|
||||
if let baseAddress = buffer.baseAddress {
|
||||
_precondition(
|
||||
unsafe baseAddress.advanced(by: buffer.count) >= baseAddress,
|
||||
"Buffer must not wrap around the address space"
|
||||
)
|
||||
}
|
||||
_precondition(
|
||||
0 <= initializedCount && initializedCount <= buffer.count,
|
||||
"OutputSpan count is not within capacity"
|
||||
)
|
||||
unsafe self.init(
|
||||
_uncheckedBuffer: buffer, initializedCount: initializedCount
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputSpan {
|
||||
|
||||
/// Unsafely create an OutputSpan over partly-initialized memory.
|
||||
///
|
||||
/// The memory in `buffer` must remain valid throughout the lifetime
|
||||
/// of the newly-created `OutputSpan`. Its prefix must contain
|
||||
/// `initializedCount` initialized instances, followed by uninitialized
|
||||
/// memory. The default value of `initializedCount` is 0, representing
|
||||
/// the common case of a completely uninitialized `buffer`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - buffer: an `UnsafeMutableBufferPointer` to be initialized
|
||||
/// - initializedCount: the number of initialized elements
|
||||
/// at the beginning of `buffer`.
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(borrow buffer)
|
||||
public init(
|
||||
buffer: borrowing Slice<UnsafeMutableBufferPointer<Element>>,
|
||||
initializedCount: Int
|
||||
) {
|
||||
let rebased = unsafe UnsafeMutableBufferPointer(rebasing: buffer)
|
||||
let os = unsafe OutputSpan(
|
||||
buffer: rebased, initializedCount: initializedCount
|
||||
)
|
||||
self = unsafe _overrideLifetime(os, borrowing: buffer)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputSpan where Element: ~Copyable {
|
||||
/// The type that represents an initialized position in an `OutputSpan`.
|
||||
public typealias Index = Int
|
||||
|
||||
/// The range of initialized positions for this `OutputSpan`.
|
||||
@_alwaysEmitIntoClient
|
||||
public var indices: Range<Index> {
|
||||
unsafe Range(_uncheckedBounds: (0, _count))
|
||||
}
|
||||
|
||||
/// Accesses the element at the specified position.
|
||||
///
|
||||
/// - Parameter index: A valid index into this span.
|
||||
///
|
||||
/// - Complexity: O(1)
|
||||
@_alwaysEmitIntoClient
|
||||
public subscript(_ index: Index) -> Element {
|
||||
unsafeAddress {
|
||||
_precondition(indices.contains(index), "index out of bounds")
|
||||
return unsafe UnsafePointer(_unsafeAddressOfElement(unchecked: index))
|
||||
}
|
||||
@lifetime(self: copy self)
|
||||
unsafeMutableAddress {
|
||||
_precondition(indices.contains(index), "index out of bounds")
|
||||
return unsafe _unsafeAddressOfElement(unchecked: index)
|
||||
}
|
||||
}
|
||||
|
||||
/// Accesses the element at the specified position.
|
||||
///
|
||||
/// This subscript does not validate `position`; this is an unsafe operation.
|
||||
///
|
||||
/// - Parameter index: A valid index into this span.
|
||||
///
|
||||
/// - Complexity: O(1)
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
public subscript(unchecked index: Index) -> Element {
|
||||
unsafeAddress {
|
||||
unsafe UnsafePointer(_unsafeAddressOfElement(unchecked: index))
|
||||
}
|
||||
@lifetime(self: copy self)
|
||||
unsafeMutableAddress {
|
||||
unsafe _unsafeAddressOfElement(unchecked: index)
|
||||
}
|
||||
}
|
||||
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
internal func _unsafeAddressOfElement(
|
||||
unchecked index: Index
|
||||
) -> UnsafeMutablePointer<Element> {
|
||||
let elementOffset = index &* MemoryLayout<Element>.stride
|
||||
let address = unsafe _start().advanced(by: elementOffset)
|
||||
return unsafe address.assumingMemoryBound(to: Element.self)
|
||||
}
|
||||
|
||||
/// Exchange the elements at the two given offsets
|
||||
///
|
||||
/// - Parameter i: A valid index into this span.
|
||||
/// - Parameter j: A valid index into this span.
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func swapAt(_ i: Index, _ j: Index) {
|
||||
_precondition(indices.contains(Index(i)))
|
||||
_precondition(indices.contains(Index(j)))
|
||||
unsafe swapAt(unchecked: i, unchecked: j)
|
||||
}
|
||||
|
||||
/// Exchange the elements at the two given offsets
|
||||
///
|
||||
/// This subscript does not validate `i` or `j`; this is an unsafe operation.
|
||||
///
|
||||
/// - Parameter i: A valid index into this span.
|
||||
/// - Parameter j: A valid index into this span.
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func swapAt(unchecked i: Index, unchecked j: Index) {
|
||||
let pi = unsafe _unsafeAddressOfElement(unchecked: i)
|
||||
let pj = unsafe _unsafeAddressOfElement(unchecked: j)
|
||||
let temporary = unsafe pi.move()
|
||||
unsafe pi.initialize(to: pj.move())
|
||||
unsafe pj.initialize(to: consume temporary)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputSpan where Element: ~Copyable {
|
||||
/// Append a single element to this span.
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func append(_ value: consuming Element) {
|
||||
_precondition(_count < capacity, "OutputSpan capacity overflow")
|
||||
unsafe _tail().initializeMemory(as: Element.self, to: value)
|
||||
_count &+= 1
|
||||
}
|
||||
|
||||
/// Remove the last initialized element from this span.
|
||||
///
|
||||
/// Returns the last element. The `OutputSpan` must not be empty.
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func removeLast() -> Element {
|
||||
_precondition(!isEmpty, "OutputSpan underflow")
|
||||
_count &-= 1
|
||||
return unsafe _tail().withMemoryRebound(to: Element.self, capacity: 1) {
|
||||
unsafe $0.move()
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove the last N elements of this span, returning the memory they occupy
|
||||
/// to the uninitialized state.
|
||||
///
|
||||
/// `n` must not be greater than `count`
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func removeLast(_ k: Int) {
|
||||
_precondition(k >= 0, "Can't remove a negative number of elements")
|
||||
_precondition(k <= _count, "OutputSpan underflow")
|
||||
_count &-= k
|
||||
unsafe _tail().withMemoryRebound(to: Element.self, capacity: k) {
|
||||
_ = unsafe $0.deinitialize(count: k)
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove all this span's elements and return its memory
|
||||
/// to the uninitialized state.
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func removeAll() {
|
||||
_ = unsafe _start().withMemoryRebound(to: Element.self, capacity: _count) {
|
||||
unsafe $0.deinitialize(count: _count)
|
||||
}
|
||||
_count = 0
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: bulk-append functions
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputSpan {
|
||||
|
||||
/// Repeatedly append an element to this span.
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func append(repeating repeatedValue: Element, count: Int) {
|
||||
_precondition(count <= freeCapacity, "OutputSpan capacity overflow")
|
||||
unsafe _tail().initializeMemory(
|
||||
as: Element.self, repeating: repeatedValue, count: count
|
||||
)
|
||||
_count &+= count
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputSpan where Element: ~Copyable {
|
||||
/// Borrow the underlying initialized memory for read-only access.
|
||||
@_alwaysEmitIntoClient
|
||||
public var span: Span<Element> {
|
||||
@lifetime(borrow self)
|
||||
borrowing get {
|
||||
let pointer = unsafe _pointer?.assumingMemoryBound(to: Element.self)
|
||||
let buffer = unsafe UnsafeBufferPointer(start: pointer, count: _count)
|
||||
let span = unsafe Span(_unsafeElements: buffer)
|
||||
return unsafe _overrideLifetime(span, borrowing: self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Exclusively borrow the underlying initialized memory for mutation.
|
||||
@_alwaysEmitIntoClient
|
||||
public var mutableSpan: MutableSpan<Element> {
|
||||
@lifetime(&self)
|
||||
mutating get {
|
||||
let pointer = unsafe _pointer?.assumingMemoryBound(to: Element.self)
|
||||
let buffer = unsafe UnsafeMutableBufferPointer(
|
||||
start: pointer, count: _count
|
||||
)
|
||||
let span = unsafe MutableSpan(_unsafeElements: buffer)
|
||||
return unsafe _overrideLifetime(span, mutating: &self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputSpan where Element: ~Copyable {
|
||||
/// Call the given closure with the unsafe buffer pointer addressed by this
|
||||
/// OutputSpan and a mutable reference to its count of initialized elements.
|
||||
///
|
||||
/// This method provides a way to process or populate an `OutputSpan` using
|
||||
/// unsafe operations, such as dispatching to code written in legacy
|
||||
/// (memory-unsafe) languages.
|
||||
///
|
||||
/// The supplied closure may process the buffer in any way it wants; however,
|
||||
/// when it finishes (whether by returning or throwing), it must leave the
|
||||
/// buffer in a state that satisfies the invariants of the output span:
|
||||
///
|
||||
/// 1. The inout integer passed in as the second argument must be the exact
|
||||
/// number of initialized items in the buffer passed in as the first
|
||||
/// argument.
|
||||
/// 2. These initialized elements must be located in a single contiguous
|
||||
/// region starting at the beginning of the buffer. The rest of the buffer
|
||||
/// must hold uninitialized memory.
|
||||
///
|
||||
/// This function cannot verify these two invariants, and therefore
|
||||
/// this is an unsafe operation. Violating the invariants of `OutputSpan`
|
||||
/// may result in undefined behavior.
|
||||
@_alwaysEmitIntoClient
|
||||
@lifetime(self: copy self)
|
||||
public mutating func withUnsafeMutableBufferPointer<E: Error, R: ~Copyable>(
|
||||
_ body: (
|
||||
UnsafeMutableBufferPointer<Element>,
|
||||
_ initializedCount: inout Int
|
||||
) throws(E) -> R
|
||||
) throws(E) -> R {
|
||||
guard let start = unsafe _pointer, capacity > 0 else {
|
||||
let buffer = UnsafeMutableBufferPointer<Element>(_empty: ())
|
||||
var initializedCount = 0
|
||||
defer {
|
||||
_precondition(initializedCount == 0, "OutputSpan capacity overflow")
|
||||
}
|
||||
return unsafe try body(buffer, &initializedCount)
|
||||
}
|
||||
// bind memory by hand to sidestep alignment concerns
|
||||
let binding = Builtin.bindMemory(
|
||||
start._rawValue, capacity._builtinWordValue, Element.self
|
||||
)
|
||||
defer { Builtin.rebindMemory(start._rawValue, binding) }
|
||||
#if SPAN_COMPATIBILITY_STUB
|
||||
let buffer = unsafe UnsafeMutableBufferPointer<Element>(
|
||||
start: .init(start._rawValue), count: capacity
|
||||
)
|
||||
#else
|
||||
let buffer = unsafe UnsafeMutableBufferPointer<Element>(
|
||||
_uncheckedStart: .init(start._rawValue), count: capacity
|
||||
)
|
||||
#endif
|
||||
var initializedCount = self._count
|
||||
defer {
|
||||
_precondition(
|
||||
0 <= initializedCount && initializedCount <= capacity,
|
||||
"OutputSpan capacity overflow"
|
||||
)
|
||||
self._count = initializedCount
|
||||
}
|
||||
return unsafe try body(buffer, &initializedCount)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputSpan where Element: ~Copyable {
|
||||
/// Consume the output span and return the number of initialized elements.
|
||||
///
|
||||
/// This method should be invoked in the scope where the `OutputSpan` was
|
||||
/// created, when it is time to commit the contents of the updated buffer
|
||||
/// back into the construct being initialized.
|
||||
///
|
||||
/// The context that created the output span is expected to remember what
|
||||
/// memory region the span is addressing. This consuming method expects to
|
||||
/// receive a copy of the same buffer pointer as a (loose) proof of ownership.
|
||||
///
|
||||
/// - Parameter buffer: The buffer we expect the `OutputSpan` to reference.
|
||||
/// This must be the same region of memory passed to
|
||||
/// the `OutputSpan` initializer.
|
||||
/// - Returns: The number of initialized elements in the same buffer, as
|
||||
/// tracked by the consumed `OutputSpan` instance.
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
public consuming func finalize(
|
||||
for buffer: UnsafeMutableBufferPointer<Element>
|
||||
) -> Int {
|
||||
_precondition(
|
||||
unsafe UnsafeMutableRawPointer(buffer.baseAddress) == self._pointer
|
||||
&& buffer.count == self.capacity,
|
||||
"OutputSpan identity mismatch"
|
||||
)
|
||||
let count = self._count
|
||||
discard self
|
||||
return count
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftCompatibilitySpan 5.0, *)
|
||||
@_originallyDefinedIn(module: "Swift;CompatibilitySpan", SwiftCompatibilitySpan 6.2)
|
||||
extension OutputSpan {
|
||||
/// Consume the output span and return the number of initialized elements.
|
||||
///
|
||||
/// This method should be invoked in the scope where the `OutputSpan` was
|
||||
/// created, when it is time to commit the contents of the updated buffer
|
||||
/// back into the construct being initialized.
|
||||
///
|
||||
/// The context that created the output span is expected to remember what
|
||||
/// memory region the span is addressing. This consuming method expects to
|
||||
/// receive a copy of the same buffer pointer as a (loose) proof of ownership.
|
||||
///
|
||||
/// - Parameter buffer: The buffer we expect the `OutputSpan` to reference.
|
||||
/// This must be the same region of memory passed to
|
||||
/// the `OutputSpan` initializer.
|
||||
/// - Returns: The number of initialized elements in the same buffer, as
|
||||
/// tracked by the consumed `OutputSpan` instance.
|
||||
@unsafe
|
||||
@_alwaysEmitIntoClient
|
||||
public consuming func finalize(
|
||||
for buffer: Slice<UnsafeMutableBufferPointer<Element>>
|
||||
) -> Int {
|
||||
unsafe finalize(for: UnsafeMutableBufferPointer(rebasing: buffer))
|
||||
}
|
||||
}
|
||||
@@ -795,6 +795,15 @@ extension Unsafe${Mutable}BufferPointer:
|
||||
% end
|
||||
}
|
||||
|
||||
extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
|
||||
@safe
|
||||
@_alwaysEmitIntoClient
|
||||
public func _isWellAligned() -> Bool {
|
||||
guard let p = baseAddress else { return true }
|
||||
return p._isWellAligned()
|
||||
}
|
||||
}
|
||||
|
||||
extension Unsafe${Mutable}BufferPointer {
|
||||
% if not Mutable:
|
||||
/// Creates a buffer over the same memory as the given buffer slice.
|
||||
|
||||
@@ -469,6 +469,13 @@ extension UnsafePointer where Pointee: ~Copyable {
|
||||
}
|
||||
}
|
||||
|
||||
extension UnsafePointer where Pointee: ~Copyable {
|
||||
@safe
|
||||
@_alwaysEmitIntoClient
|
||||
public func _isWellAligned() -> Bool {
|
||||
(Int(bitPattern: self) & (MemoryLayout<Pointee>.alignment &- 1)) == 0
|
||||
}
|
||||
}
|
||||
|
||||
/// A pointer for accessing and manipulating data of a
|
||||
/// specific type.
|
||||
@@ -1382,3 +1389,11 @@ extension UnsafeMutablePointer where Pointee: ~Copyable {
|
||||
)._unsafelyUnwrappedUnchecked
|
||||
}
|
||||
}
|
||||
|
||||
extension UnsafeMutablePointer where Pointee: ~Copyable {
|
||||
@safe
|
||||
@_alwaysEmitIntoClient
|
||||
public func _isWellAligned() -> Bool {
|
||||
(Int(bitPattern: self) & (MemoryLayout<Pointee>.alignment &- 1)) == 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,17 @@ public struct Unsafe${Mutable}RawBufferPointer {
|
||||
@usableFromInline
|
||||
internal let _position, _end: Unsafe${Mutable}RawPointer?
|
||||
|
||||
// This works around _debugPrecondition() impacting the performance of
|
||||
// optimized code. (rdar://72246338)
|
||||
@_alwaysEmitIntoClient
|
||||
internal init(
|
||||
@_nonEphemeral _uncheckedStart start: Unsafe${Mutable}RawPointer?,
|
||||
count: Int
|
||||
) {
|
||||
unsafe _position = start
|
||||
unsafe _end = start.map { unsafe $0 + _assumeNonNegative(count) }
|
||||
}
|
||||
|
||||
/// Creates a buffer over the specified number of contiguous bytes starting
|
||||
/// at the given pointer.
|
||||
///
|
||||
@@ -116,9 +127,14 @@ public struct Unsafe${Mutable}RawBufferPointer {
|
||||
_debugPrecondition(count >= 0, "${Self} with negative count")
|
||||
_debugPrecondition(unsafe count == 0 || start != nil,
|
||||
"${Self} has a nil start and nonzero count")
|
||||
unsafe self.init(_uncheckedStart: start, count: count)
|
||||
}
|
||||
|
||||
unsafe _position = start
|
||||
unsafe _end = start.map { unsafe $0 + _assumeNonNegative(count) }
|
||||
@safe
|
||||
@_alwaysEmitIntoClient
|
||||
public init(_empty: ()) {
|
||||
unsafe _position = nil
|
||||
unsafe _end = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND DEFINED SWIFT_STDLIB_LIBRARY_BUILD_TY
|
||||
FakeStdlib.swift
|
||||
../../public/core/Span/MutableRawSpan.swift
|
||||
../../public/core/Span/MutableSpan.swift
|
||||
../../public/core/Span/OutputRawSpan.swift
|
||||
../../public/core/Span/OutputSpan.swift
|
||||
../../public/core/Span/RawSpan.swift
|
||||
../../public/core/Span/Span.swift
|
||||
|
||||
|
||||
@@ -927,6 +927,23 @@ Added: _$ss14MutableRawSpanVN
|
||||
Added: _$sSS8UTF8ViewV4spans4SpanVys5UInt8VGvg
|
||||
Added: _$sSs8UTF8ViewV4spans4SpanVys5UInt8VGvg
|
||||
|
||||
// OutputSpan
|
||||
Added: _$ss10OutputSpanVMa
|
||||
Added: _$ss10OutputSpanVMn
|
||||
Added: _$ss10OutputSpanVsRi_zrlE6_countSivM
|
||||
Added: _$ss10OutputSpanVsRi_zrlE6_countSivg
|
||||
Added: _$ss10OutputSpanVsRi_zrlE6_countSivs
|
||||
Added: _$ss10OutputSpanVsRi_zrlE8_pointerSvSgvg
|
||||
Added: _$ss10OutputSpanVsRi_zrlE8capacitySivg
|
||||
Added: _$ss13OutputRawSpanV6_countSivM
|
||||
Added: _$ss13OutputRawSpanV6_countSivg
|
||||
Added: _$ss13OutputRawSpanV6_countSivs
|
||||
Added: _$ss13OutputRawSpanV8_pointerSvSgvg
|
||||
Added: _$ss13OutputRawSpanV8capacitySivg
|
||||
Added: _$ss13OutputRawSpanVMa
|
||||
Added: _$ss13OutputRawSpanVMn
|
||||
Added: _$ss13OutputRawSpanVN
|
||||
|
||||
// _SwiftifyInfo enum for _SwiftifyImports macro
|
||||
Added: _$ss13_SwiftifyExprO5paramyABSicABmFWC
|
||||
Added: _$ss13_SwiftifyExprO6returnyA2BmFWC
|
||||
@@ -1048,6 +1065,21 @@ Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss14M
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss14MutableRawSpanVMa$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss14MutableRawSpanVMn$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss14MutableRawSpanVN$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVMa$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVMn$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVsRi_zrlE6_countSivM$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVsRi_zrlE6_countSivg$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVsRi_zrlE6_countSivs$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVsRi_zrlE8_pointerSvSgvg$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVsRi_zrlE8capacitySivg$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanV6_countSivM$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanV6_countSivg$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanV6_countSivs$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanV8_pointerSvSgvg$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanV8capacitySivg$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanVMa$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanVMn$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanVN$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss4SpanVMa$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss4SpanVMn$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss4SpanVsRi_zrlE6_countSivg$
|
||||
|
||||
@@ -928,6 +928,23 @@ Added: _$ss14MutableRawSpanVN
|
||||
Added: _$sSS8UTF8ViewV4spans4SpanVys5UInt8VGvg
|
||||
Added: _$sSs8UTF8ViewV4spans4SpanVys5UInt8VGvg
|
||||
|
||||
// OutputSpan
|
||||
Added: _$ss10OutputSpanVMa
|
||||
Added: _$ss10OutputSpanVMn
|
||||
Added: _$ss10OutputSpanVsRi_zrlE6_countSivM
|
||||
Added: _$ss10OutputSpanVsRi_zrlE6_countSivg
|
||||
Added: _$ss10OutputSpanVsRi_zrlE6_countSivs
|
||||
Added: _$ss10OutputSpanVsRi_zrlE8_pointerSvSgvg
|
||||
Added: _$ss10OutputSpanVsRi_zrlE8capacitySivg
|
||||
Added: _$ss13OutputRawSpanV6_countSivM
|
||||
Added: _$ss13OutputRawSpanV6_countSivg
|
||||
Added: _$ss13OutputRawSpanV6_countSivs
|
||||
Added: _$ss13OutputRawSpanV8_pointerSvSgvg
|
||||
Added: _$ss13OutputRawSpanV8capacitySivg
|
||||
Added: _$ss13OutputRawSpanVMa
|
||||
Added: _$ss13OutputRawSpanVMn
|
||||
Added: _$ss13OutputRawSpanVN
|
||||
|
||||
// _SwiftifyInfo enum for _SwiftifyImports macro
|
||||
Added: _$ss13_SwiftifyExprO5paramyABSicABmFWC
|
||||
Added: _$ss13_SwiftifyExprO6returnyA2BmFWC
|
||||
@@ -1048,6 +1065,21 @@ Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss14M
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss14MutableRawSpanVMa$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss14MutableRawSpanVMn$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss14MutableRawSpanVN$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVMa$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVMn$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVsRi_zrlE6_countSivM$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVsRi_zrlE6_countSivg$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVsRi_zrlE6_countSivs$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVsRi_zrlE8_pointerSvSgvg$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss10OutputSpanVsRi_zrlE8capacitySivg$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanV6_countSivM$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanV6_countSivg$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanV6_countSivs$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanV8_pointerSvSgvg$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanV8capacitySivg$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanVMa$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanVMn$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss13OutputRawSpanVN$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss4SpanVMa$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss4SpanVMn$
|
||||
Added: $ld$previous$@rpath/libswiftCompatibilitySpan.dylib$$1$10.14$26.0$_$ss4SpanVsRi_zrlE6_countSivg$
|
||||
|
||||
@@ -168,14 +168,14 @@ enum InlineArrayTests {
|
||||
let error = CancellationError()
|
||||
do {
|
||||
expectDoesNotThrow {
|
||||
let a = try InlineArray<0, String> { _ in throw error }
|
||||
let a = try InlineArray<0, String>({ _ in throw error })
|
||||
_checkInlineArray(a, oracle: [])
|
||||
}
|
||||
_expectThrows {
|
||||
let _ = try InlineArray<1, String> { _ in throw error }
|
||||
let _ = try InlineArray<1, String>({ _ in throw error })
|
||||
}
|
||||
_expectThrows {
|
||||
let _ = try InlineArray<1, any P> { _ in throw error }
|
||||
let _ = try InlineArray<1, any P>({ _ in throw error })
|
||||
}
|
||||
_expectThrows {
|
||||
let _ = try InlineArray<2, String> { index in
|
||||
|
||||
@@ -249,7 +249,7 @@ suite.test("unsafeLoadUnaligned(as:)")
|
||||
a.withUnsafeMutableBytes {
|
||||
var span = MutableRawSpan(_unsafeBytes: $0)
|
||||
|
||||
let suffix = span.extracting(droppingFirst: 2)
|
||||
let suffix = span._mutatingExtracting(droppingFirst: 2)
|
||||
let u0 = suffix.unsafeLoadUnaligned(as: UInt64.self)
|
||||
expectEqual(u0 & 0xff, 2)
|
||||
expectEqual(u0.byteSwapped & 0xff, 9)
|
||||
@@ -281,111 +281,7 @@ suite.test("storeBytes(of:as:)")
|
||||
expectEqual(a[0].bigEndian & 0xffff, 0xffff)
|
||||
}
|
||||
|
||||
suite.test("update(from: some Sequence<some BitwiseCopyable>)")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
))
|
||||
.code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let capacity = 8
|
||||
var a = Array(repeating: Int.max, count: capacity)
|
||||
expectEqual(a.allSatisfy({ $0 == .max }), true)
|
||||
a.withUnsafeMutableBufferPointer {
|
||||
let empty = UnsafeMutableBufferPointer<Int>(start: nil, count: 0)
|
||||
var span = MutableRawSpan(_unsafeElements: empty)
|
||||
var (iterator, updated) = span.update(from: 0..<0)
|
||||
expectNil(iterator.next())
|
||||
expectEqual(updated, 0)
|
||||
|
||||
span = MutableRawSpan(_unsafeElements: $0)
|
||||
(iterator, updated) = span.update(from: 0..<0)
|
||||
expectNil(iterator.next())
|
||||
expectEqual(updated, 0)
|
||||
|
||||
(iterator, updated) = span.update(from: 0..<10000)
|
||||
expectNotNil(iterator.next())
|
||||
expectEqual(updated, capacity*MemoryLayout<Int>.stride)
|
||||
}
|
||||
expectEqual(a.elementsEqual(0..<capacity), true)
|
||||
}
|
||||
|
||||
suite.test("update(from: some Collection<some BitwiseCopyable>)")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
))
|
||||
.code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let capacity = 8
|
||||
var a = Array(repeating: Int.max, count: capacity)
|
||||
let e = Array(EmptyCollection<UInt>())
|
||||
expectEqual(a.allSatisfy({ $0 == .max }), true)
|
||||
a.withUnsafeMutableBytes {
|
||||
let emptyPrefix = $0.prefix(0)
|
||||
var span = MutableRawSpan(_unsafeBytes: emptyPrefix)
|
||||
var updated = span.update(fromContentsOf: e)
|
||||
expectEqual(updated, 0)
|
||||
|
||||
|
||||
updated = span.update(fromContentsOf: AnyCollection(e))
|
||||
expectEqual(updated, 0)
|
||||
|
||||
span = MutableRawSpan(_unsafeBytes: $0)
|
||||
updated = span.update(fromContentsOf: 0..<capacity)
|
||||
expectEqual(updated, capacity*MemoryLayout<Int>.stride)
|
||||
}
|
||||
expectEqual(a.elementsEqual(0..<capacity), true)
|
||||
}
|
||||
|
||||
suite.test("update(fromContentsOf:) (contiguous memory)")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
))
|
||||
.code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let capacity = 8
|
||||
var a = Array(repeating: Int.max, count: capacity)
|
||||
expectEqual(a.allSatisfy({ $0 == .max }), true)
|
||||
a.withUnsafeMutableBytes {
|
||||
var span = MutableRawSpan(_unsafeBytes: $0)
|
||||
let array = Array(0..<capacity)
|
||||
var updated = span.update(fromContentsOf: array.prefix(0))
|
||||
expectEqual(updated, 0)
|
||||
|
||||
updated = span.update(fromContentsOf: array)
|
||||
expectEqual(updated, capacity*MemoryLayout<Int>.stride)
|
||||
}
|
||||
expectEqual(a.elementsEqual(0..<capacity), true)
|
||||
|
||||
a.withUnsafeMutableBytes {
|
||||
var span = MutableRawSpan(_unsafeBytes: $0)
|
||||
var array = Array(repeating: Int.min, count: capacity)
|
||||
array.withUnsafeMutableBytes {
|
||||
let source = MutableRawSpan(_unsafeBytes: $0)
|
||||
let updated = span.update(fromContentsOf: source)
|
||||
expectEqual(updated, capacity*MemoryLayout<Int>.stride)
|
||||
}
|
||||
}
|
||||
expectEqual(a.allSatisfy({ $0 == Int.min }), true)
|
||||
|
||||
a.withUnsafeMutableBytes {
|
||||
var span = MutableRawSpan(_unsafeBytes: $0)
|
||||
let array = Array(0..<capacity)
|
||||
array.withUnsafeBufferPointer {
|
||||
let source = Span(_unsafeElements: $0)
|
||||
let updated = span.update(fromContentsOf: source)
|
||||
expectEqual(updated, capacity*MemoryLayout<Int>.stride)
|
||||
}
|
||||
}
|
||||
expectEqual(a.elementsEqual(0..<capacity), true)
|
||||
}
|
||||
|
||||
suite.test("extracting()")
|
||||
suite.test("_mutatingExtracting()")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
@@ -398,25 +294,54 @@ suite.test("extracting()")
|
||||
b.withUnsafeMutableBytes {
|
||||
var span = MutableRawSpan(_unsafeBytes: $0)
|
||||
|
||||
var sub = span.extracting(0..<2)
|
||||
var sub = span._mutatingExtracting(0..<2)
|
||||
expectEqual(sub.byteCount, 2)
|
||||
expectEqual(sub.unsafeLoad(as: UInt8.self), 0)
|
||||
|
||||
sub = span.extracting(..<2)
|
||||
sub = span._mutatingExtracting(..<2)
|
||||
expectEqual(sub.byteCount, 2)
|
||||
expectEqual(sub.unsafeLoad(as: UInt8.self), 0)
|
||||
|
||||
sub = span.extracting(...)
|
||||
sub = span._mutatingExtracting(...)
|
||||
expectEqual(sub.byteCount, 4)
|
||||
expectEqual(sub.unsafeLoad(as: UInt8.self), 0)
|
||||
|
||||
sub = span.extracting(2...)
|
||||
sub = span._mutatingExtracting(2...)
|
||||
expectEqual(sub.byteCount, 2)
|
||||
expectEqual(sub.unsafeLoad(as: UInt8.self), 2)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("extracting(unchecked:)")
|
||||
suite.test("_consumingExtracting()")
|
||||
.require(.stdlib_6_2).code {
|
||||
|
||||
let c = 16
|
||||
let b = UnsafeMutableRawBufferPointer.allocate(byteCount: c, alignment: c)
|
||||
defer { b.deallocate() }
|
||||
_ = b.initializeMemory(as: UInt8.self, from: 0..<UInt8(c))
|
||||
|
||||
var span = b.mutableBytes
|
||||
span = span._consumingExtracting(0..<2)
|
||||
expectEqual(span.byteCount, 2)
|
||||
expectEqual(span.unsafeLoad(as: UInt8.self), 0)
|
||||
|
||||
span = b.mutableBytes
|
||||
span = span._consumingExtracting(..<2)
|
||||
expectEqual(span.byteCount, 2)
|
||||
expectEqual(span.unsafeLoad(as: UInt8.self), 0)
|
||||
|
||||
span = b.mutableBytes
|
||||
span = span._consumingExtracting(...)
|
||||
expectEqual(span.byteCount, c)
|
||||
expectEqual(span.unsafeLoad(as: UInt8.self), 0)
|
||||
|
||||
span = b.mutableBytes
|
||||
span = span._consumingExtracting(2...)
|
||||
expectEqual(span.byteCount, c-2)
|
||||
expectEqual(span.unsafeLoad(as: UInt8.self), 2)
|
||||
}
|
||||
|
||||
suite.test("_mutatingExtracting(unchecked:)")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
@@ -428,14 +353,28 @@ suite.test("extracting(unchecked:)")
|
||||
var b = (0..<capacity).map(UInt8.init)
|
||||
b.withUnsafeMutableBytes {
|
||||
var span = MutableRawSpan(_unsafeBytes: $0.prefix(8))
|
||||
let beyond = span.extracting(unchecked: 16...23)
|
||||
let beyond = span._mutatingExtracting(unchecked: 16...23)
|
||||
expectEqual(beyond.byteCount, 8)
|
||||
let fromBeyond = beyond.unsafeLoad(as: UInt8.self)
|
||||
expectEqual(fromBeyond, 16)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("extracting prefixes")
|
||||
suite.test("_consumingExtracting(unchecked:)")
|
||||
.require(.stdlib_6_2).code {
|
||||
|
||||
let capacity = 32
|
||||
var b = (0..<capacity).map(UInt8.init)
|
||||
b.withUnsafeMutableBytes {
|
||||
let span = MutableRawSpan(_unsafeBytes: $0.prefix(8))
|
||||
let beyond = span._consumingExtracting(unchecked: 16...23)
|
||||
expectEqual(beyond.byteCount, 8)
|
||||
let fromBeyond = beyond.unsafeLoad(as: UInt8.self)
|
||||
expectEqual(fromBeyond, 16)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("_mutatingExtracting prefixes")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
@@ -450,19 +389,19 @@ suite.test("extracting prefixes")
|
||||
var span = MutableRawSpan(_unsafeBytes: $0)
|
||||
expectEqual(span.byteCount, capacity)
|
||||
|
||||
prefix = span.extracting(first: 1)
|
||||
prefix = span._mutatingExtracting(first: 1)
|
||||
expectEqual(prefix.unsafeLoad(as: UInt8.self), 0)
|
||||
|
||||
prefix = span.extracting(first: capacity)
|
||||
prefix = span._mutatingExtracting(first: capacity)
|
||||
expectEqual(
|
||||
prefix.unsafeLoad(fromByteOffset: capacity-1, as: UInt8.self),
|
||||
UInt8(capacity-1)
|
||||
)
|
||||
|
||||
prefix = span.extracting(droppingLast: capacity)
|
||||
prefix = span._mutatingExtracting(droppingLast: capacity)
|
||||
expectEqual(prefix.isEmpty, true)
|
||||
|
||||
prefix = span.extracting(droppingLast: 1)
|
||||
prefix = span._mutatingExtracting(droppingLast: 1)
|
||||
expectEqual(
|
||||
prefix.unsafeLoad(fromByteOffset: capacity-2, as: UInt8.self),
|
||||
UInt8(capacity-2)
|
||||
@@ -473,12 +412,51 @@ suite.test("extracting prefixes")
|
||||
let b = UnsafeMutableRawBufferPointer(start: nil, count: 0)
|
||||
var span = MutableRawSpan(_unsafeBytes: b)
|
||||
expectEqual(span.byteCount, b.count)
|
||||
expectEqual(span.extracting(first: 1).byteCount, b.count)
|
||||
expectEqual(span.extracting(droppingLast: 1).byteCount, b.count)
|
||||
expectEqual(span._mutatingExtracting(first: 1).byteCount, b.count)
|
||||
expectEqual(span._mutatingExtracting(droppingLast: 1).byteCount, b.count)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("extracting suffixes")
|
||||
suite.test("_consumingExtracting prefixes")
|
||||
.require(.stdlib_6_2).code {
|
||||
|
||||
let capacity = 4
|
||||
var a = Array(0..<UInt8(capacity))
|
||||
a.withUnsafeMutableBytes {
|
||||
var span = $0.mutableBytes
|
||||
expectEqual(span.byteCount, capacity)
|
||||
|
||||
span = span._consumingExtracting(first: 1)
|
||||
expectEqual(span.unsafeLoad(as: UInt8.self), 0)
|
||||
|
||||
span = $0.mutableBytes._consumingExtracting(first: capacity)
|
||||
expectEqual(
|
||||
span.unsafeLoad(fromByteOffset: capacity-1, as: UInt8.self),
|
||||
UInt8(capacity-1)
|
||||
)
|
||||
|
||||
span = $0.mutableBytes._consumingExtracting(droppingLast: capacity)
|
||||
expectEqual(span.isEmpty, true)
|
||||
|
||||
span = $0.mutableBytes._consumingExtracting(droppingLast: 1)
|
||||
expectEqual(
|
||||
span.unsafeLoad(fromByteOffset: capacity-2, as: UInt8.self),
|
||||
UInt8(capacity-2)
|
||||
)
|
||||
}
|
||||
|
||||
do {
|
||||
let b = UnsafeMutableRawBufferPointer(start: nil, count: 0)
|
||||
var span = MutableRawSpan(_unsafeBytes: b)
|
||||
expectEqual(span.byteCount, b.count)
|
||||
span = b.mutableBytes._consumingExtracting(first: 1)
|
||||
expectEqual(span.byteCount, b.count)
|
||||
span = b.mutableBytes._consumingExtracting(droppingLast: 1)
|
||||
expectEqual(span.byteCount, b.count)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("_mutatingExtracting suffixes")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
@@ -493,19 +471,19 @@ suite.test("extracting suffixes")
|
||||
var span = MutableRawSpan(_unsafeBytes: $0)
|
||||
expectEqual(span.byteCount, capacity)
|
||||
|
||||
prefix = span.extracting(last: capacity)
|
||||
prefix = span._mutatingExtracting(last: capacity)
|
||||
expectEqual(prefix.unsafeLoad(as: UInt8.self), 0)
|
||||
|
||||
prefix = span.extracting(last: capacity-1)
|
||||
prefix = span._mutatingExtracting(last: capacity-1)
|
||||
expectEqual(prefix.unsafeLoad(as: UInt8.self), 1)
|
||||
|
||||
prefix = span.extracting(last: 1)
|
||||
prefix = span._mutatingExtracting(last: 1)
|
||||
expectEqual(prefix.unsafeLoad(as: UInt8.self), UInt8(capacity-1))
|
||||
|
||||
prefix = span.extracting(droppingFirst: capacity)
|
||||
prefix = span._mutatingExtracting(droppingFirst: capacity)
|
||||
expectTrue(prefix.isEmpty)
|
||||
|
||||
prefix = span.extracting(droppingFirst: 1)
|
||||
prefix = span._mutatingExtracting(droppingFirst: 1)
|
||||
expectEqual(prefix.unsafeLoad(as: UInt8.self), 1)
|
||||
}
|
||||
|
||||
@@ -513,8 +491,44 @@ suite.test("extracting suffixes")
|
||||
let b = UnsafeMutableRawBufferPointer(start: nil, count: 0)
|
||||
var span = MutableRawSpan(_unsafeBytes: b)
|
||||
expectEqual(span.byteCount, b.count)
|
||||
expectEqual(span.extracting(last: 1).byteCount, b.count)
|
||||
expectEqual(span.extracting(droppingFirst: 1).byteCount, b.count)
|
||||
expectEqual(span._mutatingExtracting(last: 1).byteCount, b.count)
|
||||
expectEqual(span._mutatingExtracting(droppingFirst: 1).byteCount, b.count)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("_consumingExtracting suffixes")
|
||||
.require(.stdlib_6_2).code {
|
||||
|
||||
let capacity = 4
|
||||
var a = Array(0..<UInt8(capacity))
|
||||
a.withUnsafeMutableBytes {
|
||||
var span = $0.mutableBytes
|
||||
expectEqual(span.byteCount, capacity)
|
||||
|
||||
span = span._consumingExtracting(last: capacity)
|
||||
expectEqual(span.unsafeLoad(as: UInt8.self), 0)
|
||||
|
||||
span = $0.mutableBytes._consumingExtracting(last: capacity-1)
|
||||
expectEqual(span.unsafeLoad(as: UInt8.self), 1)
|
||||
|
||||
span = $0.mutableBytes._consumingExtracting(last: 1)
|
||||
expectEqual(span.unsafeLoad(as: UInt8.self), UInt8(capacity-1))
|
||||
|
||||
span = $0.mutableBytes._consumingExtracting(droppingFirst: capacity)
|
||||
expectEqual(span.isEmpty, true)
|
||||
|
||||
span = $0.mutableBytes._consumingExtracting(droppingFirst: 1)
|
||||
expectEqual(span.unsafeLoad(as: UInt8.self), 1)
|
||||
}
|
||||
|
||||
do {
|
||||
let b = UnsafeMutableRawBufferPointer(start: nil, count: 0)
|
||||
var span = MutableRawSpan(_unsafeBytes: b)
|
||||
expectEqual(span.byteCount, b.count)
|
||||
span = b.mutableBytes._consumingExtracting(last: 1)
|
||||
expectEqual(span.byteCount, b.count)
|
||||
span = b.mutableBytes._consumingExtracting(droppingFirst: 1)
|
||||
expectEqual(span.byteCount, b.count)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -315,232 +315,6 @@ suite.test("update(repeating:)")
|
||||
expectEqual(a.allSatisfy({ $0.id == .max }), true)
|
||||
}
|
||||
|
||||
suite.test("update(repeating:) - BitwiseCopyable")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
))
|
||||
.code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
var a = Array(0..<8)
|
||||
expectEqual(a.contains(.max), false)
|
||||
a.withUnsafeMutableBufferPointer {
|
||||
var span = MutableSpan(_unsafeElements: $0)
|
||||
span.update(repeating: .max)
|
||||
}
|
||||
expectEqual(a.allSatisfy({ $0 == .max }), true)
|
||||
}
|
||||
|
||||
suite.test("update(from: some Sequence)")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
))
|
||||
.code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let capacity = 8
|
||||
var a = Array(repeating: ID(id: .max), count: capacity)
|
||||
expectEqual(a.allSatisfy({ $0.id == .max }), true)
|
||||
a.withUnsafeMutableBufferPointer {
|
||||
let emptyPrefix = $0.prefix(0)
|
||||
var span = MutableSpan(_unsafeElements: emptyPrefix)
|
||||
var (iterator, updated) = span.update(from: [])
|
||||
expectNil(iterator.next())
|
||||
expectEqual(updated, 0)
|
||||
|
||||
span = MutableSpan(_unsafeElements: $0)
|
||||
(iterator, updated) = span.update(from: [])
|
||||
expectNil(iterator.next())
|
||||
expectEqual(updated, 0)
|
||||
|
||||
(iterator, updated) = span.update(from: (0..<12).map(ID.init(id:)))
|
||||
expectNotNil(iterator.next())
|
||||
expectEqual(updated, capacity)
|
||||
}
|
||||
expectEqual(a.map(\.id).elementsEqual(0..<capacity), true)
|
||||
}
|
||||
|
||||
suite.test("update(from: some Sequence) - BitwiseCopyable")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
))
|
||||
.code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let capacity = 8
|
||||
var a = Array(repeating: Int.max, count: capacity)
|
||||
expectEqual(a.allSatisfy({ $0 == .max }), true)
|
||||
a.withUnsafeMutableBufferPointer {
|
||||
let empty = UnsafeMutableBufferPointer<Int>(start: nil, count: 0)
|
||||
var span = MutableSpan(_unsafeElements: empty)
|
||||
var (iterator, updated) = span.update(from: 0..<0)
|
||||
expectNil(iterator.next())
|
||||
expectEqual(updated, 0)
|
||||
|
||||
span = MutableSpan(_unsafeElements: $0)
|
||||
(iterator, updated) = span.update(from: 0..<0)
|
||||
expectNil(iterator.next())
|
||||
expectEqual(updated, 0)
|
||||
|
||||
(iterator, updated) = span.update(from: 0..<10000)
|
||||
expectNotNil(iterator.next())
|
||||
expectEqual(updated, capacity)
|
||||
}
|
||||
expectEqual(a.elementsEqual(0..<capacity), true)
|
||||
}
|
||||
|
||||
suite.test("update(fromContentsOf: some Collection)")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
))
|
||||
.code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let capacity = 8
|
||||
var a = Array(repeating: ID(id: .max), count: capacity)
|
||||
expectEqual(a.allSatisfy({ $0.id == .max }), true)
|
||||
a.withUnsafeMutableBufferPointer {
|
||||
let emptyPrefix = $0.prefix(0)
|
||||
var span = MutableSpan(_unsafeElements: emptyPrefix)
|
||||
var updated = span.update(fromContentsOf: [])
|
||||
expectEqual(updated, 0)
|
||||
|
||||
updated = span.update(fromContentsOf: AnyCollection([]))
|
||||
expectEqual(updated, 0)
|
||||
|
||||
span = MutableSpan(_unsafeElements: $0)
|
||||
let elements = (0..<capacity).map(ID.init(id:))
|
||||
updated = span.update(fromContentsOf: AnyCollection(elements))
|
||||
expectEqual(updated, capacity)
|
||||
}
|
||||
expectEqual(a.map(\.id).elementsEqual(0..<capacity), true)
|
||||
}
|
||||
|
||||
suite.test("update(fromContentsOf: some Collection) - BitwiseCopyable")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
))
|
||||
.code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let capacity = 8
|
||||
var a = Array(repeating: Int.max, count: capacity)
|
||||
expectEqual(a.allSatisfy({ $0 == .max }), true)
|
||||
a.withUnsafeMutableBufferPointer {
|
||||
let emptyPrefix = $0.prefix(0)
|
||||
var span = MutableSpan(_unsafeElements: emptyPrefix)
|
||||
var updated = span.update(fromContentsOf: [])
|
||||
expectEqual(updated, 0)
|
||||
|
||||
|
||||
updated = span.update(fromContentsOf: AnyCollection([]))
|
||||
expectEqual(updated, 0)
|
||||
|
||||
span = MutableSpan(_unsafeElements: $0)
|
||||
updated = span.update(fromContentsOf: 0..<capacity)
|
||||
expectEqual(updated, capacity)
|
||||
}
|
||||
expectEqual(a.elementsEqual(0..<capacity), true)
|
||||
}
|
||||
|
||||
suite.test("update(fromContentsOf: Span)")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
))
|
||||
.code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let capacity = 8
|
||||
var a = Array(repeating: ID(id: .max), count: capacity)
|
||||
expectEqual(a.allSatisfy({ $0.id == .max }), true)
|
||||
a.withUnsafeMutableBufferPointer {
|
||||
let emptyPrefix = $0.prefix(0)
|
||||
var span = MutableSpan(_unsafeElements: emptyPrefix)
|
||||
let updated = span.update(
|
||||
fromContentsOf: UnsafeBufferPointer(start: nil, count: 0)
|
||||
)
|
||||
expectEqual(updated, 0)
|
||||
|
||||
span = MutableSpan(_unsafeElements: $0)
|
||||
var elements = (0..<capacity).map(ID.init(id:))
|
||||
elements.withUnsafeMutableBufferPointer {
|
||||
let source = MutableSpan(_unsafeElements: $0)
|
||||
let updated = span.update(fromContentsOf: source)
|
||||
expectEqual(updated, capacity)
|
||||
}
|
||||
}
|
||||
expectEqual(a.map(\.id).elementsEqual(0..<capacity), true)
|
||||
}
|
||||
|
||||
suite.test("update(fromContentsOf: Span) - BitwiseCopyable")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
))
|
||||
.code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let capacity = 8
|
||||
var a = Array(repeating: Int.max, count: capacity)
|
||||
expectEqual(a.allSatisfy({ $0 == .max }), true)
|
||||
a.withUnsafeMutableBufferPointer {
|
||||
let emptyPrefix = $0.prefix(0)
|
||||
var span = MutableSpan(_unsafeElements: emptyPrefix)
|
||||
let update = span.update(fromContentsOf: [])
|
||||
expectEqual(update, 0)
|
||||
|
||||
span = MutableSpan(_unsafeElements: $0)
|
||||
var array = Array(0..<capacity)
|
||||
array.withUnsafeMutableBufferPointer {
|
||||
let source = MutableSpan(_unsafeElements: $0)
|
||||
let update = span.update(fromContentsOf: source)
|
||||
expectEqual(update, capacity)
|
||||
}
|
||||
}
|
||||
expectEqual(a.elementsEqual(0..<capacity), true)
|
||||
}
|
||||
|
||||
suite.test("moveUpdate()")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
))
|
||||
.code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let capacity = 8
|
||||
var a = Array(repeating: ID(id: .max), count: capacity)
|
||||
|
||||
a.withUnsafeMutableBufferPointer {
|
||||
var span = MutableSpan(_unsafeElements: $0)
|
||||
let empty = UnsafeMutableBufferPointer(start: $0.baseAddress, count: 0)
|
||||
let updated = span.moveUpdate(fromContentsOf: empty)
|
||||
expectEqual(updated, 0)
|
||||
}
|
||||
expectEqual(a.allSatisfy({ $0.id == .max }), true)
|
||||
|
||||
let b = UnsafeMutableBufferPointer<ID>.allocate(capacity: 2*capacity)
|
||||
let i = b.initialize(fromContentsOf: (0..<2*capacity).map(ID.init(id:)))
|
||||
expectEqual(i, 2*capacity)
|
||||
|
||||
a.withUnsafeMutableBufferPointer {
|
||||
var span = MutableSpan(_unsafeElements: $0)
|
||||
let updated = span.moveUpdate(fromContentsOf: b.suffix(capacity))
|
||||
expectEqual(updated, capacity)
|
||||
}
|
||||
expectEqual(a.map(\.id).elementsEqual(capacity..<2*capacity), true)
|
||||
|
||||
a = []
|
||||
b.prefix(capacity).deinitialize()
|
||||
b.deallocate()
|
||||
}
|
||||
|
||||
suite.test("span property")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
@@ -596,7 +370,7 @@ suite.test("swapAt")
|
||||
expectEqual(array, (0..<count).reversed())
|
||||
}
|
||||
|
||||
suite.test("extracting()")
|
||||
suite.test("_mutatingExtracting()")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
@@ -609,25 +383,54 @@ suite.test("extracting()")
|
||||
b.withUnsafeMutableBufferPointer {
|
||||
var span = MutableSpan(_unsafeElements: $0)
|
||||
|
||||
var sub = span.extracting(0..<2)
|
||||
var sub = span._mutatingExtracting(0..<2)
|
||||
expectEqual(sub.count, 2)
|
||||
expectEqual(sub[0], 0)
|
||||
|
||||
sub = span.extracting(..<2)
|
||||
sub = span._mutatingExtracting(..<2)
|
||||
expectEqual(sub.count, 2)
|
||||
expectEqual(sub[0], 0)
|
||||
|
||||
sub = span.extracting(...)
|
||||
sub = span._mutatingExtracting(...)
|
||||
expectEqual(sub.count, 4)
|
||||
expectEqual(sub[0], 0)
|
||||
|
||||
sub = span.extracting(2...)
|
||||
sub = span._mutatingExtracting(2...)
|
||||
expectEqual(sub.count, 2)
|
||||
expectEqual(sub[0], 2)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("extracting(unchecked:)")
|
||||
suite.test("_consumingExtracting()")
|
||||
.require(.stdlib_6_2).code {
|
||||
|
||||
let c = 16
|
||||
let b = UnsafeMutableBufferPointer<Int8>.allocate(capacity: c)
|
||||
defer { b.deallocate() }
|
||||
_ = b.initialize(fromContentsOf: 0..<Int8(c))
|
||||
|
||||
var span = b.mutableSpan
|
||||
span = span._consumingExtracting(0..<2)
|
||||
expectEqual(span.count, 2)
|
||||
expectEqual(span[0], 0)
|
||||
|
||||
span = b.mutableSpan
|
||||
span = span._consumingExtracting(..<2)
|
||||
expectEqual(span.count, 2)
|
||||
expectEqual(span[0], 0)
|
||||
|
||||
span = b.mutableSpan
|
||||
span = span._consumingExtracting(...)
|
||||
expectEqual(span.count, c)
|
||||
expectEqual(span[0], 0)
|
||||
|
||||
span = b.mutableSpan
|
||||
span = span._consumingExtracting(2...)
|
||||
expectEqual(span.count, c-2)
|
||||
expectEqual(span[0], 2)
|
||||
}
|
||||
|
||||
suite.test("_mutatingExtracting(unchecked:)")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
@@ -639,14 +442,27 @@ suite.test("extracting(unchecked:)")
|
||||
var b = (0..<capacity).map(UInt8.init)
|
||||
b.withUnsafeMutableBufferPointer {
|
||||
var span = MutableSpan(_unsafeElements: $0.prefix(8))
|
||||
let beyond = span.extracting(unchecked: 16...23)
|
||||
let beyond = span._mutatingExtracting(unchecked: 16...23)
|
||||
expectEqual(beyond.count, 8)
|
||||
let fromBeyond = beyond[0]
|
||||
expectEqual(fromBeyond, 16)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("extracting prefixes")
|
||||
suite.test("_consumingExtracting(unchecked:)")
|
||||
.require(.stdlib_6_2).code {
|
||||
|
||||
let capacity = 32
|
||||
var b = (0..<capacity).map(UInt8.init)
|
||||
b.withUnsafeMutableBufferPointer {
|
||||
let span = MutableSpan(_unsafeElements: $0.prefix(8))
|
||||
let beyond = span._consumingExtracting(unchecked: 16...23)
|
||||
expectEqual(beyond.count, 8)
|
||||
expectEqual(beyond[0], 16)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("_mutatingExtracting prefixes")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
@@ -661,16 +477,16 @@ suite.test("extracting prefixes")
|
||||
var span = MutableSpan(_unsafeElements: $0)
|
||||
expectEqual(span.count, capacity)
|
||||
|
||||
prefix = span.extracting(first: 1)
|
||||
prefix = span._mutatingExtracting(first: 1)
|
||||
expectEqual(prefix[0], 0)
|
||||
|
||||
prefix = span.extracting(first: capacity)
|
||||
prefix = span._mutatingExtracting(first: capacity)
|
||||
expectEqual(prefix[capacity-1], UInt8(capacity-1))
|
||||
|
||||
prefix = span.extracting(droppingLast: capacity)
|
||||
prefix = span._mutatingExtracting(droppingLast: capacity)
|
||||
expectEqual(prefix.isEmpty, true)
|
||||
|
||||
prefix = span.extracting(droppingLast: 1)
|
||||
prefix = span._mutatingExtracting(droppingLast: 1)
|
||||
expectEqual(prefix[capacity-2], UInt8(capacity-2))
|
||||
}
|
||||
|
||||
@@ -678,12 +494,46 @@ suite.test("extracting prefixes")
|
||||
let b = UnsafeMutableBufferPointer<Int>(start: nil, count: 0)
|
||||
var span = MutableSpan(_unsafeElements: b)
|
||||
expectEqual(span.count, b.count)
|
||||
expectEqual(span.extracting(first: 1).count, b.count)
|
||||
expectEqual(span.extracting(droppingLast: 1).count, b.count)
|
||||
expectEqual(span._mutatingExtracting(first: 1).count, b.count)
|
||||
expectEqual(span._mutatingExtracting(droppingLast: 1).count, b.count)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("extracting suffixes")
|
||||
suite.test("_consumingExtracting prefixes")
|
||||
.require(.stdlib_6_2).code {
|
||||
|
||||
let capacity = 4
|
||||
var a = Array(0..<capacity)
|
||||
a.withUnsafeMutableBufferPointer {
|
||||
var span = $0.mutableSpan
|
||||
expectEqual(span.count, capacity)
|
||||
|
||||
span = span._consumingExtracting(first: 1)
|
||||
expectEqual(span.count, 1)
|
||||
expectEqual(span[0], 0)
|
||||
|
||||
span = $0.mutableSpan._consumingExtracting(first: capacity)
|
||||
expectEqual(span[capacity-1], capacity-1)
|
||||
|
||||
span = $0.mutableSpan._consumingExtracting(droppingLast: capacity)
|
||||
expectEqual(span.isEmpty, true)
|
||||
|
||||
span = $0.mutableSpan._consumingExtracting(droppingLast: 1)
|
||||
expectEqual(span[capacity-2], capacity-2)
|
||||
}
|
||||
|
||||
do {
|
||||
let b = UnsafeMutableBufferPointer<Int>(start: nil, count: 0)
|
||||
var span = b.mutableSpan
|
||||
expectEqual(span.count, b.count)
|
||||
span = b.mutableSpan._consumingExtracting(first: 1)
|
||||
expectEqual(span.count, b.count)
|
||||
span = b.mutableSpan._consumingExtracting(droppingLast: 1)
|
||||
expectEqual(span.count, b.count)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("_mutatingExtracting suffixes")
|
||||
.skip(.custom(
|
||||
{ if #available(SwiftStdlib 6.2, *) { false } else { true } },
|
||||
reason: "Requires Swift 6.2's standard library"
|
||||
@@ -698,19 +548,19 @@ suite.test("extracting suffixes")
|
||||
var span = MutableSpan(_unsafeElements: $0)
|
||||
expectEqual(span.count, capacity)
|
||||
|
||||
suffix = span.extracting(last: capacity)
|
||||
suffix = span._mutatingExtracting(last: capacity)
|
||||
expectEqual(suffix[0], 0)
|
||||
|
||||
suffix = span.extracting(last: capacity-1)
|
||||
suffix = span._mutatingExtracting(last: capacity-1)
|
||||
expectEqual(suffix[0], 1)
|
||||
|
||||
suffix = span.extracting(last: 1)
|
||||
suffix = span._mutatingExtracting(last: 1)
|
||||
expectEqual(suffix[0], UInt8(capacity-1))
|
||||
|
||||
suffix = span.extracting(droppingFirst: capacity)
|
||||
suffix = span._mutatingExtracting(droppingFirst: capacity)
|
||||
expectTrue(suffix.isEmpty)
|
||||
|
||||
suffix = span.extracting(droppingFirst: 1)
|
||||
suffix = span._mutatingExtracting(droppingFirst: 1)
|
||||
expectEqual(suffix[0], 1)
|
||||
}
|
||||
|
||||
@@ -718,8 +568,44 @@ suite.test("extracting suffixes")
|
||||
let b = UnsafeMutableBufferPointer<ObjectIdentifier>(start: nil, count: 0)
|
||||
var span = MutableSpan(_unsafeElements: b)
|
||||
expectEqual(span.count, b.count)
|
||||
expectEqual(span.extracting(last: 1).count, b.count)
|
||||
expectEqual(span.extracting(droppingFirst: 1).count, b.count)
|
||||
expectEqual(span._mutatingExtracting(last: 1).count, b.count)
|
||||
expectEqual(span._mutatingExtracting(droppingFirst: 1).count, b.count)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("_consumingExtracting suffixes")
|
||||
.require(.stdlib_6_2).code {
|
||||
|
||||
let capacity = 4
|
||||
var a = Array(0..<capacity)
|
||||
a.withUnsafeMutableBufferPointer {
|
||||
var span = $0.mutableSpan
|
||||
expectEqual(span.count, capacity)
|
||||
|
||||
span = span._consumingExtracting(last: capacity)
|
||||
expectEqual(span[0], 0)
|
||||
|
||||
span = $0.mutableSpan._consumingExtracting(last: capacity-1)
|
||||
expectEqual(span[0], 1)
|
||||
|
||||
span = $0.mutableSpan._consumingExtracting(last: 1)
|
||||
expectEqual(span[0], capacity-1)
|
||||
|
||||
span = $0.mutableSpan._consumingExtracting(droppingFirst: capacity)
|
||||
expectEqual(span.isEmpty, true)
|
||||
|
||||
span = $0.mutableSpan._consumingExtracting(droppingFirst: 1)
|
||||
expectEqual(span[0], 1)
|
||||
}
|
||||
|
||||
do {
|
||||
let b = UnsafeMutableBufferPointer<AnyObject>(start: nil, count: 0)
|
||||
var span = b.mutableSpan
|
||||
expectEqual(span.count, b.count)
|
||||
span = b.mutableSpan._consumingExtracting(last: 1)
|
||||
expectEqual(span.count, b.count)
|
||||
span = b.mutableSpan._consumingExtracting(droppingFirst: 1)
|
||||
expectEqual(span.count, b.count)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
155
test/stdlib/Span/OutputRawSpanTests.swift
Normal file
155
test/stdlib/Span/OutputRawSpanTests.swift
Normal file
@@ -0,0 +1,155 @@
|
||||
//===--- OutputRawSpanTests.swift -----------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2025 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
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// RUN: %target-run-stdlib-swift
|
||||
|
||||
// REQUIRES: executable_test
|
||||
|
||||
import StdlibUnittest
|
||||
|
||||
var suite = TestSuite("OutputRawSpan Tests")
|
||||
defer { runAllTests() }
|
||||
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
struct Allocation: ~Copyable {
|
||||
let allocation: UnsafeMutableRawBufferPointer
|
||||
var byteCount: Int? = nil
|
||||
|
||||
init(byteCount: Int = 1) {
|
||||
precondition(byteCount >= 0)
|
||||
allocation = .allocate(byteCount: byteCount, alignment: 16)
|
||||
}
|
||||
|
||||
var isEmpty: Bool { (byteCount ?? 0) == 0 }
|
||||
|
||||
mutating func initialize<E>(
|
||||
_ body: (inout OutputRawSpan) throws(E) -> Void
|
||||
) throws(E) {
|
||||
if byteCount != nil { fatalError() }
|
||||
var outputBuffer = OutputRawSpan(buffer: allocation, initializedCount: 0)
|
||||
do {
|
||||
try body(&outputBuffer)
|
||||
let initialized = outputBuffer.finalize(for: allocation)
|
||||
byteCount = initialized
|
||||
}
|
||||
catch {
|
||||
outputBuffer.removeAll()
|
||||
let initialized = outputBuffer.finalize(for: allocation)
|
||||
assert(initialized == 0)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
borrowing func withSpan<E, R: ~Copyable>(
|
||||
_ body: (borrowing RawSpan) throws(E) -> R
|
||||
) throws(E) -> R {
|
||||
try body(RawSpan(_unsafeBytes: allocation[0..<(byteCount ?? 0)]))
|
||||
}
|
||||
|
||||
deinit {
|
||||
allocation.deallocate()
|
||||
}
|
||||
}
|
||||
|
||||
enum MyTestError: Error { case error }
|
||||
|
||||
suite.test("Create OutputRawSpan")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let c = 48
|
||||
let allocation = UnsafeMutableRawBufferPointer.allocate(byteCount: c, alignment: 16)
|
||||
defer { allocation.deallocate() }
|
||||
|
||||
let ob = unsafe OutputRawSpan(buffer: allocation, initializedCount: 0)
|
||||
let initialized = ob.finalize(for: allocation)
|
||||
expectEqual(initialized, 0)
|
||||
}
|
||||
|
||||
suite.test("deinit without relinquishing memory")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let c = 48
|
||||
let allocation = UnsafeMutableRawBufferPointer.allocate(byteCount: c, alignment: 16)
|
||||
defer { allocation.deallocate() }
|
||||
|
||||
var ob = unsafe OutputRawSpan(buffer: allocation, initializedCount: 0)
|
||||
// OutputRawSpan(buffer: Slice(base: allocation, bounds: 0..<c))
|
||||
ob.append(repeating: 65, count: 12, as: UInt8.self)
|
||||
expectEqual(ob.byteCount, 12)
|
||||
_ = ob
|
||||
}
|
||||
|
||||
suite.test("append single elements")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
var a = Allocation(byteCount: 48)
|
||||
let c = 10
|
||||
a.initialize {
|
||||
for i in 0...c {
|
||||
$0.append(UInt8(i))
|
||||
}
|
||||
let oops = $0.removeLast()
|
||||
expectEqual(Int(oops), c)
|
||||
}
|
||||
expectNotNil(a.byteCount)
|
||||
expectEqual(a.byteCount, c)
|
||||
a.withSpan {
|
||||
expectEqual($0.byteCount, c)
|
||||
for o in $0.byteOffsets {
|
||||
expectEqual(Int($0.unsafeLoad(fromByteOffset: o, as: UInt8.self)), o)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("initialize buffer with repeated elements")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
var a = Allocation(byteCount: 48)
|
||||
let c = UInt8(10)
|
||||
a.initialize {
|
||||
$0.append(repeating: c, count: Int(c), as: UInt8.self)
|
||||
let oops = $0.removeLast()
|
||||
expectEqual(oops, c)
|
||||
expectEqual($0.byteCount, Int(c-1))
|
||||
}
|
||||
a.withSpan {
|
||||
expectEqual($0.byteCount, Int(c-1))
|
||||
for o in $0.byteOffsets {
|
||||
expectEqual($0.unsafeLoad(fromByteOffset: o, as: UInt8.self), c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("deinitialize buffer")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
var a = Allocation(byteCount: 48)
|
||||
do {
|
||||
try a.initialize {
|
||||
$0.append(0)
|
||||
$0.append(1)
|
||||
expectTrue($0.byteCount > 0)
|
||||
throw MyTestError.error
|
||||
}
|
||||
}
|
||||
catch MyTestError.error {
|
||||
expectEqual(a.isEmpty, true)
|
||||
}
|
||||
catch {
|
||||
expectTrue(false)
|
||||
}
|
||||
}
|
||||
248
test/stdlib/Span/OutputSpanTests.swift
Normal file
248
test/stdlib/Span/OutputSpanTests.swift
Normal file
@@ -0,0 +1,248 @@
|
||||
//===--- OutputSpanTests.swift --------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2025 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
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// RUN: %target-run-stdlib-swift
|
||||
|
||||
// REQUIRES: executable_test
|
||||
|
||||
import StdlibUnittest
|
||||
|
||||
var suite = TestSuite("OutputSpan Tests")
|
||||
defer { runAllTests() }
|
||||
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
struct Allocation<T>: ~Copyable {
|
||||
let allocation: UnsafeMutableBufferPointer<T>
|
||||
var count: Int? = nil
|
||||
|
||||
init(of count: Int = 1, _ t: T.Type) {
|
||||
precondition(count >= 0)
|
||||
allocation = .allocate(capacity: count)
|
||||
}
|
||||
|
||||
var isEmpty: Bool { (count ?? 0) == 0 }
|
||||
|
||||
mutating func initialize<E>(
|
||||
_ body: (inout OutputSpan<T>) throws(E) -> Void
|
||||
) throws(E) {
|
||||
if count != nil { fatalError() }
|
||||
var outputBuffer = OutputSpan<T>(buffer: allocation, initializedCount: 0)
|
||||
do {
|
||||
try body(&outputBuffer)
|
||||
let initialized = outputBuffer.finalize(for: allocation)
|
||||
count = initialized
|
||||
}
|
||||
catch {
|
||||
outputBuffer.removeAll()
|
||||
let initialized = outputBuffer.finalize(for: allocation)
|
||||
assert(initialized == 0)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
borrowing func withSpan<E, R: ~Copyable>(
|
||||
_ body: (borrowing Span<T>) throws(E) -> R
|
||||
) throws(E) -> R {
|
||||
try body(Span(_unsafeElements: allocation[0..<count!]))
|
||||
}
|
||||
|
||||
deinit {
|
||||
if let count {
|
||||
allocation.prefix(count).deinitialize()
|
||||
}
|
||||
allocation.deallocate()
|
||||
}
|
||||
}
|
||||
|
||||
enum MyTestError: Error { case error }
|
||||
|
||||
suite.test("Create OutputSpan")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let c = 48
|
||||
let allocation = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: c)
|
||||
defer { allocation.deallocate() }
|
||||
|
||||
let ob = unsafe OutputSpan(buffer: allocation, initializedCount: 0)
|
||||
let initialized = ob.finalize(for: allocation)
|
||||
expectEqual(initialized, 0)
|
||||
}
|
||||
|
||||
suite.test("deinit without relinquishing memory")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let c = 48
|
||||
let allocation = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: c)
|
||||
defer { allocation.deallocate() }
|
||||
|
||||
var ob = unsafe OutputSpan(buffer: allocation, initializedCount: 0)
|
||||
// OutputSpan(buffer: Slice(base: allocation, bounds: 0..<c))
|
||||
ob.append(repeating: 65, count: 12)
|
||||
expectEqual(ob.count, 12)
|
||||
_ = ob
|
||||
}
|
||||
|
||||
suite.test("append single elements")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
var a = Allocation(of: 48, Int.self)
|
||||
let c = 10
|
||||
a.initialize {
|
||||
for i in 0...c {
|
||||
$0.append(i)
|
||||
}
|
||||
let oops = $0.removeLast()
|
||||
expectEqual(oops, c)
|
||||
}
|
||||
expectNotNil(a.count)
|
||||
expectEqual(a.count, c)
|
||||
a.withSpan {
|
||||
expectEqual($0.count, c)
|
||||
for i in $0.indices {
|
||||
expectEqual($0[i], i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("initialize buffer with repeated elements")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
var a = Allocation(of: 48, Int.self)
|
||||
let c = 10
|
||||
a.initialize {
|
||||
$0.append(repeating: c, count: c)
|
||||
let oops = $0.removeLast()
|
||||
expectEqual(oops, c)
|
||||
expectEqual($0.count, c-1)
|
||||
}
|
||||
a.withSpan {
|
||||
expectEqual($0.count, c-1)
|
||||
for i in $0.indices {
|
||||
expectEqual($0[i], c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("indices property")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let capacity = 4
|
||||
let b = UnsafeMutableBufferPointer<Int>.allocate(capacity: capacity)
|
||||
defer { b.deallocate() }
|
||||
_ = b.initialize(fromContentsOf: 0..<capacity)
|
||||
defer { b.deinitialize() }
|
||||
|
||||
let span = unsafe OutputSpan(buffer: b, initializedCount: capacity)
|
||||
expectEqual(span.indices.count, capacity)
|
||||
let equal = span.indices.elementsEqual(0..<capacity)
|
||||
expectTrue(equal)
|
||||
}
|
||||
|
||||
suite.test("IndexingSubscript")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let capacity = 4
|
||||
let b = UnsafeMutableBufferPointer<Int>.allocate(capacity: capacity)
|
||||
defer { b.deallocate() }
|
||||
_ = b.initialize(fromContentsOf: 0..<capacity)
|
||||
defer { b.deinitialize() }
|
||||
|
||||
var span = unsafe OutputSpan(buffer: b, initializedCount: capacity)
|
||||
expectEqual(span[0], b.first)
|
||||
|
||||
span[0] += 1
|
||||
expectEqual(span[0], b.first)
|
||||
}
|
||||
|
||||
suite.test("deinitialize buffer")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
var a = Allocation(of: 48, Int.self)
|
||||
do {
|
||||
try a.initialize {
|
||||
$0.append(0)
|
||||
$0.append(1)
|
||||
expectTrue($0.count > 0)
|
||||
throw MyTestError.error
|
||||
}
|
||||
}
|
||||
catch MyTestError.error {
|
||||
expectEqual(a.isEmpty, true)
|
||||
}
|
||||
catch {
|
||||
expectTrue(false)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("InlineArray initialization")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
let i = InlineArray<10, Int> {
|
||||
(o: inout OutputSpan<Int>) in
|
||||
expectEqual(o.count, 0)
|
||||
for i in 0..<o.capacity {
|
||||
o.append(i)
|
||||
}
|
||||
expectEqual(o.freeCapacity, 0)
|
||||
}
|
||||
for j in i.indices {
|
||||
expectEqual(j, i[j])
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("InlineArray initialization underflow")
|
||||
.skip(.wasiAny(reason: "Trap tests aren't supported on WASI."))
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
expectCrashLater()
|
||||
_ = InlineArray<4, Int> {
|
||||
$0.append(1)
|
||||
}
|
||||
}
|
||||
|
||||
suite.test("InlineArray initialization throws")
|
||||
.require(.stdlib_6_2).code {
|
||||
guard #available(SwiftStdlib 6.2, *) else { return }
|
||||
|
||||
enum LocalError: Error { case error }
|
||||
|
||||
class I {
|
||||
static var count = 0
|
||||
init() { Self.count += 1 }
|
||||
deinit { Self.count -= 1 }
|
||||
}
|
||||
|
||||
let a: InlineArray<4, I>
|
||||
do throws(LocalError) {
|
||||
a = try InlineArray {
|
||||
o throws(LocalError) in
|
||||
o.append(I())
|
||||
o.append(I())
|
||||
o.append(I())
|
||||
o.append(I())
|
||||
expectEqual(I.count, 4)
|
||||
throw LocalError.error
|
||||
}
|
||||
_ = a
|
||||
} catch {
|
||||
expectEqual(I.count, 0)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user