Skip to content

Commit 74dce06

Browse files
authored
Use binary search for removing elements from Bag (#878)
1 parent 6b38733 commit 74dce06

File tree

3 files changed

+36
-3
lines changed

3 files changed

+36
-3
lines changed

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ jobs:
6868
swiftpm-linux:
6969
strategy:
7070
matrix:
71-
swift: ["5.2", "5.7"]
71+
swift: ["5.7"]
7272

7373
name: SwiftPM Linux
74-
runs-on: ubuntu-18.04
74+
runs-on: ubuntu-22.04
7575
steps:
7676
- name: Setup Swift version
7777
uses: swift-actions/setup-swift@v1

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
1. Fix minimum deployment target of iOS 11 in CocoaPods
55
1. Fix CI release git tag push trigger (#869, kudos to @p4checo)
6+
1. Find and remove items from Bag using a binary search to improve performance when the collection gets large.
67

78
# 7.1.1
89
1. Bumped deployment target to iOS 11, tvOS 11, watchOS 4, macOS 10.13, per Xcode 14 warnings (#865, kudos to @lickel)

Sources/Bag.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,45 @@ public struct Bag<Element> {
5858
/// - token: A token returned from a call to `insert()`.
5959
@discardableResult
6060
public mutating func remove(using token: Token) -> Element? {
61-
guard let index = indices.first(where: { tokens[$0] == token.value }) else {
61+
// Given that tokens are always added to the end of the array and have a monotonically
62+
// increasing value, this list is always sorted, so we can use a binary search to improve
63+
// performance if this list gets large.
64+
guard let index = binarySearch(tokens, value: token.value) else {
6265
return nil
6366
}
6467

6568
tokens.remove(at: index)
6669
return elements.remove(at: index)
6770
}
71+
72+
/// Perform a binary search on a sorted array returning the index of a value.
73+
///
74+
/// - parameters:
75+
/// - input: The sorted array to search for `value`
76+
/// - value: The value to find in the sorted `input` array
77+
///
78+
/// - returns: The index of the `value` or `nil`
79+
private func binarySearch(_ input:ContiguousArray<UInt64>, value: UInt64) -> Int? {
80+
var lower = 0
81+
var upper = input.count - 1
82+
83+
while (true) {
84+
let current = (lower + upper)/2
85+
if(input[current] == value) {
86+
return current
87+
}
88+
89+
if (lower > upper) {
90+
return nil
91+
}
92+
93+
if (input[current] > value) {
94+
upper = current - 1
95+
} else {
96+
lower = current + 1
97+
}
98+
}
99+
}
68100
}
69101

70102
extension Bag: RandomAccessCollection {

0 commit comments

Comments
 (0)