diff --git a/stdlib/public/core/Span/MutableRawSpan.swift b/stdlib/public/core/Span/MutableRawSpan.swift index 056a5f9f912e8..e5c4d8f523ed7 100644 --- a/stdlib/public/core/Span/MutableRawSpan.swift +++ b/stdlib/public/core/Span/MutableRawSpan.swift @@ -102,16 +102,17 @@ extension MutableRawSpan { } @_alwaysEmitIntoClient - @lifetime(copy elements) + @lifetime(&elements) public init( - _elements elements: consuming MutableSpan + _elements elements: inout MutableSpan ) { - let bytes = unsafe UnsafeMutableRawBufferPointer( - start: elements._pointer, - count: elements.count &* MemoryLayout.stride + let (start, count) = unsafe (elements._pointer, elements._count) + let span = unsafe MutableRawSpan( + _unchecked: start, + byteCount: count == 1 ? MemoryLayout.size + : count &* MemoryLayout.stride ) - let span = unsafe MutableRawSpan(_unsafeBytes: bytes) - self = unsafe _overrideLifetime(span, copying: elements) + self = unsafe _overrideLifetime(span, mutating: &elements) } } diff --git a/stdlib/public/core/Span/MutableSpan.swift b/stdlib/public/core/Span/MutableSpan.swift index c9f444c434f1f..a4de39f18c9e1 100644 --- a/stdlib/public/core/Span/MutableSpan.swift +++ b/stdlib/public/core/Span/MutableSpan.swift @@ -241,6 +241,17 @@ extension MutableSpan where Element: BitwiseCopyable { RawSpan(_mutableSpan: self) } } + + /// Construct a MutableRawSpan over the memory represented by this span + /// + /// - Returns: a MutableRawSpan over the memory represented by this span + @_alwaysEmitIntoClient + public var mutableBytes: MutableRawSpan { + @lifetime(&self) + mutating get { + MutableRawSpan(_elements: &self) + } + } } @available(SwiftStdlib 6.2, *) diff --git a/test/stdlib/Span/MutableRawSpanTests.swift b/test/stdlib/Span/MutableRawSpanTests.swift index 51b9cbcb30228..e64558bd0ef3b 100644 --- a/test/stdlib/Span/MutableRawSpanTests.swift +++ b/test/stdlib/Span/MutableRawSpanTests.swift @@ -36,6 +36,38 @@ suite.test("Basic Initializer") } } +private struct Padded: BitwiseCopyable { + var storage: (Int64, Int8) +} + +suite.test("Initializer from MutableSpan") +.require(.stdlib_6_2).code { + guard #available(SwiftStdlib 6.2, *) else { return } + + var array = [0, 1, 2].map({ Padded(storage: (Int64($0), Int8($0))) }) + array.withUnsafeMutableBufferPointer { + var span = MutableSpan(_unsafeElements: $0) + var rawSpan = MutableRawSpan(_elements: &span) + + expectEqual(rawSpan.byteCount, $0.count * MemoryLayout.stride) + + rawSpan.storeBytes(of: 15, as: Int64.self) + } + expectEqual(array[0].storage.0, 15) + + var slice = array.prefix(1) + slice.withUnsafeMutableBufferPointer { + expectEqual($0.count, 1) + var span = MutableSpan(_unsafeElements: $0) + var rawSpan = MutableRawSpan(_elements: &span) + + expectEqual(rawSpan.byteCount, MemoryLayout.size) + + rawSpan.storeBytes(of: 3, as: Int64.self) + } + expectEqual(slice[0].storage.0, 3) +} + suite.test("isEmpty property") .skip(.custom( { if #available(SwiftStdlib 6.2, *) { false } else { true } }, diff --git a/test/stdlib/Span/MutableSpanTests.swift b/test/stdlib/Span/MutableSpanTests.swift index 8c962dfdfc98c..944c049c5f11b 100644 --- a/test/stdlib/Span/MutableSpanTests.swift +++ b/test/stdlib/Span/MutableSpanTests.swift @@ -122,7 +122,28 @@ suite.test("RawSpan from MutableSpan") let span = MutableSpan(_unsafeStart: p, count: c) let bytes = span.bytes expectEqual(bytes.byteCount, count*MemoryLayout.stride) + let v = bytes.unsafeLoad( + fromByteOffset: MemoryLayout.stride, as: Int.self + ) + expectEqual(v, 1) + } +} + +suite.test("MutableRawSpan from MutableSpan") +.require(.stdlib_6_2).code { + guard #available(SwiftStdlib 6.2, *) else { return } + + let count = 4 + var array = Array(0...stride) + bytes.storeBytes(of: 1, as: Int.self) } + expectEqual(array[0], 1) } suite.test("indices property")