Skip to content

Commit 04c7d94

Browse files
committed
Migrate _copyContents to be called from UnsafeMutableBufferPointer with checks for overrun.
1 parent cbc9d89 commit 04c7d94

15 files changed

+121
-127
lines changed

stdlib/private/StdlibCollectionUnittest/CheckSequenceInstance.swift.gyb

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,14 @@ public func checkSequence<
8686
_ = sequence._preprocessingPass { () -> Void in
8787
var count = 0
8888
for _ in sequence { count += 1 }
89-
let buf = UnsafeMutablePointer<S.Iterator.Element>.allocate(capacity: count)
90-
let end = sequence._copyContents(initializing: buf)
91-
expectTrue(end == buf + count, "_copyContents returned the wrong value")
92-
var j = expected.startIndex
93-
for i in 0..<(end - buf) {
94-
expectTrue(sameValue(expected[j], buf[i]))
95-
j = expected.index(after: j)
96-
}
97-
buf.deinitialize(count: end - buf)
98-
buf.deallocate(capacity: count)
89+
let ptr = UnsafeMutablePointer<S.Iterator.Element>.allocate(capacity: count)
90+
let buf = UnsafeMutableBufferPointer(start: ptr, count: count)
91+
var remainders = sequence._copyContents(initializing: buf)
92+
expectTrue(remainders == nil || remainders!.next() == nil,
93+
"_copyContents returned unwritten elements")
94+
expectEqualSequence(expected, buf, ${trace}, sameValue: sameValue)
95+
ptr.deinitialize(count: count)
96+
ptr.deallocate(capacity: count)
9997
}
10098

10199
// Test `_copyToContiguousArray()` if we can do so

stdlib/private/StdlibCollectionUnittest/LoggingWrappers.swift.gyb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ public struct ${Self}<
215215

216216
public typealias Iterator = LoggingIterator<Base.Iterator>
217217

218-
public func makeIterator() -> LoggingIterator<Base.Iterator> {
218+
public func makeIterator() -> Iterator {
219219
Log.makeIterator[selfType] += 1
220220
return LoggingIterator(wrapping: base.makeIterator())
221221
}
@@ -321,10 +321,10 @@ public struct ${Self}<
321321

322322
/// Copy a Sequence into an array.
323323
public func _copyContents(
324-
initializing ptr: UnsafeMutablePointer<Base.Iterator.Element>
325-
) -> UnsafeMutablePointer<Base.Iterator.Element> {
324+
initializing buf: UnsafeMutableBufferPointer<Iterator.Element>
325+
) -> Iterator? {
326326
Log._copyContents[selfType] += 1
327-
return base._copyContents(initializing: ptr)
327+
return base._copyContents(initializing: buf).map(Iterator.init)
328328
}
329329

330330
% if Kind in ['Collection', 'MutableCollection', 'RangeReplaceableCollection']:

stdlib/public/SDK/Foundation/Data.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,9 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
551551
}
552552

553553
if replacementCount != 0 {
554-
newElements._copyContents(initializing: bytes + start)
554+
let buf = UnsafeMutableBufferPointer(start: bytes + start, count: numericCast(newElements.count))
555+
// FIXME: is this guaranteed to return no residual elements?
556+
let _ = newElements._copyContents(initializing: buf)
555557
}
556558
}
557559
}

stdlib/public/core/Arrays.swift.gyb

Lines changed: 17 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,7 +1279,7 @@ extension ${Self} : RangeReplaceableCollection, _ArrayProtocol {
12791279

12801280
/// Adds the elements of a sequence to the end of the array.
12811281
///
1282-
/// Use this method to append the elements of a sequence to the end of an
1282+
/// Use this method to append the elements of a sequence to the end of this
12831283
/// array. This example appends the elements of a `Range<Int>` instance
12841284
/// to an array of integers.
12851285
///
@@ -1293,39 +1293,8 @@ extension ${Self} : RangeReplaceableCollection, _ArrayProtocol {
12931293
/// - Complexity: O(*n*), where *n* is the length of the resulting array.
12941294
public mutating func append<S : Sequence>(contentsOf newElements: S)
12951295
where S.Iterator.Element == Element {
1296-
let oldCount = self.count
1297-
let capacity = self.capacity
1298-
let newCount = oldCount + newElements.underestimatedCount
12991296

1300-
if newCount > capacity {
1301-
self.reserveCapacity(
1302-
Swift.max(newCount, _growArrayCapacity(capacity)))
1303-
}
1304-
_buffer._arrayAppendSequence(newElements)
1305-
}
1306-
1307-
// An overload of `append(contentsOf:)` that uses the += that is optimized for
1308-
// collections.
1309-
// FIXME(ABI)#13 (Performance): remove this entrypoint. The overload for `Sequence` should be
1310-
// made optimal for this case, too.
1311-
/// Adds the elements of a collection to the end of the array.
1312-
///
1313-
/// Use this method to append the elements of a collection to the end of this
1314-
/// array. This example appends the elements of a `Range<Int>` instance
1315-
/// to an array of integers.
1316-
///
1317-
/// var numbers = [1, 2, 3, 4, 5]
1318-
/// numbers.append(contentsOf: 10...15)
1319-
/// print(numbers)
1320-
/// // Prints "[1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15]"
1321-
///
1322-
/// - Parameter newElements: The elements to append to the array.
1323-
///
1324-
/// - Complexity: O(*n*), where *n* is the length of the resulting array.
1325-
public mutating func append<C : Collection>(contentsOf newElements: C)
1326-
where C.Iterator.Element == Element {
1327-
1328-
let newElementsCount = numericCast(newElements.count) as Int
1297+
let newElementsCount = newElements.underestimatedCount
13291298

13301299
let oldCount = self.count
13311300
let capacity = self.capacity
@@ -1338,8 +1307,13 @@ extension ${Self} : RangeReplaceableCollection, _ArrayProtocol {
13381307
Swift.max(newCount, _growArrayCapacity(capacity))
13391308
: newCount)
13401309

1341-
(self._buffer.firstElementAddress + oldCount).initialize(from: newElements)
1342-
self._buffer.count = newCount
1310+
let buf = UnsafeMutableBufferPointer(start: _buffer.firstElementAddress + oldCount, count: newElementsCount)
1311+
_buffer.count = newCount
1312+
if let remainder = buf.initialize(from: newElements) {
1313+
// there were elements that didn't fit in the existing buffer,
1314+
// append them in slow sequence-only mode
1315+
_buffer._arrayAppendSequence(IteratorSequence(remainder))
1316+
}
13431317
}
13441318

13451319
%if Self == 'ArraySlice':
@@ -1624,23 +1598,22 @@ extension ${Self} {
16241598
return try body(&inoutBufferPointer)
16251599
}
16261600

1627-
@discardableResult
16281601
public func _copyContents(
1629-
initializing ptr: UnsafeMutablePointer<Element>
1630-
) -> UnsafeMutablePointer<Element> {
1631-
if let s = self._baseAddressIfContiguous {
1632-
let count = self.count
1633-
ptr.initialize(from: s, count: count)
1602+
initializing buf: UnsafeMutableBufferPointer<Element>
1603+
) -> Iterator? {
1604+
// FIXME: decide if this really is a fatalError
1605+
guard var p = buf.baseAddress
1606+
else { fatalError("Attempt to copy contents into nil buffer pointer") }
1607+
if let s = _baseAddressIfContiguous {
1608+
p.initialize(from: s, count: self.count)
16341609
_fixLifetime(self._owner)
1635-
return ptr + count
16361610
} else {
1637-
var p = ptr
16381611
for x in self {
16391612
p.initialize(to: x)
16401613
p += 1
16411614
}
1642-
return p
16431615
}
1616+
return nil
16441617
}
16451618
}
16461619
%end
@@ -1790,30 +1763,6 @@ public func += <
17901763
>(lhs: inout ${Self}<S.Iterator.Element>, rhs: S) {
17911764
lhs.append(contentsOf: rhs)
17921765
}
1793-
1794-
// FIXME(ABI)#17 : remove this entrypoint. The functionality should be provided by
1795-
// a `+=` operator on `RangeReplaceableCollection`.
1796-
/// Appends the elements of a collection to ${a_Self}.
1797-
///
1798-
/// Use this operator to append the elements of a collection to the end of
1799-
/// ${a_Self} with same `Element` type. This example appends
1800-
/// the elements of a `Range<Int>` instance to an array of integers.
1801-
///
1802-
/// var numbers = [1, 2, 3, 4, 5]
1803-
/// numbers += 10...15
1804-
/// print(numbers)
1805-
/// // Prints "[1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15]"
1806-
///
1807-
/// - Parameters:
1808-
/// - lhs: The array to append to.
1809-
/// - rhs: A collection.
1810-
///
1811-
/// - Complexity: O(*n*), where *n* is the length of the resulting array.
1812-
public func += <
1813-
C : Collection
1814-
>(lhs: inout ${Self}<C.Iterator.Element>, rhs: C) {
1815-
lhs.append(contentsOf: rhs)
1816-
}
18171766
% end
18181767

18191768
//===--- generic helpers --------------------------------------------------===//

stdlib/public/core/ContiguousArrayBuffer.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,9 +477,11 @@ internal func += <Element, C : Collection>(
477477
let oldCount = lhs.count
478478
let newCount = oldCount + numericCast(rhs.count)
479479

480+
let buf: UnsafeMutableBufferPointer<Element>
481+
480482
if _fastPath(newCount <= lhs.capacity) {
483+
buf = UnsafeMutableBufferPointer(start: lhs.firstElementAddress + oldCount, count: numericCast(rhs.count))
481484
lhs.count = newCount
482-
(lhs.firstElementAddress + oldCount).initialize(from: rhs)
483485
}
484486
else {
485487
var newLHS = _ContiguousArrayBuffer<Element>(
@@ -490,7 +492,13 @@ internal func += <Element, C : Collection>(
490492
from: lhs.firstElementAddress, count: oldCount)
491493
lhs.count = 0
492494
swap(&lhs, &newLHS)
493-
(lhs.firstElementAddress + oldCount).initialize(from: rhs)
495+
buf = UnsafeMutableBufferPointer(start: lhs.firstElementAddress + oldCount, count: numericCast(rhs.count))
496+
}
497+
498+
if let remainder = buf.initialize(from: rhs) {
499+
// there were elements that didn't fit in the existing buffer,
500+
// append them in slow sequence-only mode
501+
//FIXME: handle this possibility
494502
}
495503
}
496504

stdlib/public/core/ExistentialCollection.swift.gyb

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ internal class _AnyRandomAccessCollectionBox<Element>
192192
_abstract()
193193
}
194194

195-
internal func __copyContents(initializing ptr: UnsafeMutablePointer<Element>)
196-
-> UnsafeMutablePointer<Element> {
195+
internal func __copyContents(initializing buf: UnsafeMutableBufferPointer<Element>)
196+
-> AnyIterator<Element>? {
197197
_abstract()
198198
}
199199

@@ -387,9 +387,9 @@ internal final class _${Kind}Box<S : ${Kind}> : _Any${Kind}Box<S.Iterator.Elemen
387387
internal override func __copyToContiguousArray() -> ContiguousArray<Element> {
388388
return _base._copyToContiguousArray()
389389
}
390-
internal override func __copyContents(initializing ptr: UnsafeMutablePointer<Element>)
391-
-> UnsafeMutablePointer<Element> {
392-
return _base._copyContents(initializing: ptr)
390+
internal override func __copyContents(initializing buf: UnsafeMutableBufferPointer<Element>)
391+
-> AnyIterator<Element>? {
392+
return _base._copyContents(initializing: buf).map(AnyIterator.init)
393393
}
394394
internal override func _drop(
395395
while predicate: (Element) throws -> Bool
@@ -588,6 +588,8 @@ public struct AnySequence<Element> : Sequence {
588588
self.init(_ClosureBasedSequence(makeUnderlyingIterator))
589589
}
590590

591+
public typealias Iterator = AnyIterator<Element>
592+
591593
internal init(_box: _AnySequenceBox<Element>) {
592594
self._box = _box
593595
}
@@ -602,7 +604,7 @@ extension Any${Kind} {
602604
% else:
603605
/// Returns an iterator over the elements of this collection.
604606
% end
605-
public func makeIterator() -> AnyIterator<Element> {
607+
public func makeIterator() -> Iterator {
606608
return _box._makeIterator()
607609
}
608610

@@ -683,9 +685,9 @@ extension Any${Kind} {
683685
return self._box.__copyToContiguousArray()
684686
}
685687

686-
public func _copyContents(initializing ptr: UnsafeMutablePointer<Element>)
687-
-> UnsafeMutablePointer<Element> {
688-
return _box.__copyContents(initializing: ptr)
688+
public func _copyContents(initializing buf: UnsafeMutableBufferPointer<Iterator.Element>)
689+
-> Iterator? {
690+
return _box.__copyContents(initializing: buf).map(AnyIterator.init)
689691
}
690692
}
691693
% end
@@ -808,6 +810,8 @@ public struct ${Self}<Element>
808810
// public typealias Indices
809811
// = Default${Traversal.replace('Forward', '')}Indices<${Self}>
810812

813+
public typealias Iterator = AnyIterator<Element>
814+
811815
internal init(_box: _${Self}Box<Element>) {
812816
self._box = _box
813817
}

stdlib/public/core/LazyCollection.swift.gyb

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,13 @@ public struct ${Self}<Base : ${TraversalCollection}> : LazyCollectionProtocol {
7575
/// Forward implementations to the base collection, to pick up any
7676
/// optimizations it might implement.
7777
extension ${Self} : Sequence {
78+
79+
public typealias Iterator = Base.Iterator
7880

7981
/// Returns an iterator over the elements of this sequence.
8082
///
8183
/// - Complexity: O(1).
82-
public func makeIterator() -> Base.Iterator {
84+
public func makeIterator() -> Iterator {
8385
return _base.makeIterator()
8486
}
8587

@@ -94,11 +96,10 @@ extension ${Self} : Sequence {
9496
return _base._copyToContiguousArray()
9597
}
9698

97-
@discardableResult
9899
public func _copyContents(
99-
initializing ptr: UnsafeMutablePointer<Base.Iterator.Element>
100-
) -> UnsafeMutablePointer<Base.Iterator.Element> {
101-
return _base._copyContents(initializing: ptr)
100+
initializing buf: UnsafeMutableBufferPointer<Iterator.Element>
101+
) -> Iterator? {
102+
return _base._copyContents(initializing: buf)
102103
}
103104

104105
public func _customContainsEquatableElement(

stdlib/public/core/Sequence.swift

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -605,11 +605,11 @@ public protocol Sequence {
605605
/// in the same order.
606606
func _copyToContiguousArray() -> ContiguousArray<Iterator.Element>
607607

608-
/// Copy a Sequence into an array, returning one past the last
609-
/// element initialized.
610-
@discardableResult
611-
func _copyContents(initializing ptr: UnsafeMutablePointer<Iterator.Element>)
612-
-> UnsafeMutablePointer<Iterator.Element>
608+
/// Copy `self` into an unsafe buffer, returning a partially-consumed
609+
/// iterator with any elements that didn't fit remaining.
610+
func _copyContents(
611+
initializing ptr: UnsafeMutableBufferPointer<Iterator.Element>
612+
) -> Iterator?
613613
}
614614

615615
/// A default makeIterator() function for `IteratorProtocol` instances that
@@ -1317,19 +1317,23 @@ extension Sequence {
13171317
}
13181318

13191319
extension Sequence {
1320-
@discardableResult
13211320
public func _copyContents(
1322-
initializing ptr: UnsafeMutablePointer<Iterator.Element>
1323-
) -> UnsafeMutablePointer<Iterator.Element> {
1324-
var p = UnsafeMutablePointer<Iterator.Element>(ptr)
1325-
for x in IteratorSequence(self.makeIterator()) {
1321+
initializing buf: UnsafeMutableBufferPointer<Iterator.Element>
1322+
) -> Iterator? {
1323+
var it = self.makeIterator()
1324+
// FIXME: decide if a nil buffer base pointer is valid or an error
1325+
guard let base = buf.baseAddress else { return it }
1326+
for p in base..<(base + buf.count) {
1327+
// FIXME: decide if underflow is an error that should trap
1328+
guard let x = it.next() else { break }
13261329
p.initialize(to: x)
1327-
p += 1
13281330
}
1329-
return p
1331+
return it
13301332
}
13311333
}
13321334

1335+
// FIXME(ABI) #167(Recursive Protocol Constraints): IteratorSequence
1336+
// shouldn't be necessary, iterators should be sequences.
13331337
// Pending <rdar://problem/14011860> and <rdar://problem/14396120>,
13341338
// pass an IteratorProtocol through IteratorSequence to give it "Sequence-ness"
13351339
/// A sequence built around an iterator of type `Base`.

stdlib/public/core/SequenceWrapper.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ extension Sequence
119119
/// element initialized.
120120
@discardableResult
121121
public func _copyContents(
122-
initializing ptr: UnsafeMutablePointer<Base.Iterator.Element>
123-
) -> UnsafeMutablePointer<Base.Iterator.Element> {
124-
return _base._copyContents(initializing: ptr)
122+
initializing buf: UnsafeMutableBufferPointer<Base.Iterator.Element>
123+
) -> Base.Iterator? {
124+
return _base._copyContents(initializing: buf)
125125
}
126126
}

stdlib/public/core/UnsafeBufferPointer.swift.gyb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,24 @@ extension Unsafe${Mutable}BufferPointer : CustomDebugStringConvertible {
224224
}
225225
%end
226226

227+
228+
extension UnsafeMutableBufferPointer {
229+
/// Initializes memory in the buffer starting with the elements of `source`.
230+
/// Returns an iterator to any elements of `source` that didn't fit in the
231+
/// buffer.
232+
///
233+
/// - Precondition: The memory at `self..<self + count` is
234+
/// uninitialized.
235+
///
236+
/// - Postcondition: The `Pointee`s at `self..<self + count` are
237+
/// initialized.
238+
public func initialize<S: Sequence>(from source: S) -> S.Iterator?
239+
where S.Iterator.Element == Iterator.Element {
240+
return source._copyContents(initializing: self)
241+
}
242+
}
243+
244+
227245
@available(*, unavailable, renamed: "UnsafeBufferPointerIterator")
228246
public struct UnsafeBufferPointerGenerator<Element> {}
229247

0 commit comments

Comments
 (0)