Skip to content

Commit

Permalink
Use binary search for removing elements from Bag (#878)
Browse files Browse the repository at this point in the history
  • Loading branch information
nickoto authored Oct 11, 2023
1 parent 6b38733 commit 74dce06
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 3 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ jobs:
swiftpm-linux:
strategy:
matrix:
swift: ["5.2", "5.7"]
swift: ["5.7"]

name: SwiftPM Linux
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
steps:
- name: Setup Swift version
uses: swift-actions/setup-swift@v1
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

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

# 7.1.1
1. Bumped deployment target to iOS 11, tvOS 11, watchOS 4, macOS 10.13, per Xcode 14 warnings (#865, kudos to @lickel)
Expand Down
34 changes: 33 additions & 1 deletion Sources/Bag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,45 @@ public struct Bag<Element> {
/// - token: A token returned from a call to `insert()`.
@discardableResult
public mutating func remove(using token: Token) -> Element? {
guard let index = indices.first(where: { tokens[$0] == token.value }) else {
// Given that tokens are always added to the end of the array and have a monotonically
// increasing value, this list is always sorted, so we can use a binary search to improve
// performance if this list gets large.
guard let index = binarySearch(tokens, value: token.value) else {
return nil
}

tokens.remove(at: index)
return elements.remove(at: index)
}

/// Perform a binary search on a sorted array returning the index of a value.
///
/// - parameters:
/// - input: The sorted array to search for `value`
/// - value: The value to find in the sorted `input` array
///
/// - returns: The index of the `value` or `nil`
private func binarySearch(_ input:ContiguousArray<UInt64>, value: UInt64) -> Int? {
var lower = 0
var upper = input.count - 1

while (true) {
let current = (lower + upper)/2
if(input[current] == value) {
return current
}

if (lower > upper) {
return nil
}

if (input[current] > value) {
upper = current - 1
} else {
lower = current + 1
}
}
}
}

extension Bag: RandomAccessCollection {
Expand Down

0 comments on commit 74dce06

Please sign in to comment.