Skip to content

Eliminate Sequence.SubSequence + Use @_borrowed #20454

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

Closed
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
6 changes: 5 additions & 1 deletion lib/SILOptimizer/Transforms/PerformanceInliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,12 @@ bool SILPerformanceInliner::isProfitableToInline(
int BaseBenefit = RemovedCallBenefit;

// Osize heuristic.
//
// As a hack, don't apply this at all to coroutine inlining; avoiding
// coroutine allocation overheads is extremely valuable. There might be
// more principled ways of getting this effect.
bool isClassMethodAtOsize = false;
if (OptMode == OptimizationMode::ForSize) {
if (OptMode == OptimizationMode::ForSize && !isa<BeginApplyInst>(AI)) {
// Don't inline into thunks.
if (AI.getFunction()->isThunk())
return false;
Expand Down
14 changes: 0 additions & 14 deletions stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1643,14 +1643,6 @@ extension TestSuite {

testNamePrefix += String(describing: S.Type.self)

let isMultiPass = makeSequence([])
._preprocessingPass { true } ?? false
let isEquatableMultiPass = makeSequenceOfEquatable([])
._preprocessingPass { true } ?? false
expectEqual(
isMultiPass, isEquatableMultiPass,
"Two sequence types are of different kinds?")

// FIXME: swift-3-indexing-model: add tests for `underestimatedCount`
// Check that it is non-negative, and an underestimate of the actual
// element count.
Expand All @@ -1667,12 +1659,6 @@ self.test("\(testNamePrefix).contains()/WhereElementIsEquatable/semantics") {
test.expected != nil,
s.contains(wrapValueIntoEquatable(test.element)),
stackTrace: SourceLocStack().with(test.loc))

if !isMultiPass {
expectEqualSequence(
test.expectedLeftoverSequence, s.map(extractValueFromEquatable),
stackTrace: SourceLocStack().with(test.loc))
}
}
}

Expand Down
49 changes: 1 addition & 48 deletions stdlib/private/StdlibCollectionUnittest/LoggingWrappers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ public class SequenceLog {
public static var prefixWhile = TypeIndexed(0)
public static var prefixMaxLength = TypeIndexed(0)
public static var suffixMaxLength = TypeIndexed(0)
public static var split = TypeIndexed(0)
public static var _customContainsEquatableElement = TypeIndexed(0)
public static var _preprocessingPass = TypeIndexed(0)
public static var _copyToContiguousArray = TypeIndexed(0)
Expand Down Expand Up @@ -202,7 +201,6 @@ extension LoggingSequence: LoggingType {
extension LoggingSequence: Sequence {
public typealias Element = Base.Element
public typealias Iterator = LoggingIterator<Base.Iterator>
public typealias SubSequence = Base.SubSequence

public func makeIterator() -> Iterator {
SequenceLog.makeIterator[selfType] += 1
Expand All @@ -214,52 +212,6 @@ extension LoggingSequence: Sequence {
return base.underestimatedCount
}

public func dropFirst(_ n: Int) -> SubSequence {
SequenceLog.dropFirst[selfType] += 1
return base.dropFirst(n)
}

public func dropLast(_ n: Int) -> SubSequence {
SequenceLog.dropLast[selfType] += 1
return base.dropLast(n)
}

public func drop(
while predicate: (Element) throws -> Bool
) rethrows -> SubSequence {
SequenceLog.dropWhile[selfType] += 1
return try base.drop(while: predicate)
}

public func prefix(_ maxLength: Int) -> SubSequence {
SequenceLog.prefixMaxLength[selfType] += 1
return base.prefix(maxLength)
}

public func prefix(
while predicate: (Element) throws -> Bool
) rethrows -> SubSequence {
SequenceLog.prefixWhile[selfType] += 1
return try base.prefix(while: predicate)
}

public func suffix(_ maxLength: Int) -> SubSequence {
SequenceLog.suffixMaxLength[selfType] += 1
return base.suffix(maxLength)
}

public func split(
maxSplits: Int = Int.max,
omittingEmptySubsequences: Bool = true,
whereSeparator isSeparator: (Element) throws -> Bool
) rethrows -> [SubSequence] {
SequenceLog.split[selfType] += 1
return try base.split(
maxSplits: maxSplits,
omittingEmptySubsequences: omittingEmptySubsequences,
whereSeparator: isSeparator)
}

public func _customContainsEquatableElement(_ element: Element) -> Bool? {
SequenceLog._customContainsEquatableElement[selfType] += 1
return base._customContainsEquatableElement(element)
Expand Down Expand Up @@ -297,6 +249,7 @@ public typealias LoggingCollection<Base: Collection> = LoggingSequence<Base>
extension LoggingCollection: Collection {
public typealias Index = Base.Index
public typealias Indices = Base.Indices
public typealias SubSequence = Base.SubSequence

public var startIndex: Index {
CollectionLog.startIndex[selfType] += 1
Expand Down
3 changes: 1 addition & 2 deletions stdlib/private/StdlibUnittest/StdlibUnittest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -499,8 +499,7 @@ public func expectMutableSliceType<X : MutableCollection>(
/// to be.
public func expectSequenceAssociatedTypes<X : Sequence>(
sequenceType: X.Type,
iteratorType: X.Iterator.Type,
subSequenceType: X.SubSequence.Type
iteratorType: X.Iterator.Type
) {}

/// Check that all associated types of a `Collection` are what we expect them
Expand Down
9 changes: 5 additions & 4 deletions stdlib/public/SDK/CoreAudio/CoreAudio.swift
Original file line number Diff line number Diff line change
Expand Up @@ -151,16 +151,17 @@ extension UnsafeMutableAudioBufferListPointer
}

/// Access an indexed `AudioBuffer` (`mBuffers[i]`).
@_borrowed
public subscript(index: Index) -> Element {
get {
_read {
precondition(index >= 0 && index < self.count,
"subscript index out of range")
return (_audioBuffersPointer + index).pointee
yield ((_audioBuffersPointer + index).pointee)
}
nonmutating set(newValue) {
nonmutating _modify {
precondition(index >= 0 && index < self.count,
"subscript index out of range")
(_audioBuffersPointer + index).pointee = newValue
yield (&(_audioBuffersPointer + index).pointee)
}
}
}
Expand Down
1 change: 0 additions & 1 deletion stdlib/public/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ set(SWIFTLIB_ESSENTIAL
SipHash.swift
Sequence.swift
SequenceAlgorithms.swift
SequenceWrapper.swift
Set.swift
SetAlgebra.swift
SetAnyHashableExtensions.swift
Expand Down
14 changes: 9 additions & 5 deletions stdlib/public/core/Collection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ extension IndexingIterator: IteratorProtocol, Sequence {
/// or bidirectional collection must traverse the entire collection to count
/// the number of contained elements, accessing its `count` property is an
/// O(*n*) operation.
public protocol Collection: Sequence where SubSequence: Collection {
public protocol Collection: Sequence {
// FIXME: ideally this would be in MigrationSupport.swift, but it needs
// to be on the protocol instead of as an extension
@available(*, deprecated/*, obsoleted: 5.0*/, message: "all index distances are now of type Int")
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this still the case?

Copy link
Member Author

Choose a reason for hiding this comment

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

You mean the commented out obsolete part? I need to go through and remove all those – but that's not an ABI thing so not as urgent as some other stuff.

Expand Down Expand Up @@ -390,7 +390,10 @@ public protocol Collection: Sequence where SubSequence: Collection {
/// This associated type appears as a requirement in the `Sequence`
/// protocol, but it is restated here with stricter constraints. In a
/// collection, the subsequence should also conform to `Collection`.
associatedtype SubSequence = Slice<Self> where SubSequence.Index == Index
associatedtype SubSequence: Collection = Slice<Self>
where SubSequence.Index == Index,
Element == SubSequence.Element,
SubSequence.SubSequence == SubSequence

/// Accesses the element at the specified position.
///
Expand All @@ -411,6 +414,7 @@ public protocol Collection: Sequence where SubSequence: Collection {
/// `endIndex` property.
///
/// - Complexity: O(1)
@_borrowed
subscript(position: Index) -> Element { get }

/// Accesses a contiguous subrange of the collection's elements.
Expand Down Expand Up @@ -1226,7 +1230,7 @@ extension Collection {
/// `RandomAccessCollection`; otherwise, O(*k*), where *k* is the number of
/// elements to drop from the beginning of the collection.
@inlinable
public __consuming func dropFirst(_ k: Int) -> SubSequence {
public __consuming func dropFirst(_ k: Int = 1) -> SubSequence {
_precondition(k >= 0, "Can't drop a negative number of elements from a collection")
let start = index(startIndex, offsetBy: k, limitedBy: endIndex) ?? endIndex
return self[start..<endIndex]
Expand All @@ -1253,15 +1257,15 @@ extension Collection {
/// `RandomAccessCollection`; otherwise, O(*n*), where *n* is the length of
/// the collection.
@inlinable
public __consuming func dropLast(_ k: Int) -> SubSequence {
public __consuming func dropLast(_ k: Int = 1) -> SubSequence {
_precondition(
k >= 0, "Can't drop a negative number of elements from a collection")
let amount = Swift.max(0, count - k)
let end = index(startIndex,
offsetBy: amount, limitedBy: endIndex) ?? endIndex
return self[startIndex..<end]
}

/// Returns a subsequence by skipping elements while `predicate` returns
/// `true` and returning the remaining elements.
///
Expand Down
3 changes: 3 additions & 0 deletions stdlib/public/core/Dictionary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,8 @@ extension Dictionary {
}

extension Dictionary: Collection {
public typealias SubSequence = Slice<Dictionary>

/// The position of the first element in a nonempty dictionary.
///
/// If the collection is empty, `startIndex` is equal to `endIndex`.
Expand Down Expand Up @@ -1321,6 +1323,7 @@ extension Dictionary {
: Collection, Equatable,
CustomStringConvertible, CustomDebugStringConvertible {
public typealias Element = Key
public typealias SubSequence = Slice<Dictionary.Keys>

@usableFromInline
internal var _variant: Dictionary<Key, Value>._Variant
Expand Down
117 changes: 9 additions & 108 deletions stdlib/public/core/DropWhile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ extension LazyDropWhileSequence.Iterator: IteratorProtocol {
}

extension LazyDropWhileSequence: Sequence {
public typealias SubSequence = AnySequence<Element> // >:(

/// Returns an iterator over the elements of this sequence.
///
/// - Complexity: O(1).
Expand Down Expand Up @@ -119,140 +117,43 @@ extension LazySequenceProtocol {
/// performance given by the `Collection` protocol. Be aware, therefore,
/// that general operations on lazy collections may not have the
/// documented complexity.
@_fixed_layout // lazy-performance
public struct LazyDropWhileCollection<Base: Collection> {
public typealias Element = Base.Element

@inlinable // lazy-performance
internal init(_base: Base, predicate: @escaping (Element) -> Bool) {
self._base = _base
self._predicate = predicate
}

@usableFromInline // lazy-performance
internal var _base: Base
@usableFromInline // lazy-performance
internal let _predicate: (Element) -> Bool
}
public typealias LazyDropWhileCollection<T: Collection> = LazyDropWhileSequence<T>

extension LazyDropWhileCollection: Sequence {
public typealias Iterator = LazyDropWhileSequence<Base>.Iterator

/// Returns an iterator over the elements of this sequence.
///
/// - Complexity: O(1).
@inlinable // lazy-performance
public __consuming func makeIterator() -> Iterator {
return Iterator(_base: _base.makeIterator(), predicate: _predicate)
}
}

extension LazyDropWhileCollection {
extension LazyDropWhileCollection: Collection {
public typealias SubSequence = Slice<LazyDropWhileCollection<Base>>
public typealias Index = Base.Index

/// A position in a `LazyDropWhileCollection` or
/// `LazyDropWhileBidirectionalCollection` instance.
@_fixed_layout // lazy-performance
public struct Index {
/// The position corresponding to `self` in the underlying collection.
public let base: Base.Index

@inlinable // lazy-performance
internal init(_base: Base.Index) {
self.base = _base
}
}
}

extension LazyDropWhileCollection.Index: Equatable, Comparable {
@inlinable // lazy-performance
public static func == (
lhs: LazyDropWhileCollection<Base>.Index,
rhs: LazyDropWhileCollection<Base>.Index
) -> Bool {
return lhs.base == rhs.base
}

@inlinable // lazy-performance
public static func < (
lhs: LazyDropWhileCollection<Base>.Index,
rhs: LazyDropWhileCollection<Base>.Index
) -> Bool {
return lhs.base < rhs.base
}
}

extension LazyDropWhileCollection.Index: Hashable where Base.Index: Hashable {
/// The hash value.
@inlinable
public var hashValue: Int {
return base.hashValue
}

/// Hashes the essential components of this value by feeding them into the
/// given hasher.
///
/// - Parameter hasher: The hasher to use when combining the components
/// of this instance.
@inlinable
public func hash(into hasher: inout Hasher) {
hasher.combine(base)
}
}

extension LazyDropWhileCollection: Collection {
@inlinable // lazy-performance
public var startIndex: Index {
var index = _base.startIndex
while index != _base.endIndex && _predicate(_base[index]) {
_base.formIndex(after: &index)
}
return Index(_base: index)
return index
}

@inlinable // lazy-performance
public var endIndex: Index {
return Index(_base: _base.endIndex)
return _base.endIndex
}

@inlinable // lazy-performance
public func index(after i: Index) -> Index {
_precondition(i.base < _base.endIndex, "Can't advance past endIndex")
return Index(_base: _base.index(after: i.base))
_precondition(i < _base.endIndex, "Can't advance past endIndex")
return _base.index(after: i)
}


@inlinable // lazy-performance
public subscript(position: Index) -> Element {
return _base[position.base]
return _base[position]
}
}

extension LazyDropWhileCollection: LazyCollectionProtocol { }

extension LazyDropWhileCollection: BidirectionalCollection
where Base: BidirectionalCollection {
@inlinable // lazy-performance
public func index(before i: Index) -> Index {
_precondition(i > startIndex, "Can't move before startIndex")
return Index(_base: _base.index(before: i.base))
return _base.index(before: i)
}
}

extension LazyCollectionProtocol {
/// Returns a lazy collection that skips any initial elements that satisfy
/// `predicate`.
///
/// - Parameter predicate: A closure that takes an element of the collection
/// as its argument and returns `true` if the element should be skipped or
/// `false` otherwise. Once `predicate` returns `false` it will not be
/// called again.
@inlinable // lazy-performance
public __consuming func drop(
while predicate: @escaping (Elements.Element) -> Bool
) -> LazyDropWhileCollection<Self.Elements> {
return LazyDropWhileCollection(
_base: self.elements, predicate: predicate)
}
}

Loading