From ed9348ddb2394b53612157183147d1373e6aedb0 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Mon, 29 Jun 2020 10:32:04 -0500 Subject: [PATCH 1/3] Fix removeLast(_:) performance for non-random-access collections This replaces the `count` comparison precondition with a limited index offset, which converts the method from O(n) to O(k). --- .../public/core/BidirectionalCollection.swift | 9 +++++--- .../core/RangeReplaceableCollection.swift | 22 +++++++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/stdlib/public/core/BidirectionalCollection.swift b/stdlib/public/core/BidirectionalCollection.swift index 98b6cc89029b5..c702e3c5d5530 100644 --- a/stdlib/public/core/BidirectionalCollection.swift +++ b/stdlib/public/core/BidirectionalCollection.swift @@ -342,9 +342,12 @@ extension BidirectionalCollection where SubSequence == Self { public mutating func removeLast(_ k: Int) { if k == 0 { return } _precondition(k >= 0, "Number of elements to remove should be non-negative") - _precondition(count >= k, - "Can't remove more items from a collection than it contains") - self = self[startIndex.. Element? /// Customization point for `removeLast(_:)`. Implement this function if you /// want to replace the default implementation. /// + /// - Parameter n: The number of elements to remove from the collection. + /// `n` must be greater than or equal to zero and must not exceed the + /// number of elements in the collection. /// - Returns: `true` if the operation was performed. mutating func _customRemoveLast(_ n: Int) -> Bool @@ -802,7 +807,12 @@ extension RangeReplaceableCollection @inlinable public mutating func _customRemoveLast(_ n: Int) -> Bool { - self = self[startIndex..= 0, "Number of elements to remove should be non-negative") - _precondition(count >= k, - "Can't remove more items from a collection than it contains") if _customRemoveLast(k) { return } let end = endIndex - removeSubrange(index(end, offsetBy: -k).. Date: Mon, 29 Jun 2020 13:50:14 -0500 Subject: [PATCH 2/3] Update the other removeLast implementation --- stdlib/public/core/RangeReplaceableCollection.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/stdlib/public/core/RangeReplaceableCollection.swift b/stdlib/public/core/RangeReplaceableCollection.swift index add9cb50f8b81..24e6e4bc91bf5 100644 --- a/stdlib/public/core/RangeReplaceableCollection.swift +++ b/stdlib/public/core/RangeReplaceableCollection.swift @@ -950,12 +950,15 @@ where Self: BidirectionalCollection, SubSequence == Self { public mutating func removeLast(_ k: Int) { if k == 0 { return } _precondition(k >= 0, "Number of elements to remove should be non-negative") - _precondition(count >= k, - "Can't remove more items from a collection than it contains") if _customRemoveLast(k) { return } let end = endIndex + guard let start = index(end, offsetBy: -k, limitedBy: startIndex) + else { + _preconditionFailure( + "Can't remove more items from a collection than it contains") + } removeSubrange(index(end, offsetBy: -k).. Date: Wed, 1 Jul 2020 00:18:16 -0500 Subject: [PATCH 3/3] Update stdlib/public/core/RangeReplaceableCollection.swift Co-authored-by: Karoy Lorentey --- stdlib/public/core/RangeReplaceableCollection.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/core/RangeReplaceableCollection.swift b/stdlib/public/core/RangeReplaceableCollection.swift index 24e6e4bc91bf5..6ec6afaea0416 100644 --- a/stdlib/public/core/RangeReplaceableCollection.swift +++ b/stdlib/public/core/RangeReplaceableCollection.swift @@ -959,7 +959,7 @@ where Self: BidirectionalCollection, SubSequence == Self { _preconditionFailure( "Can't remove more items from a collection than it contains") } - removeSubrange(index(end, offsetBy: -k)..