diff --git a/stdlib/private/StdlibUnittest/CheckSequenceType.swift b/stdlib/private/StdlibUnittest/CheckSequenceType.swift index 8eedbfbfa7618..e233a86adb516 100644 --- a/stdlib/private/StdlibUnittest/CheckSequenceType.swift +++ b/stdlib/private/StdlibUnittest/CheckSequenceType.swift @@ -1520,7 +1520,8 @@ self.test("\(testNamePrefix).dropFirst/semantics/equivalence") { let s1 = makeWrappedSequence([1010, 2020, 3030, 4040].map(OpaqueValue.init)) let s2 = makeWrappedSequence([1010, 2020, 3030, 4040].map(OpaqueValue.init)) - let result1 = s1.dropFirst(1).dropFirst(1) + let result0 = s1.dropFirst(1) + let result1 = result0.dropFirst(1) let result2 = s2.dropFirst(2) expectEqualSequence( @@ -1611,7 +1612,8 @@ self.test("\(testNamePrefix).prefix/semantics/equivalence") { let s2 = makeWrappedSequence(expected) let prefixedOnce = s1.prefix(3) - let prefixedTwice = s2.prefix(3).prefix(3) + let temp = s2.prefix(3) + let prefixedTwice = temp.prefix(3) expectEqualSequence(prefixedOnce, prefixedTwice) { extractValue($0).value == extractValue($1).value @@ -1649,7 +1651,8 @@ self.test("\(testNamePrefix).suffix/semantics/equivalence") { let s2 = makeWrappedSequence(expected) let prefixedOnce = s1.suffix(3) - let prefixedTwice = s2.suffix(3).prefix(3) + let temp = s2.suffix(3) + let prefixedTwice = temp.prefix(3) expectEqualSequence(prefixedOnce, prefixedTwice) { extractValue($0).value == extractValue($1).value diff --git a/stdlib/public/core/ExistentialCollection.swift.gyb b/stdlib/public/core/ExistentialCollection.swift.gyb index f637f67083500..1e78803a157fa 100644 --- a/stdlib/public/core/ExistentialCollection.swift.gyb +++ b/stdlib/public/core/ExistentialCollection.swift.gyb @@ -139,6 +139,11 @@ internal class _AnySequenceBox { internal func _copyToNativeArrayBuffer() -> _ContiguousArrayStorageBase { _abstract() } + + internal func _dropFirst(n: Int) -> _AnySequenceBox { _abstract() } + internal func _prefix(maxLength: Int) -> _AnySequenceBox { + _abstract() + } } internal class _AnyCollectionBoxBase : _AnySequenceBox { @@ -154,8 +159,15 @@ internal class _AnyCollectionBoxBase : _AnySequenceBox { % for Kind in ['Sequence', 'Collection']: // FIXME: can't make this a protocol due to -internal class _${Kind}Box - : _Any${Kind}Box { +internal final class _${Kind}Box< + S : ${Kind}Type +% if Kind == 'Sequence': + where + S.SubSequence : ${Kind}Type, + S.SubSequence.Generator.Element == S.Generator.Element, + S.SubSequence.SubSequence == S.SubSequence +% end +> : _Any${Kind}Box { typealias Element = S.Generator.Element override func generate() -> AnyGenerator { @@ -171,6 +183,15 @@ internal class _${Kind}Box override func _copyToNativeArrayBuffer() -> _ContiguousArrayStorageBase { return _base._copyToNativeArrayBuffer()._storage } +% if Kind == 'Sequence': + internal override func _dropFirst(n: Int) -> _AnySequenceBox { + return _SequenceBox(_base.dropFirst(n)) + } + internal override func _prefix(maxLength: Int) -> _AnySequenceBox { + return _SequenceBox(_base.prefix(maxLength)) + } +% end + % if Kind == 'Collection': override func _count() -> IntMax { return numericCast(_base.count) @@ -224,7 +245,14 @@ public struct AnySequence : SequenceType { public typealias T = Element /// Wrap and forward operations to `base`. - public init(_ base: S) { + public init< + S: SequenceType + where + S.Generator.Element == Element, + S.SubSequence : SequenceType, + S.SubSequence.Generator.Element == Element, + S.SubSequence.SubSequence == S.SubSequence + >(_ base: S) { _box = _SequenceBox(base) } @@ -236,6 +264,10 @@ public struct AnySequence : SequenceType { self.init(_ClosureBasedSequence(makeUnderlyingGenerator)) } + internal init(_ box: _AnySequenceBox) { + _box = box + } + /// Return a *generator* over the elements of this *sequence*. /// /// - Complexity: O(1). @@ -246,6 +278,18 @@ public struct AnySequence : SequenceType { internal let _box: _AnySequenceBox } +extension AnySequence { + @warn_unused_result + public func dropFirst(n: Int) -> AnySequence { + return AnySequence(_box._dropFirst(n)) + } + + @warn_unused_result + public func prefix(maxLength: Int) -> AnySequence { + return AnySequence(_box._prefix(maxLength)) + } +} + % for Kind in ['Sequence'] + [t + 'Collection' for t in traversals]: extension Any${Kind} { public func underestimateCount() -> Int { diff --git a/stdlib/public/core/Sequence.swift b/stdlib/public/core/Sequence.swift index dca54b1d35bf0..0d7df20275016 100644 --- a/stdlib/public/core/Sequence.swift +++ b/stdlib/public/core/Sequence.swift @@ -244,6 +244,16 @@ internal class _DropFirstSequence } return generator.next() } + + internal func dropFirst(n: Int) -> AnySequence { + // If this is already a _DropFirstSequence, we need to fold in + // the current drop count and drop limit so no data is lost. + // + // i.e. [1,2,3,4].dropFirst(1).dropFirst(1) should be equivalent to + // [1,2,3,4].dropFirst(2). + return AnySequence( + _DropFirstSequence(generator, limit: limit + n, dropped: dropped)) + } } /// A sequence that only consumes up to `n` elements from an underlying @@ -253,7 +263,8 @@ internal class _DropFirstSequence /// /// This is a class - we require reference semantics to keep track /// of how many elements we've already taken from the underlying sequence. -internal class _PrefixSequence : SequenceType, GeneratorType { +internal class _PrefixSequence + : SequenceType, GeneratorType { internal let maxLength: Int internal var generator: Base internal var taken: Int @@ -279,6 +290,12 @@ internal class _PrefixSequence : SequenceType, GeneratorTy taken = maxLength return nil } + + internal func prefix(maxLength: Int) -> AnySequence { + return AnySequence( + _PrefixSequence(generator, + maxLength: min(maxLength, self.maxLength), taken: taken)) + } } //===----------------------------------------------------------------------===// @@ -331,83 +348,6 @@ extension SequenceType { return Array(result) } - /// Returns a subsequence containing all but the first `n` elements. - /// - /// - Requires: `n >= 0` - /// - Complexity: O(`n`) - @warn_unused_result - public func dropFirst(n: Int) -> AnySequence { - _precondition(n >= 0, "Can't drop a negative number of elements from a sequence") - if n == 0 { return AnySequence(self) } - // If this is already a _DropFirstSequence, we need to fold in - // the current drop count and drop limit so no data is lost. - // - // i.e. [1,2,3,4].dropFirst(1).dropFirst(1) should be equivalent to - // [1,2,3,4].dropFirst(2). - // FIXME: Use method dispatch to fold - // _PrefixSequence and _DropFirstSequence counts - if let any = self as? AnySequence, - let box = any._box as? _SequenceBox<_DropFirstSequence> { - let base = box._base - let folded = _DropFirstSequence(base.generator, limit: base.limit + n, - dropped: base.dropped) - return AnySequence(folded) - } - - return AnySequence(_DropFirstSequence(generate(), limit: n)) - } - - /// Returns a subsequence containing all but the last `n` elements. - /// - /// - Requires: `self` is a finite collection. - /// - Requires: `n >= 0` - /// - Complexity: O(`self.count`) - @warn_unused_result - public func dropLast(n: Int) -> AnySequence { - _precondition(n >= 0, "Can't drop a negative number of elements from a sequence") - if n == 0 { return AnySequence(self) } - // FIXME: Create reusable RingBuffer - // Put incoming elements from this sequence in a holding tank, a ring buffer - // of size <= n. If more elements keep coming in, pull them out of the - // holding tank into the result, an `Array`. This saves - // `n` * sizeof(Generator.Element) of memory, because slices keep the entire - // memory of an `Array` alive. - var result: [Generator.Element] = [] - var ringBuffer: [Generator.Element] = [] - var i = ringBuffer.startIndex - - for element in self { - if ringBuffer.count < n { - ringBuffer.append(element) - } else { - result.append(ringBuffer[i]) - ringBuffer[i] = element - i = i.successor() % n - } - } - return AnySequence(result) - } - - @warn_unused_result - public func prefix(maxLength: Int) -> AnySequence { - _precondition(maxLength >= 0, "Can't take a prefix of negative length from a sequence") - if maxLength == 0 { - return AnySequence(EmptyCollection()) - } - // FIXME: Use method dispatch to fold - // _PrefixSequence and _DropFirstSequence counts - if let any = self as? AnySequence, - let box = any._box as? _SequenceBox<_PrefixSequence> { - let base = box._base - let folded = _PrefixSequence( - base.generator, - maxLength: min(base.maxLength, maxLength), - taken: base.taken) - return AnySequence(folded) - } - return AnySequence(_PrefixSequence(generate(), maxLength: maxLength)) - } - @warn_unused_result public func suffix(maxLength: Int) -> AnySequence { _precondition(maxLength >= 0, "Can't take a suffix of negative length from a sequence") @@ -526,9 +466,7 @@ extension SequenceType { ) -> Bool? { return nil } -} -extension SequenceType { /// Call `body` on each element in `self` in the same order as a /// *for-in loop.* /// @@ -585,6 +523,64 @@ extension SequenceType where Generator.Element : Equatable { } } +extension SequenceType where + SubSequence : SequenceType, + SubSequence.Generator.Element == Generator.Element, + SubSequence.SubSequence == SubSequence { + + /// Returns a subsequence containing all but the first `n` elements. + /// + /// - Requires: `n >= 0` + /// - Complexity: O(`n`) + @warn_unused_result + public func dropFirst(n: Int) -> AnySequence { + _precondition(n >= 0, "Can't drop a negative number of elements from a sequence") + if n == 0 { return AnySequence(self) } + return AnySequence(_DropFirstSequence(generate(), limit: n)) + } + + /// Returns a subsequence containing all but the last `n` elements. + /// + /// - Requires: `self` is a finite collection. + /// - Requires: `n >= 0` + /// - Complexity: O(`self.count`) + @warn_unused_result + public func dropLast(n: Int) -> AnySequence { + _precondition(n >= 0, "Can't drop a negative number of elements from a sequence") + if n == 0 { return AnySequence(self) } + + // FIXME: Create reusable RingBuffer + // Put incoming elements from this sequence in a holding tank, a ring buffer + // of size <= n. If more elements keep coming in, pull them out of the + // holding tank into the result, an `Array`. This saves + // `n` * sizeof(Generator.Element) of memory, because slices keep the entire + // memory of an `Array` alive. + var result: [Generator.Element] = [] + var ringBuffer: [Generator.Element] = [] + var i = ringBuffer.startIndex + + for element in self { + if ringBuffer.count < n { + ringBuffer.append(element) + } else { + result.append(ringBuffer[i]) + ringBuffer[i] = element + i = i.successor() % n + } + } + return AnySequence(result) + } + + @warn_unused_result + public func prefix(maxLength: Int) -> AnySequence { + _precondition(maxLength >= 0, "Can't take a prefix of negative length from a sequence") + if maxLength == 0 { + return AnySequence(EmptyCollection()) + } + return AnySequence(_PrefixSequence(generate(), maxLength: maxLength)) + } +} + extension SequenceType { /// Returns a subsequence containing all but the first element. ///