Skip to content

Commit d225b37

Browse files
author
Max Moiseev
committed
[stdlib] using static method dispatch instead of failable casts
Overriding `AnySequence.dropFirst` and `AnySequence.prefix` to delegate these operations to an underlying sequence, thus simplifying default implementations in `Sequence`.
1 parent ae41794 commit d225b37

File tree

3 files changed

+129
-86
lines changed

3 files changed

+129
-86
lines changed

stdlib/private/StdlibUnittest/CheckSequenceType.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,7 +1520,8 @@ self.test("\(testNamePrefix).dropFirst/semantics/equivalence") {
15201520
let s1 = makeWrappedSequence([1010, 2020, 3030, 4040].map(OpaqueValue.init))
15211521
let s2 = makeWrappedSequence([1010, 2020, 3030, 4040].map(OpaqueValue.init))
15221522

1523-
let result1 = s1.dropFirst(1).dropFirst(1)
1523+
let result0 = s1.dropFirst(1)
1524+
let result1 = result0.dropFirst(1)
15241525
let result2 = s2.dropFirst(2)
15251526

15261527
expectEqualSequence(
@@ -1611,7 +1612,8 @@ self.test("\(testNamePrefix).prefix/semantics/equivalence") {
16111612
let s2 = makeWrappedSequence(expected)
16121613

16131614
let prefixedOnce = s1.prefix(3)
1614-
let prefixedTwice = s2.prefix(3).prefix(3)
1615+
let temp = s2.prefix(3)
1616+
let prefixedTwice = temp.prefix(3)
16151617

16161618
expectEqualSequence(prefixedOnce, prefixedTwice) {
16171619
extractValue($0).value == extractValue($1).value
@@ -1649,7 +1651,8 @@ self.test("\(testNamePrefix).suffix/semantics/equivalence") {
16491651
let s2 = makeWrappedSequence(expected)
16501652

16511653
let prefixedOnce = s1.suffix(3)
1652-
let prefixedTwice = s2.suffix(3).prefix(3)
1654+
let temp = s2.suffix(3)
1655+
let prefixedTwice = temp.prefix(3)
16531656

16541657
expectEqualSequence(prefixedOnce, prefixedTwice) {
16551658
extractValue($0).value == extractValue($1).value

stdlib/public/core/ExistentialCollection.swift.gyb

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ internal class _AnySequenceBox<Element> {
139139
internal func _copyToNativeArrayBuffer() -> _ContiguousArrayStorageBase {
140140
_abstract()
141141
}
142+
143+
internal func _dropFirst(n: Int) -> _AnySequenceBox<Element> { _abstract() }
144+
internal func _prefix(maxLength: Int) -> _AnySequenceBox<Element> {
145+
_abstract()
146+
}
142147
}
143148

144149
internal class _AnyCollectionBoxBase<Element> : _AnySequenceBox<Element> {
@@ -154,8 +159,15 @@ internal class _AnyCollectionBoxBase<Element> : _AnySequenceBox<Element> {
154159

155160
% for Kind in ['Sequence', 'Collection']:
156161
// FIXME: can't make this a protocol due to <rdar://20209031>
157-
internal class _${Kind}Box<S : ${Kind}Type>
158-
: _Any${Kind}Box<S.Generator.Element> {
162+
internal final class _${Kind}Box<
163+
S : ${Kind}Type
164+
% if Kind == 'Sequence':
165+
where
166+
S.SubSequence : ${Kind}Type,
167+
S.SubSequence.Generator.Element == S.Generator.Element,
168+
S.SubSequence.SubSequence == S.SubSequence
169+
% end
170+
> : _Any${Kind}Box<S.Generator.Element> {
159171
typealias Element = S.Generator.Element
160172

161173
override func generate() -> AnyGenerator<Element> {
@@ -171,6 +183,15 @@ internal class _${Kind}Box<S : ${Kind}Type>
171183
override func _copyToNativeArrayBuffer() -> _ContiguousArrayStorageBase {
172184
return _base._copyToNativeArrayBuffer()._storage
173185
}
186+
% if Kind == 'Sequence':
187+
internal override func _dropFirst(n: Int) -> _AnySequenceBox<Element> {
188+
return _SequenceBox<S.SubSequence>(_base.dropFirst(n))
189+
}
190+
internal override func _prefix(maxLength: Int) -> _AnySequenceBox<Element> {
191+
return _SequenceBox<S.SubSequence>(_base.prefix(maxLength))
192+
}
193+
% end
194+
174195
% if Kind == 'Collection':
175196
override func _count() -> IntMax {
176197
return numericCast(_base.count)
@@ -224,7 +245,14 @@ public struct AnySequence<Element> : SequenceType {
224245
public typealias T = Element
225246

226247
/// Wrap and forward operations to `base`.
227-
public init<S: SequenceType where S.Generator.Element == Element>(_ base: S) {
248+
public init<
249+
S: SequenceType
250+
where
251+
S.Generator.Element == Element,
252+
S.SubSequence : SequenceType,
253+
S.SubSequence.Generator.Element == Element,
254+
S.SubSequence.SubSequence == S.SubSequence
255+
>(_ base: S) {
228256
_box = _SequenceBox(base)
229257
}
230258

@@ -236,6 +264,10 @@ public struct AnySequence<Element> : SequenceType {
236264
self.init(_ClosureBasedSequence(makeUnderlyingGenerator))
237265
}
238266

267+
internal init(_ box: _AnySequenceBox<Element>) {
268+
_box = box
269+
}
270+
239271
/// Return a *generator* over the elements of this *sequence*.
240272
///
241273
/// - Complexity: O(1).
@@ -246,6 +278,18 @@ public struct AnySequence<Element> : SequenceType {
246278
internal let _box: _AnySequenceBox<Element>
247279
}
248280

281+
extension AnySequence {
282+
@warn_unused_result
283+
public func dropFirst(n: Int) -> AnySequence<Element> {
284+
return AnySequence(_box._dropFirst(n))
285+
}
286+
287+
@warn_unused_result
288+
public func prefix(maxLength: Int) -> AnySequence<Element> {
289+
return AnySequence(_box._prefix(maxLength))
290+
}
291+
}
292+
249293
% for Kind in ['Sequence'] + [t + 'Collection' for t in traversals]:
250294
extension Any${Kind} {
251295
public func underestimateCount() -> Int {

stdlib/public/core/Sequence.swift

Lines changed: 76 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,16 @@ internal class _DropFirstSequence<Base : GeneratorType>
244244
}
245245
return generator.next()
246246
}
247+
248+
internal func dropFirst(n: Int) -> AnySequence<Base.Element> {
249+
// If this is already a _DropFirstSequence, we need to fold in
250+
// the current drop count and drop limit so no data is lost.
251+
//
252+
// i.e. [1,2,3,4].dropFirst(1).dropFirst(1) should be equivalent to
253+
// [1,2,3,4].dropFirst(2).
254+
return AnySequence(
255+
_DropFirstSequence(generator, limit: limit + n, dropped: dropped))
256+
}
247257
}
248258

249259
/// A sequence that only consumes up to `n` elements from an underlying
@@ -253,7 +263,8 @@ internal class _DropFirstSequence<Base : GeneratorType>
253263
///
254264
/// This is a class - we require reference semantics to keep track
255265
/// of how many elements we've already taken from the underlying sequence.
256-
internal class _PrefixSequence<Base : GeneratorType> : SequenceType, GeneratorType {
266+
internal class _PrefixSequence<Base : GeneratorType>
267+
: SequenceType, GeneratorType {
257268
internal let maxLength: Int
258269
internal var generator: Base
259270
internal var taken: Int
@@ -279,6 +290,12 @@ internal class _PrefixSequence<Base : GeneratorType> : SequenceType, GeneratorTy
279290
taken = maxLength
280291
return nil
281292
}
293+
294+
internal func prefix(maxLength: Int) -> AnySequence<Base.Element> {
295+
return AnySequence(
296+
_PrefixSequence(generator,
297+
maxLength: min(maxLength, self.maxLength), taken: taken))
298+
}
282299
}
283300

284301
//===----------------------------------------------------------------------===//
@@ -331,83 +348,6 @@ extension SequenceType {
331348
return Array(result)
332349
}
333350

334-
/// Returns a subsequence containing all but the first `n` elements.
335-
///
336-
/// - Requires: `n >= 0`
337-
/// - Complexity: O(`n`)
338-
@warn_unused_result
339-
public func dropFirst(n: Int) -> AnySequence<Generator.Element> {
340-
_precondition(n >= 0, "Can't drop a negative number of elements from a sequence")
341-
if n == 0 { return AnySequence(self) }
342-
// If this is already a _DropFirstSequence, we need to fold in
343-
// the current drop count and drop limit so no data is lost.
344-
//
345-
// i.e. [1,2,3,4].dropFirst(1).dropFirst(1) should be equivalent to
346-
// [1,2,3,4].dropFirst(2).
347-
// FIXME: <rdar://problem/21885675> Use method dispatch to fold
348-
// _PrefixSequence and _DropFirstSequence counts
349-
if let any = self as? AnySequence<Generator.Element>,
350-
let box = any._box as? _SequenceBox<_DropFirstSequence<Generator>> {
351-
let base = box._base
352-
let folded = _DropFirstSequence(base.generator, limit: base.limit + n,
353-
dropped: base.dropped)
354-
return AnySequence(folded)
355-
}
356-
357-
return AnySequence(_DropFirstSequence(generate(), limit: n))
358-
}
359-
360-
/// Returns a subsequence containing all but the last `n` elements.
361-
///
362-
/// - Requires: `self` is a finite collection.
363-
/// - Requires: `n >= 0`
364-
/// - Complexity: O(`self.count`)
365-
@warn_unused_result
366-
public func dropLast(n: Int) -> AnySequence<Generator.Element> {
367-
_precondition(n >= 0, "Can't drop a negative number of elements from a sequence")
368-
if n == 0 { return AnySequence(self) }
369-
// FIXME: <rdar://problem/21885650> Create reusable RingBuffer<T>
370-
// Put incoming elements from this sequence in a holding tank, a ring buffer
371-
// of size <= n. If more elements keep coming in, pull them out of the
372-
// holding tank into the result, an `Array`. This saves
373-
// `n` * sizeof(Generator.Element) of memory, because slices keep the entire
374-
// memory of an `Array` alive.
375-
var result: [Generator.Element] = []
376-
var ringBuffer: [Generator.Element] = []
377-
var i = ringBuffer.startIndex
378-
379-
for element in self {
380-
if ringBuffer.count < n {
381-
ringBuffer.append(element)
382-
} else {
383-
result.append(ringBuffer[i])
384-
ringBuffer[i] = element
385-
i = i.successor() % n
386-
}
387-
}
388-
return AnySequence(result)
389-
}
390-
391-
@warn_unused_result
392-
public func prefix(maxLength: Int) -> AnySequence<Generator.Element> {
393-
_precondition(maxLength >= 0, "Can't take a prefix of negative length from a sequence")
394-
if maxLength == 0 {
395-
return AnySequence(EmptyCollection<Generator.Element>())
396-
}
397-
// FIXME: <rdar://problem/21885675> Use method dispatch to fold
398-
// _PrefixSequence and _DropFirstSequence counts
399-
if let any = self as? AnySequence<Generator.Element>,
400-
let box = any._box as? _SequenceBox<_PrefixSequence<Generator>> {
401-
let base = box._base
402-
let folded = _PrefixSequence(
403-
base.generator,
404-
maxLength: min(base.maxLength, maxLength),
405-
taken: base.taken)
406-
return AnySequence(folded)
407-
}
408-
return AnySequence(_PrefixSequence(generate(), maxLength: maxLength))
409-
}
410-
411351
@warn_unused_result
412352
public func suffix(maxLength: Int) -> AnySequence<Generator.Element> {
413353
_precondition(maxLength >= 0, "Can't take a suffix of negative length from a sequence")
@@ -526,9 +466,7 @@ extension SequenceType {
526466
) -> Bool? {
527467
return nil
528468
}
529-
}
530469

531-
extension SequenceType {
532470
/// Call `body` on each element in `self` in the same order as a
533471
/// *for-in loop.*
534472
///
@@ -585,6 +523,64 @@ extension SequenceType where Generator.Element : Equatable {
585523
}
586524
}
587525

526+
extension SequenceType where
527+
SubSequence : SequenceType,
528+
SubSequence.Generator.Element == Generator.Element,
529+
SubSequence.SubSequence == SubSequence {
530+
531+
/// Returns a subsequence containing all but the first `n` elements.
532+
///
533+
/// - Requires: `n >= 0`
534+
/// - Complexity: O(`n`)
535+
@warn_unused_result
536+
public func dropFirst(n: Int) -> AnySequence<Generator.Element> {
537+
_precondition(n >= 0, "Can't drop a negative number of elements from a sequence")
538+
if n == 0 { return AnySequence(self) }
539+
return AnySequence(_DropFirstSequence(generate(), limit: n))
540+
}
541+
542+
/// Returns a subsequence containing all but the last `n` elements.
543+
///
544+
/// - Requires: `self` is a finite collection.
545+
/// - Requires: `n >= 0`
546+
/// - Complexity: O(`self.count`)
547+
@warn_unused_result
548+
public func dropLast(n: Int) -> AnySequence<Generator.Element> {
549+
_precondition(n >= 0, "Can't drop a negative number of elements from a sequence")
550+
if n == 0 { return AnySequence(self) }
551+
552+
// FIXME: <rdar://problem/21885650> Create reusable RingBuffer<T>
553+
// Put incoming elements from this sequence in a holding tank, a ring buffer
554+
// of size <= n. If more elements keep coming in, pull them out of the
555+
// holding tank into the result, an `Array`. This saves
556+
// `n` * sizeof(Generator.Element) of memory, because slices keep the entire
557+
// memory of an `Array` alive.
558+
var result: [Generator.Element] = []
559+
var ringBuffer: [Generator.Element] = []
560+
var i = ringBuffer.startIndex
561+
562+
for element in self {
563+
if ringBuffer.count < n {
564+
ringBuffer.append(element)
565+
} else {
566+
result.append(ringBuffer[i])
567+
ringBuffer[i] = element
568+
i = i.successor() % n
569+
}
570+
}
571+
return AnySequence(result)
572+
}
573+
574+
@warn_unused_result
575+
public func prefix(maxLength: Int) -> AnySequence<Generator.Element> {
576+
_precondition(maxLength >= 0, "Can't take a prefix of negative length from a sequence")
577+
if maxLength == 0 {
578+
return AnySequence(EmptyCollection<Generator.Element>())
579+
}
580+
return AnySequence(_PrefixSequence(generate(), maxLength: maxLength))
581+
}
582+
}
583+
588584
extension SequenceType {
589585
/// Returns a subsequence containing all but the first element.
590586
///

0 commit comments

Comments
 (0)