Skip to content

Commit c2c432c

Browse files
committed
[se-0370] re-implement in accordance with updated proposal
1 parent f5ffe09 commit c2c432c

File tree

2 files changed

+130
-57
lines changed

2 files changed

+130
-57
lines changed

stdlib/public/core/UnsafeBufferPointer.swift.gyb

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -704,22 +704,27 @@ extension Unsafe${Mutable}BufferPointer {
704704
public func initialize(
705705
fromContentsOf source: some Collection<Element>
706706
) -> Index {
707-
let count = Swift.min(self.count, source.count)
708-
guard count > 0, let base = baseAddress else { return startIndex }
709-
710-
if let _ = source.withContiguousStorageIfAvailable({
711-
base.initialize(
712-
from: $0.baseAddress._unsafelyUnwrappedUnchecked,
713-
count: count
707+
let count = source.withContiguousStorageIfAvailable {
708+
guard let sourceAddress = $0.baseAddress, !$0.isEmpty else {
709+
return 0
710+
}
711+
_precondition(
712+
$0.count <= self.count,
713+
"buffer cannot contain every element from source."
714714
)
715-
}) {
715+
baseAddress?.initialize(from: sourceAddress, count: $0.count)
716+
return $0.count
717+
}
718+
if let count {
716719
return startIndex.advanced(by: count)
717720
}
718721

719-
for (p, e) in zip(base..<base.advanced(by: count), source) {
720-
p.initialize(to: e)
721-
}
722-
return startIndex.advanced(by: count)
722+
var (iterator, copied) = source._copySequenceContents(initializing: self)
723+
_precondition(
724+
iterator.next() == nil,
725+
"buffer cannot contain every element from source."
726+
)
727+
return startIndex.advanced(by: copied)
723728
}
724729

725730
/// Updates every element of this buffer's initialized memory.
@@ -799,20 +804,41 @@ extension Unsafe${Mutable}BufferPointer {
799804
public func update(
800805
fromContentsOf source: some Collection<Element>
801806
) -> Index {
802-
let count = Swift.min(source.count, self.count)
803-
guard count > 0, let base = baseAddress else { return startIndex }
804-
805-
if let _ = source.withContiguousStorageIfAvailable({
806-
base.update(from: $0.baseAddress._unsafelyUnwrappedUnchecked,
807-
count: count)
808-
}) {
807+
let count = source.withContiguousStorageIfAvailable {
808+
guard let sourceAddress = $0.baseAddress else {
809+
return 0
810+
}
811+
_precondition(
812+
$0.count <= self.count,
813+
"buffer cannot contain every element from source."
814+
)
815+
baseAddress?.update(from: sourceAddress, count: $0.count)
816+
return $0.count
817+
}
818+
if let count {
809819
return startIndex.advanced(by: count)
810820
}
811821

812-
for (p, e) in zip(base..<base.advanced(by: count), source) {
813-
p.pointee = e
822+
guard var position = baseAddress else {
823+
_precondition(
824+
source.isEmpty,
825+
"buffer cannot contain every element from source."
826+
)
827+
return startIndex
814828
}
815-
return startIndex.advanced(by: count)
829+
var iterator = source.makeIterator()
830+
for index in indices {
831+
guard let value = iterator.next() else {
832+
return index
833+
}
834+
position.pointee = value
835+
position = position.advanced(by: 1)
836+
}
837+
_precondition(
838+
iterator.next() == nil,
839+
"buffer cannot contain every element from source."
840+
)
841+
return endIndex
816842
}
817843

818844
/// Moves every element of an initialized source buffer into the
@@ -844,10 +870,14 @@ extension Unsafe${Mutable}BufferPointer {
844870
@inlinable
845871
@_alwaysEmitIntoClient
846872
public func moveInitialize(fromContentsOf source: Self) -> Index {
847-
guard let pointer = source.baseAddress, source.count > 0 else { return 0 }
848-
_debugPrecondition(count >= source.count)
849-
baseAddress._unsafelyUnwrappedUnchecked.moveInitialize(from: pointer,
850-
count: source.count)
873+
guard let sourceAddress = source.baseAddress, !source.isEmpty else {
874+
return startIndex
875+
}
876+
_precondition(
877+
source.count <= self.count,
878+
"buffer cannot contain every element from source."
879+
)
880+
baseAddress?.moveInitialize(from: sourceAddress, count: source.count)
851881
return startIndex.advanced(by: source.count)
852882
}
853883

@@ -908,10 +938,14 @@ extension Unsafe${Mutable}BufferPointer {
908938
@inlinable
909939
@_alwaysEmitIntoClient
910940
public func moveUpdate(fromContentsOf source: Self) -> Index {
911-
guard let pointer = source.baseAddress, source.count > 0 else { return 0 }
912-
_debugPrecondition(count >= source.count)
913-
baseAddress._unsafelyUnwrappedUnchecked.moveUpdate(from: pointer,
914-
count: source.count)
941+
guard let sourceAddress = source.baseAddress, !source.isEmpty else {
942+
return startIndex
943+
}
944+
_precondition(
945+
source.count <= self.count,
946+
"buffer cannot contain every element from source."
947+
)
948+
baseAddress?.moveUpdate(from: sourceAddress, count: source.count)
915949
return startIndex.advanced(by: source.count)
916950
}
917951

stdlib/public/core/UnsafeRawBufferPointer.swift.gyb

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,11 @@ extension Unsafe${Mutable}RawBufferPointer {
766766
return (it, UnsafeMutableBufferPointer(start: nil, count: 0))
767767
}
768768

769+
_debugPrecondition(
770+
Int(bitPattern: base) % MemoryLayout<S.Element>.stride == 0,
771+
"buffer base address must be properly aligned to access S.Element"
772+
)
773+
769774
_internalInvariant(_end != nil)
770775
for p in stride(from: base,
771776
// only advance to as far as the last element that will fit
@@ -813,27 +818,57 @@ extension Unsafe${Mutable}RawBufferPointer {
813818
as type: C.Element.Type,
814819
fromContentsOf source: C
815820
) -> UnsafeMutableBufferPointer<C.Element> {
816-
var count = source.count
817-
guard let base = _position, let end = _end, end > base, count > 0 else {
818-
return UnsafeMutableBufferPointer(start: nil, count: 0)
821+
let buffer: UnsafeMutableBufferPointer<C.Element>?
822+
buffer = source.withContiguousStorageIfAvailable {
823+
guard let sourceAddress = $0.baseAddress, !$0.isEmpty else {
824+
return .init(start: nil, count: 0)
825+
}
826+
_debugPrecondition(
827+
Int(bitPattern: baseAddress) % MemoryLayout<C.Element>.stride == 0,
828+
"buffer base address must be properly aligned to access C.Element"
829+
)
830+
_precondition(
831+
$0.count * MemoryLayout<C.Element>.stride < self.count,
832+
"buffer cannot contain every element from source collection."
833+
)
834+
let start = baseAddress?.initializeMemory(
835+
as: C.Element.self, from: sourceAddress, count: $0.count
836+
)
837+
return .init(start: start, count: $0.count)
838+
}
839+
if let buffer {
840+
return buffer
819841
}
820-
count = Swift.min((end - base)/MemoryLayout<C.Element>.stride, count)
821842

822-
if let start = source.withContiguousStorageIfAvailable({
823-
base.initializeMemory(
824-
as: C.Element.self,
825-
from: $0.baseAddress._unsafelyUnwrappedUnchecked,
826-
count: count
843+
guard let base = baseAddress else {
844+
_precondition(
845+
source.isEmpty,
846+
"buffer cannot contain every element from source collection."
827847
)
828-
}) {
829-
return UnsafeMutableBufferPointer(start: start, count: count)
848+
return .init(start: nil, count: 0)
830849
}
831-
832-
let start = base.bindMemory(to: C.Element.self, capacity: count)
833-
for (pointer, element) in zip(start..<start.advanced(by: count), source) {
834-
pointer.initialize(to: element)
850+
_internalInvariant(_end != nil)
851+
_debugPrecondition(
852+
Int(bitPattern: baseAddress) % MemoryLayout<C.Element>.stride == 0,
853+
"buffer base address must be properly aligned to access C.Element"
854+
)
855+
var iterator = source.makeIterator()
856+
var element = base
857+
var initialized = 0
858+
let end = _end._unsafelyUnwrappedUnchecked - MemoryLayout<C.Element>.stride
859+
while element <= end {
860+
guard let value = iterator.next() else {
861+
return .init(start: .init(base._rawValue), count: initialized)
862+
}
863+
element.initializeMemory(as: C.Element.self, to: value)
864+
element = element.advanced(by: MemoryLayout<C.Element>.stride)
865+
initialized += 1
835866
}
836-
return UnsafeMutableBufferPointer(start: start, count: count)
867+
_precondition(
868+
iterator.next() == nil,
869+
"buffer cannot contain every element from source collection."
870+
)
871+
return .init(start: .init(base._rawValue), count: initialized)
837872
}
838873

839874
/// Moves every element of an initialized source buffer into the
@@ -870,17 +905,21 @@ extension Unsafe${Mutable}RawBufferPointer {
870905
as type: T.Type,
871906
fromContentsOf source: UnsafeMutableBufferPointer<T>
872907
) -> UnsafeMutableBufferPointer<T> {
873-
guard let sourceBase = source.baseAddress
874-
else { return UnsafeMutableBufferPointer(start: nil, count: 0) }
875-
876-
let neededBytes = source.count*MemoryLayout<T>.stride
877-
guard let base = _position, count >= neededBytes
878-
else { _debugPreconditionFailure("destination has too few bytes") }
879-
880-
let initialized = base.moveInitializeMemory(as: T.self,
881-
from: sourceBase,
882-
count: source.count)
883-
return UnsafeMutableBufferPointer(start: initialized, count: source.count)
908+
guard let sourceAddress = source.baseAddress, !source.isEmpty else {
909+
return .init(start: nil, count: 0)
910+
}
911+
_precondition(
912+
source.count * MemoryLayout<T>.stride <= self.count,
913+
"buffer cannot contain every element from source."
914+
)
915+
_debugPrecondition(
916+
Int(bitPattern: baseAddress) % MemoryLayout<T>.stride == 0,
917+
"buffer base address must be properly aligned to access T"
918+
)
919+
let initialized = baseAddress?.moveInitializeMemory(
920+
as: T.self, from: sourceAddress, count: source.count
921+
)
922+
return .init(start: initialized, count: source.count)
884923
}
885924

886925
/// Moves every element of an initialized source buffer slice into the

0 commit comments

Comments
 (0)