Skip to content
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

[stdlib] using static method dispatch instead of failable casts #220

Closed
wants to merge 1 commit into from
Closed
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: 6 additions & 3 deletions stdlib/private/StdlibUnittest/CheckSequenceType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
50 changes: 47 additions & 3 deletions stdlib/public/core/ExistentialCollection.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ internal class _AnySequenceBox<Element> {
internal func _copyToNativeArrayBuffer() -> _ContiguousArrayStorageBase {
_abstract()
}

internal func _dropFirst(n: Int) -> _AnySequenceBox<Element> { _abstract() }
internal func _prefix(maxLength: Int) -> _AnySequenceBox<Element> {
_abstract()
}
}

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

% for Kind in ['Sequence', 'Collection']:
// FIXME: can't make this a protocol due to <rdar://20209031>
internal class _${Kind}Box<S : ${Kind}Type>
: _Any${Kind}Box<S.Generator.Element> {
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<S.Generator.Element> {
typealias Element = S.Generator.Element

override func generate() -> AnyGenerator<Element> {
Expand All @@ -171,6 +183,15 @@ internal class _${Kind}Box<S : ${Kind}Type>
override func _copyToNativeArrayBuffer() -> _ContiguousArrayStorageBase {
return _base._copyToNativeArrayBuffer()._storage
}
% if Kind == 'Sequence':
internal override func _dropFirst(n: Int) -> _AnySequenceBox<Element> {
return _SequenceBox<S.SubSequence>(_base.dropFirst(n))
}
internal override func _prefix(maxLength: Int) -> _AnySequenceBox<Element> {
return _SequenceBox<S.SubSequence>(_base.prefix(maxLength))
}
% end

% if Kind == 'Collection':
override func _count() -> IntMax {
return numericCast(_base.count)
Expand Down Expand Up @@ -224,7 +245,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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the signature. We want to constrain SequenceType.SubSequence this way anyway, but don't have the necessary language feature. Nevertheless, this requires a writing a proposal in swift-evolution.

_box = _SequenceBox(base)
}

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

internal init(_ box: _AnySequenceBox<Element>) {
_box = box
}

/// Return a *generator* over the elements of this *sequence*.
///
/// - Complexity: O(1).
Expand All @@ -246,6 +278,18 @@ public struct AnySequence<Element> : SequenceType {
internal let _box: _AnySequenceBox<Element>
}

extension AnySequence {
@warn_unused_result
public func dropFirst(n: Int) -> AnySequence<Element> {
return AnySequence(_box._dropFirst(n))
}

@warn_unused_result
public func prefix(maxLength: Int) -> AnySequence<Element> {
return AnySequence(_box._prefix(maxLength))
}
}

% for Kind in ['Sequence'] + [t + 'Collection' for t in traversals]:
extension Any${Kind} {
public func underestimateCount() -> Int {
Expand Down
156 changes: 76 additions & 80 deletions stdlib/public/core/Sequence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,16 @@ internal class _DropFirstSequence<Base : GeneratorType>
}
return generator.next()
}

internal func dropFirst(n: Int) -> AnySequence<Base.Element> {
// 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
Expand All @@ -253,7 +263,8 @@ internal class _DropFirstSequence<Base : GeneratorType>
///
/// 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<Base : GeneratorType> : SequenceType, GeneratorType {
internal class _PrefixSequence<Base : GeneratorType>
: SequenceType, GeneratorType {
internal let maxLength: Int
internal var generator: Base
internal var taken: Int
Expand All @@ -279,6 +290,12 @@ internal class _PrefixSequence<Base : GeneratorType> : SequenceType, GeneratorTy
taken = maxLength
return nil
}

internal func prefix(maxLength: Int) -> AnySequence<Base.Element> {
return AnySequence(
_PrefixSequence(generator,
maxLength: min(maxLength, self.maxLength), taken: taken))
}
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -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<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")
if maxLength == 0 {
return AnySequence(EmptyCollection<Generator.Element>())
}
// 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<_PrefixSequence<Generator>> {
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<Generator.Element> {
_precondition(maxLength >= 0, "Can't take a suffix of negative length from a sequence")
Expand Down Expand Up @@ -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.*
///
Expand Down Expand Up @@ -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<Generator.Element> {
_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<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")
if maxLength == 0 {
return AnySequence(EmptyCollection<Generator.Element>())
}
return AnySequence(_PrefixSequence(generate(), maxLength: maxLength))
}
}

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