Skip to content

Commit 717e907

Browse files
Merge pull request #6601 from airspeedswift/se-147
[stdlib] Implement SE-147: Move initialize(from:) from Pointer to BufferPointer
2 parents e844d57 + 578a526 commit 717e907

23 files changed

+342
-190
lines changed

stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,19 @@ self.test("\(testNamePrefix).append(contentsOf:)/semantics") {
608608
}
609609
}
610610

611+
self.test("\(testNamePrefix).OperatorPlusEquals") {
612+
for test in appendContentsOfTests {
613+
var c = makeWrappedCollection(test.collection)
614+
let newElements =
615+
MinimalCollection(elements: test.newElements.map(wrapValue))
616+
c += newElements
617+
expectEqualSequence(
618+
test.expected,
619+
c.map { extractValue($0).value },
620+
stackTrace: SourceLocStack().with(test.loc))
621+
}
622+
}
623+
611624
//===----------------------------------------------------------------------===//
612625
// insert()
613626
//===----------------------------------------------------------------------===//

stdlib/private/StdlibCollectionUnittest/CheckSequenceInstance.swift.gyb

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,16 @@ 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,writtenUpTo) = sequence._copyContents(initializing: buf)
92+
expectTrue(remainders.next() == nil,
93+
"_copyContents returned unwritten elements")
94+
expectTrue(writtenUpTo == buf.endIndex,
95+
"_copyContents failed to use entire buffer")
96+
expectEqualSequence(expected, buf, ${trace}, sameValue: sameValue)
97+
ptr.deinitialize(count: count)
98+
ptr.deallocate(capacity: count)
9999
}
100100

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

stdlib/private/StdlibCollectionUnittest/LoggingWrappers.swift.gyb

Lines changed: 5 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,11 @@ 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 buffer: UnsafeMutableBufferPointer<Iterator.Element>
325+
) -> (Iterator,UnsafeMutableBufferPointer<Iterator.Element>.Index) {
326326
Log._copyContents[selfType] += 1
327-
return base._copyContents(initializing: ptr)
327+
let (it,idx) = base._copyContents(initializing: buffer)
328+
return (Iterator(wrapping: it),idx)
328329
}
329330

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

stdlib/public/SDK/Foundation/Data.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,7 +1425,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
14251425
// In the future, if we keep the malloced pointer and count inside this struct/ref instead of deferring to NSData, we may be able to do this more efficiently.
14261426
self.count = resultCount
14271427
}
1428-
1428+
14291429
let shift = resultCount - currentCount
14301430
let start = subrange.lowerBound
14311431

@@ -1437,7 +1437,11 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
14371437
}
14381438

14391439
if replacementCount != 0 {
1440-
newElements._copyContents(initializing: bytes + start)
1440+
let buf = UnsafeMutableBufferPointer(start: bytes + start,
1441+
count: replacementCount)
1442+
var (it,idx) = newElements._copyContents(initializing: buf)
1443+
precondition(it.next() == nil && idx == buf.endIndex,
1444+
"newElements iterator returned different count to newElements.count")
14411445
}
14421446
}
14431447
}

stdlib/public/core/ArrayType.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ internal protocol _ArrayProtocol
4343
/// - Complexity: O(`self.count`).
4444
mutating func reserveCapacity(_ minimumCapacity: Int)
4545

46-
/// Operator form of `append(contentsOf:)`.
47-
static func += <S : Sequence>(lhs: inout Self, rhs: S)
48-
where S.Iterator.Element == Iterator.Element
49-
5046
/// Insert `newElement` at index `i`.
5147
///
5248
/// Invalidates all indices with respect to `self`.

stdlib/public/core/Arrays.swift.gyb

Lines changed: 45 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,7 +1344,7 @@ extension ${Self} : RangeReplaceableCollection, _ArrayProtocol {
13441344

13451345
/// Adds the elements of a sequence to the end of the array.
13461346
///
1347-
/// Use this method to append the elements of a sequence to the end of an
1347+
/// Use this method to append the elements of a sequence to the end of this
13481348
/// array. This example appends the elements of a `Range<Int>` instance
13491349
/// to an array of integers.
13501350
///
@@ -1358,53 +1358,40 @@ extension ${Self} : RangeReplaceableCollection, _ArrayProtocol {
13581358
/// - Complexity: O(*n*), where *n* is the length of the resulting array.
13591359
public mutating func append<S : Sequence>(contentsOf newElements: S)
13601360
where S.Iterator.Element == Element {
1361-
let oldCount = self.count
1362-
let capacity = self.capacity
1363-
let newCount = oldCount + newElements.underestimatedCount
1364-
1365-
if newCount > capacity {
1366-
self.reserveCapacity(
1367-
Swift.max(newCount, _growArrayCapacity(capacity)))
1368-
}
1369-
_buffer._arrayAppendSequence(newElements)
1370-
}
1371-
1372-
// An overload of `append(contentsOf:)` that uses the += that is optimized for
1373-
// collections.
1374-
// FIXME(ABI)#13 (Performance): remove this entrypoint. The overload for `Sequence` should be
1375-
// made optimal for this case, too.
1376-
/// Adds the elements of a collection to the end of the array.
1377-
///
1378-
/// Use this method to append the elements of a collection to the end of this
1379-
/// array. This example appends the elements of a `Range<Int>` instance
1380-
/// to an array of integers.
1381-
///
1382-
/// var numbers = [1, 2, 3, 4, 5]
1383-
/// numbers.append(contentsOf: 10...15)
1384-
/// print(numbers)
1385-
/// // Prints "[1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15]"
1386-
///
1387-
/// - Parameter newElements: The elements to append to the array.
1388-
///
1389-
/// - Complexity: O(*n*), where *n* is the length of the resulting array.
1390-
public mutating func append<C : Collection>(contentsOf newElements: C)
1391-
where C.Iterator.Element == Element {
13921361

1393-
let newElementsCount = numericCast(newElements.count) as Int
1362+
let newElementsCount = newElements.underestimatedCount
13941363

13951364
let oldCount = self.count
1396-
let capacity = self.capacity
1365+
let oldCapacity = self.capacity
13971366
let newCount = oldCount + newElementsCount
13981367

13991368
// Ensure uniqueness, mutability, and sufficient storage. Note that
14001369
// for consistency, we need unique self even if newElements is empty.
14011370
self.reserveCapacity(
1402-
newCount > capacity ?
1403-
Swift.max(newCount, _growArrayCapacity(capacity))
1371+
newCount > oldCapacity ?
1372+
Swift.max(newCount, _growArrayCapacity(oldCapacity))
14041373
: newCount)
14051374

1406-
(self._buffer.firstElementAddress + oldCount).initialize(from: newElements)
1407-
self._buffer.count = newCount
1375+
let startNewElements = _buffer.firstElementAddress + oldCount
1376+
let buf = UnsafeMutableBufferPointer(
1377+
start: startNewElements,
1378+
count: self.capacity - oldCount)
1379+
1380+
let (remainder,writtenUpTo) = buf.initialize(from: newElements)
1381+
1382+
// trap on underflow from the sequence's underestimate:
1383+
let writtenCount = buf.distance(from: buf.startIndex, to: writtenUpTo)
1384+
_precondition(newElementsCount <= writtenCount,
1385+
"newElements.underestimatedCount was an overestimate")
1386+
// can't check for overflow as sequences can underestimate
1387+
1388+
_buffer.count += writtenCount
1389+
1390+
if writtenUpTo == buf.endIndex {
1391+
// there may be elements that didn't fit in the existing buffer,
1392+
// append them in slow sequence-only mode
1393+
_buffer._arrayAppendSequence(IteratorSequence(remainder))
1394+
}
14081395
}
14091396

14101397
%if Self == 'ArraySlice':
@@ -1697,23 +1684,34 @@ extension ${Self} {
16971684
return try body(&inoutBufferPointer)
16981685
}
16991686

1700-
@discardableResult
17011687
public func _copyContents(
1702-
initializing ptr: UnsafeMutablePointer<Element>
1703-
) -> UnsafeMutablePointer<Element> {
1704-
if let s = self._baseAddressIfContiguous {
1705-
let count = self.count
1706-
ptr.initialize(from: s, count: count)
1688+
initializing buffer: UnsafeMutableBufferPointer<Iterator.Element>
1689+
) -> (Iterator,UnsafeMutableBufferPointer<Iterator.Element>.Index) {
1690+
1691+
guard !self.isEmpty else { return (makeIterator(),buffer.startIndex) }
1692+
1693+
// It is not OK for there to be no pointer/not enough space, as this is
1694+
// a precondition and Array never lies about its count.
1695+
guard var p = buffer.baseAddress
1696+
else { _preconditionFailure("Attempt to copy contents into nil buffer pointer") }
1697+
_precondition(self.count <= buffer.count,
1698+
"Insufficient space allocated to copy array contents")
1699+
1700+
if let s = _baseAddressIfContiguous {
1701+
p.initialize(from: s, count: self.count)
1702+
// Need a _fixLifetime bracketing the _baseAddressIfContiguous getter
1703+
// and all uses of the pointer it returns:
17071704
_fixLifetime(self._owner)
1708-
return ptr + count
17091705
} else {
1710-
var p = ptr
17111706
for x in self {
17121707
p.initialize(to: x)
17131708
p += 1
17141709
}
1715-
return p
17161710
}
1711+
1712+
var it = IndexingIterator(_elements: self)
1713+
it._position = endIndex
1714+
return (it,buffer.index(buffer.startIndex, offsetBy: self.count))
17171715
}
17181716
}
17191717
%end
@@ -1839,54 +1837,6 @@ extension ${Self} {
18391837
}
18401838
}
18411839
}
1842-
1843-
// FIXME(ABI)#16 : remove this entrypoint. The functionality should be provided by
1844-
// a `+=` operator on `RangeReplaceableCollection`.
1845-
/// Appends the elements of a sequence to ${a_Self}.
1846-
///
1847-
/// Use this operator to append the elements of a sequence to the end of
1848-
/// ${a_Self} with same `Element` type. This example appends
1849-
/// the elements of a `Range<Int>` instance to an array of integers.
1850-
///
1851-
/// var numbers = [1, 2, 3, 4, 5]
1852-
/// numbers += 10...15
1853-
/// print(numbers)
1854-
/// // Prints "[1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15]"
1855-
///
1856-
/// - Parameters:
1857-
/// - lhs: The array to append to.
1858-
/// - rhs: A collection or finite sequence.
1859-
///
1860-
/// - Complexity: O(*n*), where *n* is the length of the resulting array.
1861-
public func += <
1862-
S : Sequence
1863-
>(lhs: inout ${Self}<S.Iterator.Element>, rhs: S) {
1864-
lhs.append(contentsOf: rhs)
1865-
}
1866-
1867-
// FIXME(ABI)#17 : remove this entrypoint. The functionality should be provided by
1868-
// a `+=` operator on `RangeReplaceableCollection`.
1869-
/// Appends the elements of a collection to ${a_Self}.
1870-
///
1871-
/// Use this operator to append the elements of a collection to the end of
1872-
/// ${a_Self} with same `Element` type. This example appends
1873-
/// the elements of a `Range<Int>` instance to an array of integers.
1874-
///
1875-
/// var numbers = [1, 2, 3, 4, 5]
1876-
/// numbers += 10...15
1877-
/// print(numbers)
1878-
/// // Prints "[1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15]"
1879-
///
1880-
/// - Parameters:
1881-
/// - lhs: The array to append to.
1882-
/// - rhs: A collection.
1883-
///
1884-
/// - Complexity: O(*n*), where *n* is the length of the resulting array.
1885-
public func += <
1886-
C : Collection
1887-
>(lhs: inout ${Self}<C.Iterator.Element>, rhs: C) {
1888-
lhs.append(contentsOf: rhs)
1889-
}
18901840
% end
18911841

18921842
//===--- 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,8 +492,14 @@ 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))
494496
}
497+
498+
var (remainders,writtenUpTo) = buf.initialize(from: rhs)
499+
500+
// ensure that exactly rhs.count elements were written
501+
_precondition(remainders.next() == nil, "rhs underreported its count")
502+
_precondition(writtenUpTo == buf.endIndex, "rhs overreported its count")
495503
}
496504

497505
extension _ContiguousArrayBuffer : RandomAccessCollection {

stdlib/public/core/ExistentialCollection.swift.gyb

Lines changed: 15 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>,UnsafeMutableBufferPointer<Element>.Index) {
197197
_abstract()
198198
}
199199

@@ -387,9 +387,10 @@ 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>,UnsafeMutableBufferPointer<Element>.Index) {
392+
let (it,idx) = _base._copyContents(initializing: buf)
393+
return (AnyIterator(it),idx)
393394
}
394395
internal override func _drop(
395396
while predicate: (Element) throws -> Bool
@@ -588,6 +589,8 @@ public struct AnySequence<Element> : Sequence {
588589
self.init(_ClosureBasedSequence(makeUnderlyingIterator))
589590
}
590591

592+
public typealias Iterator = AnyIterator<Element>
593+
591594
internal init(_box: _AnySequenceBox<Element>) {
592595
self._box = _box
593596
}
@@ -602,7 +605,7 @@ extension Any${Kind} {
602605
% else:
603606
/// Returns an iterator over the elements of this collection.
604607
% end
605-
public func makeIterator() -> AnyIterator<Element> {
608+
public func makeIterator() -> Iterator {
606609
return _box._makeIterator()
607610
}
608611

@@ -683,9 +686,10 @@ extension Any${Kind} {
683686
return self._box.__copyToContiguousArray()
684687
}
685688

686-
public func _copyContents(initializing ptr: UnsafeMutablePointer<Element>)
687-
-> UnsafeMutablePointer<Element> {
688-
return _box.__copyContents(initializing: ptr)
689+
public func _copyContents(initializing buf: UnsafeMutableBufferPointer<Iterator.Element>)
690+
-> (AnyIterator<Element>,UnsafeMutableBufferPointer<Element>.Index) {
691+
let (it,idx) = _box.__copyContents(initializing: buf)
692+
return (AnyIterator(it),idx)
689693
}
690694
}
691695
% end
@@ -808,6 +812,8 @@ public struct ${Self}<Element>
808812
// public typealias Indices
809813
// = Default${Traversal.replace('Forward', '')}Indices<${Self}>
810814

815+
public typealias Iterator = AnyIterator<Element>
816+
811817
internal init(_box: _${Self}Box<Element>) {
812818
self._box = _box
813819
}

0 commit comments

Comments
 (0)