Skip to content

Commit df2307e

Browse files
[stdlib][DNM] Collapse sequence and collection wrappers (#20221)
* Concretize dropFirst/Last/sufix/prefix from Sequence Remove split customization point Eliminate SubSequence from Sequence protocol Collapse LazyCollection Collapse LazyMapCollection Eliminate _SequenceWrapper Collapse LazyFilterCollection Collapse LazyDrop/PrefixWhileCollection Fix tests, ABI stability update Collapse FlattenSequence * Add entries to source/ABI compatible expected results. * Update tests to avoid pre-10.14 objc runtime bug * Expunge _preprocessingPass
1 parent 3666e02 commit df2307e

39 files changed

+575
-1686
lines changed

stdlib/private/StdlibCollectionUnittest/CheckSequenceInstance.swift

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -87,32 +87,6 @@ public func checkSequence<
8787
expectGE(
8888
expectedCount, sequence.underestimatedCount, message(),
8989
stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
90-
91-
// Test `_copyContents(initializing:)` if we can do so without destroying the
92-
// sequence.
93-
_ = sequence._preprocessingPass { () -> Void in
94-
var count = 0
95-
for _ in sequence { count += 1 }
96-
let ptr = UnsafeMutablePointer<S.Element>.allocate(capacity: count)
97-
let buf = UnsafeMutableBufferPointer(start: ptr, count: count)
98-
var (remainders,writtenUpTo) = sequence._copyContents(initializing: buf)
99-
expectTrue(remainders.next() == nil,
100-
"_copyContents returned unwritten elements")
101-
expectTrue(writtenUpTo == buf.endIndex,
102-
"_copyContents failed to use entire buffer")
103-
expectEqualSequence(expected, buf, message(),
104-
stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), sameValue: sameValue)
105-
ptr.deinitialize(count: count)
106-
ptr.deallocate()
107-
}
108-
109-
// Test `_copyToContiguousArray()` if we can do so
110-
// without destroying the sequence.
111-
_ = sequence._preprocessingPass { () -> Void in
112-
let copy = sequence._copyToContiguousArray()
113-
expectEqualSequence(expected, copy, message(),
114-
stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), sameValue: sameValue)
115-
}
11690
}
11791

11892
public func checkSequence<
@@ -206,32 +180,6 @@ public func checkSequence<
206180
expectGE(
207181
expectedCount, sequence.underestimatedCount, message(),
208182
stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
209-
210-
// Test `_copyContents(initializing:)` if we can do so without destroying the
211-
// sequence.
212-
_ = sequence._preprocessingPass { () -> Void in
213-
var count = 0
214-
for _ in sequence { count += 1 }
215-
let ptr = UnsafeMutablePointer<S.Element>.allocate(capacity: count)
216-
let buf = UnsafeMutableBufferPointer(start: ptr, count: count)
217-
var (remainders,writtenUpTo) = sequence._copyContents(initializing: buf)
218-
expectTrue(remainders.next() == nil,
219-
"_copyContents returned unwritten elements")
220-
expectTrue(writtenUpTo == buf.endIndex,
221-
"_copyContents failed to use entire buffer")
222-
expectEqualSequence(expected, buf, message(),
223-
stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), sameValue: sameValue)
224-
ptr.deinitialize(count: count)
225-
ptr.deallocate()
226-
}
227-
228-
// Test `_copyToContiguousArray()` if we can do so
229-
// without destroying the sequence.
230-
_ = sequence._preprocessingPass { () -> Void in
231-
let copy = sequence._copyToContiguousArray()
232-
expectEqualSequence(expected, copy, message(),
233-
stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), sameValue: sameValue)
234-
}
235183
}
236184

237185
public func checkSequence<

stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1643,14 +1643,6 @@ extension TestSuite {
16431643

16441644
testNamePrefix += String(describing: S.Type.self)
16451645

1646-
let isMultiPass = makeSequence([])
1647-
._preprocessingPass { true } ?? false
1648-
let isEquatableMultiPass = makeSequenceOfEquatable([])
1649-
._preprocessingPass { true } ?? false
1650-
expectEqual(
1651-
isMultiPass, isEquatableMultiPass,
1652-
"Two sequence types are of different kinds?")
1653-
16541646
// FIXME: swift-3-indexing-model: add tests for `underestimatedCount`
16551647
// Check that it is non-negative, and an underestimate of the actual
16561648
// element count.
@@ -1667,12 +1659,6 @@ self.test("\(testNamePrefix).contains()/WhereElementIsEquatable/semantics") {
16671659
test.expected != nil,
16681660
s.contains(wrapValueIntoEquatable(test.element)),
16691661
stackTrace: SourceLocStack().with(test.loc))
1670-
1671-
if !isMultiPass {
1672-
expectEqualSequence(
1673-
test.expectedLeftoverSequence, s.map(extractValueFromEquatable),
1674-
stackTrace: SourceLocStack().with(test.loc))
1675-
}
16761662
}
16771663
}
16781664

@@ -1992,52 +1978,6 @@ self.test("\(testNamePrefix).first(where:)/semantics") {
19921978
}
19931979
}
19941980

1995-
//===----------------------------------------------------------------------===//
1996-
// _preprocessingPass()
1997-
//===----------------------------------------------------------------------===//
1998-
1999-
self.test("\(testNamePrefix)._preprocessingPass/semantics") {
2000-
for test in forEachTests {
2001-
let s = makeWrappedSequence(test.sequence.map(OpaqueValue.init))
2002-
var wasInvoked = false
2003-
let result = s._preprocessingPass {
2004-
() -> OpaqueValue<Int> in
2005-
wasInvoked = true
2006-
2007-
expectEqualSequence(
2008-
test.sequence,
2009-
s.map { extractValue($0).value })
2010-
2011-
return OpaqueValue(42)
2012-
}
2013-
if wasInvoked {
2014-
expectEqual(42, result?.value)
2015-
} else {
2016-
expectNil(result)
2017-
}
2018-
}
2019-
2020-
for test in forEachTests {
2021-
let s = makeWrappedSequence(test.sequence.map(OpaqueValue.init))
2022-
var wasInvoked = false
2023-
var caughtError: Error?
2024-
var result: OpaqueValue<Int>?
2025-
do {
2026-
result = try s._preprocessingPass {
2027-
() -> OpaqueValue<Int> in
2028-
wasInvoked = true
2029-
throw TestError.error2
2030-
}
2031-
} catch {
2032-
caughtError = error
2033-
}
2034-
expectNil(result)
2035-
if wasInvoked {
2036-
expectEqual(TestError.error2, caughtError as? TestError)
2037-
}
2038-
}
2039-
}
2040-
20411981
//===----------------------------------------------------------------------===//
20421982
} // addSequenceTests
20431983
}

stdlib/private/StdlibCollectionUnittest/LoggingWrappers.swift

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,7 @@ public class SequenceLog {
8383
public static var prefixWhile = TypeIndexed(0)
8484
public static var prefixMaxLength = TypeIndexed(0)
8585
public static var suffixMaxLength = TypeIndexed(0)
86-
public static var split = TypeIndexed(0)
8786
public static var _customContainsEquatableElement = TypeIndexed(0)
88-
public static var _preprocessingPass = TypeIndexed(0)
8987
public static var _copyToContiguousArray = TypeIndexed(0)
9088
public static var _copyContents = TypeIndexed(0)
9189
// Collection
@@ -202,7 +200,6 @@ extension LoggingSequence: LoggingType {
202200
extension LoggingSequence: Sequence {
203201
public typealias Element = Base.Element
204202
public typealias Iterator = LoggingIterator<Base.Iterator>
205-
public typealias SubSequence = Base.SubSequence
206203

207204
public func makeIterator() -> Iterator {
208205
SequenceLog.makeIterator[selfType] += 1
@@ -214,67 +211,11 @@ extension LoggingSequence: Sequence {
214211
return base.underestimatedCount
215212
}
216213

217-
public func dropFirst(_ n: Int) -> SubSequence {
218-
SequenceLog.dropFirst[selfType] += 1
219-
return base.dropFirst(n)
220-
}
221-
222-
public func dropLast(_ n: Int) -> SubSequence {
223-
SequenceLog.dropLast[selfType] += 1
224-
return base.dropLast(n)
225-
}
226-
227-
public func drop(
228-
while predicate: (Element) throws -> Bool
229-
) rethrows -> SubSequence {
230-
SequenceLog.dropWhile[selfType] += 1
231-
return try base.drop(while: predicate)
232-
}
233-
234-
public func prefix(_ maxLength: Int) -> SubSequence {
235-
SequenceLog.prefixMaxLength[selfType] += 1
236-
return base.prefix(maxLength)
237-
}
238-
239-
public func prefix(
240-
while predicate: (Element) throws -> Bool
241-
) rethrows -> SubSequence {
242-
SequenceLog.prefixWhile[selfType] += 1
243-
return try base.prefix(while: predicate)
244-
}
245-
246-
public func suffix(_ maxLength: Int) -> SubSequence {
247-
SequenceLog.suffixMaxLength[selfType] += 1
248-
return base.suffix(maxLength)
249-
}
250-
251-
public func split(
252-
maxSplits: Int = Int.max,
253-
omittingEmptySubsequences: Bool = true,
254-
whereSeparator isSeparator: (Element) throws -> Bool
255-
) rethrows -> [SubSequence] {
256-
SequenceLog.split[selfType] += 1
257-
return try base.split(
258-
maxSplits: maxSplits,
259-
omittingEmptySubsequences: omittingEmptySubsequences,
260-
whereSeparator: isSeparator)
261-
}
262-
263214
public func _customContainsEquatableElement(_ element: Element) -> Bool? {
264215
SequenceLog._customContainsEquatableElement[selfType] += 1
265216
return base._customContainsEquatableElement(element)
266217
}
267218

268-
/// If `self` is multi-pass (i.e., a `Collection`), invoke
269-
/// `preprocess` on `self` and return its result. Otherwise, return
270-
/// `nil`.
271-
public func _preprocessingPass<R>(
272-
_ preprocess: () throws -> R
273-
) rethrows -> R? {
274-
SequenceLog._preprocessingPass[selfType] += 1
275-
return try base._preprocessingPass(preprocess)
276-
}
277-
278219
/// Create a native array buffer containing the elements of `self`,
279220
/// in the same order.
280221
public func _copyToContiguousArray() -> ContiguousArray<Element> {
@@ -297,6 +238,7 @@ public typealias LoggingCollection<Base: Collection> = LoggingSequence<Base>
297238
extension LoggingCollection: Collection {
298239
public typealias Index = Base.Index
299240
public typealias Indices = Base.Indices
241+
public typealias SubSequence = Base.SubSequence
300242

301243
public var startIndex: Index {
302244
CollectionLog.startIndex[selfType] += 1

stdlib/private/StdlibUnittest/StdlibUnittest.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -499,8 +499,7 @@ public func expectMutableSliceType<X : MutableCollection>(
499499
/// to be.
500500
public func expectSequenceAssociatedTypes<X : Sequence>(
501501
sequenceType: X.Type,
502-
iteratorType: X.Iterator.Type,
503-
subSequenceType: X.SubSequence.Type
502+
iteratorType: X.Iterator.Type
504503
) {}
505504

506505
/// Check that all associated types of a `Collection` are what we expect them

stdlib/public/core/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ set(SWIFTLIB_ESSENTIAL
122122
SipHash.swift
123123
Sequence.swift
124124
SequenceAlgorithms.swift
125-
SequenceWrapper.swift
126125
Set.swift
127126
SetAlgebra.swift
128127
SetAnyHashableExtensions.swift

stdlib/public/core/Collection.swift

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ extension IndexingIterator: IteratorProtocol, Sequence {
332332
/// or bidirectional collection must traverse the entire collection to count
333333
/// the number of contained elements, accessing its `count` property is an
334334
/// O(*n*) operation.
335-
public protocol Collection: Sequence where SubSequence: Collection {
335+
public protocol Collection: Sequence {
336336
// FIXME: ideally this would be in MigrationSupport.swift, but it needs
337337
// to be on the protocol instead of as an extension
338338
@available(*, deprecated/*, obsoleted: 5.0*/, message: "all index distances are now of type Int")
@@ -390,7 +390,10 @@ public protocol Collection: Sequence where SubSequence: Collection {
390390
/// This associated type appears as a requirement in the `Sequence`
391391
/// protocol, but it is restated here with stricter constraints. In a
392392
/// collection, the subsequence should also conform to `Collection`.
393-
associatedtype SubSequence = Slice<Self> where SubSequence.Index == Index
393+
associatedtype SubSequence: Collection = Slice<Self>
394+
where SubSequence.Index == Index,
395+
Element == SubSequence.Element,
396+
SubSequence.SubSequence == SubSequence
394397

395398
/// Accesses the element at the specified position.
396399
///
@@ -1223,7 +1226,7 @@ extension Collection {
12231226
/// `RandomAccessCollection`; otherwise, O(*k*), where *k* is the number of
12241227
/// elements to drop from the beginning of the collection.
12251228
@inlinable
1226-
public __consuming func dropFirst(_ k: Int) -> SubSequence {
1229+
public __consuming func dropFirst(_ k: Int = 1) -> SubSequence {
12271230
_precondition(k >= 0, "Can't drop a negative number of elements from a collection")
12281231
let start = index(startIndex, offsetBy: k, limitedBy: endIndex) ?? endIndex
12291232
return self[start..<endIndex]
@@ -1250,15 +1253,15 @@ extension Collection {
12501253
/// `RandomAccessCollection`; otherwise, O(*n*), where *n* is the length of
12511254
/// the collection.
12521255
@inlinable
1253-
public __consuming func dropLast(_ k: Int) -> SubSequence {
1256+
public __consuming func dropLast(_ k: Int = 1) -> SubSequence {
12541257
_precondition(
12551258
k >= 0, "Can't drop a negative number of elements from a collection")
12561259
let amount = Swift.max(0, count - k)
12571260
let end = index(startIndex,
12581261
offsetBy: amount, limitedBy: endIndex) ?? endIndex
12591262
return self[startIndex..<end]
12601263
}
1261-
1264+
12621265
/// Returns a subsequence by skipping elements while `predicate` returns
12631266
/// `true` and returning the remaining elements.
12641267
///
@@ -1665,13 +1668,3 @@ extension Collection where SubSequence == Self {
16651668
self = self[index(startIndex, offsetBy: k)..<endIndex]
16661669
}
16671670
}
1668-
1669-
extension Collection {
1670-
@inlinable
1671-
@inline(__always)
1672-
public func _preprocessingPass<R>(
1673-
_ preprocess: () throws -> R
1674-
) rethrows -> R? {
1675-
return try preprocess()
1676-
}
1677-
}

stdlib/public/core/Dictionary.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,8 @@ extension Dictionary {
618618
}
619619

620620
extension Dictionary: Collection {
621+
public typealias SubSequence = Slice<Dictionary>
622+
621623
/// The position of the first element in a nonempty dictionary.
622624
///
623625
/// If the collection is empty, `startIndex` is equal to `endIndex`.
@@ -1321,6 +1323,7 @@ extension Dictionary {
13211323
: Collection, Equatable,
13221324
CustomStringConvertible, CustomDebugStringConvertible {
13231325
public typealias Element = Key
1326+
public typealias SubSequence = Slice<Dictionary.Keys>
13241327

13251328
@usableFromInline
13261329
internal var _variant: Dictionary<Key, Value>._Variant

0 commit comments

Comments
 (0)