Skip to content

[stdlib] Constraining AnySequence.init #895

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion stdlib/public/core/ExistentialCollection.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,14 @@ public struct AnySequence<Element> : SequenceType {
public typealias T = Element

/// Wrap and forward operations to `base`.
public init<S: SequenceType where S.Generator.Element == Element>(_ 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)
}

Expand Down
122 changes: 63 additions & 59 deletions stdlib/public/core/Sequence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -331,63 +331,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<Generator.Element> {
_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: <rdar://problem/21885675> Use method dispatch to fold
// _PrefixSequence and _DropFirstSequence counts
if let any = self as? AnySequence<Generator.Element>,
let box = any._box as? _SequenceBox<_DropFirstSequence<Generator>> {
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<Generator.Element> {
_precondition(n >= 0, "Can't drop a negative number of elements from a sequence")
if n == 0 { return AnySequence(self) }
// FIXME: <rdar://problem/21885650> Create reusable RingBuffer<T>
// 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<Generator.Element> {
_precondition(maxLength >= 0, "Can't take a prefix of negative length from a sequence")
Expand Down Expand Up @@ -526,9 +469,7 @@ extension SequenceType {
) -> Bool? {
return nil
}
}

extension SequenceType {
/// Call `body` on each element in `self` in the same order as a
/// *for-in loop.*
///
Expand Down Expand Up @@ -585,6 +526,69 @@ 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<Generator.Element> {
_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: <rdar://problem/21885675> Use method dispatch to fold
// _PrefixSequence and _DropFirstSequence counts
if let any = self as? AnySequence<Generator.Element>,
let box = any._box as? _SequenceBox<_DropFirstSequence<Generator>> {
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<Generator.Element> {
_precondition(n >= 0, "Can't drop a negative number of elements from a sequence")
if n == 0 { return AnySequence(self) }
// FIXME: <rdar://problem/21885650> Create reusable RingBuffer<T>
// 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)
}
}

extension SequenceType {
/// Returns a subsequence containing all but the first element.
///
Expand Down