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

[SR-13802] EnumeratedSequence should conform to Collection when Base conforms to it #56199

Open
swift-ci opened this issue Nov 1, 2020 · 1 comment
Labels
improvement standard library Area: Standard library umbrella

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Nov 1, 2020

Previous ID SR-13802
Radar rdar://problem/70934033
Original Reporter laclouis5 (JIRA User)
Type Improvement
Additional Detail from JIRA
Votes 0
Component/s Standard Library
Labels Improvement
Assignee None
Priority Medium

md5: 2b6c41ac1cc8a67e9b18be3b820d1805

Issue Description:

This issue is related to SR-11479. Currently enumerated() returns an EnumeratedSequence lazy evaluated struct. This struct is a sequence, even if Base is a Collection such as an Array, so it does not preserve the sequence type and associated performances of the underlying sequence type (Base).

For instance the following code does not work as expected. Because enumerated()
returns a Sequence, reversed() is forced to create a new array instead of a ReversedCollection:

// `elements` is an Array<(Int, String)>
let elements = ["a", "b", "c"].enumerated().reversed()

This is a performance issue in for-loops using the above pattern as the operation is now O👎 instead of O(1) and allocated storage.

This also cause a cause a gap in the API, for example it is currently impossible to subscript or get the last element efficiently.

An implementation of a fix could be this:

public typealias EnumeratedCollection<Base: Collection> = EnumeratedSequence<Base>

extension EnumeratedCollection: Collection {
    public typealias Index = Base.Index

    public var startIndex: Index { _base.startIndex }
    public var endIndex: Index { _base.endIndex }

    public subscript(position: Index) -> Element {
        return (position, _base[position])
    }

    public func index(after i: Index) -> Index {
        return _base.index(after: i)
    }
}

extension EnumeratedCollection: BidirectionalCollection where Base: BidirectionalCollection {
    public func index(before i: Index) -> Index {
        return _base.index(before: i)
    }
}

extension EnumeratedCollection: RandomAccessCollection where Base: RandomAccessCollection { }

Another related issue: EnumeratedSequence does not forward laziness like ReverseCollection does which is in my opinion not expected:

extension EnumeratedSequence: LazyProtocol where Base: LazyProtocol

Can fix code like this:

// elements is not lazy mapped
let elements = (0..<10).lazy.enumerated().map { $0 }
@typesanitizer
Copy link

@swift-ci create

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
improvement standard library Area: Standard library umbrella
Projects
None yet
Development

No branches or pull requests

2 participants