diff --git a/Benchmarks/Benchmarks/OrderedSetBenchmarks.swift b/Benchmarks/Benchmarks/OrderedSetBenchmarks.swift index 2717dc461..eff65f571 100644 --- a/Benchmarks/Benchmarks/OrderedSetBenchmarks.swift +++ b/Benchmarks/Benchmarks/OrderedSetBenchmarks.swift @@ -269,6 +269,25 @@ extension Benchmark { } } + for percent in [0, 25, 50, 75, 100] { + self.add( + title: "OrderedSet filter keeping \(percent)%", + input: [Int].self + ) { input in + let set = OrderedSet(input) + return { timer in + var r: OrderedSet! + timer.measure { + r = set.filter { $0 % 100 < percent } + } + let div = input.count / 100 + let rem = input.count % 100 + precondition(r.count == percent * div + Swift.min(rem, percent)) + blackHole(r) + } + } + } + let overlaps: [(String, (Int) -> Int)] = [ ("0%", { c in c }), ("25%", { c in 3 * c / 4 }), diff --git a/Sources/OrderedCollections/OrderedSet/OrderedSet.swift b/Sources/OrderedCollections/OrderedSet/OrderedSet.swift index 25cc22f42..046228a23 100644 --- a/Sources/OrderedCollections/OrderedSet/OrderedSet.swift +++ b/Sources/OrderedCollections/OrderedSet/OrderedSet.swift @@ -508,13 +508,15 @@ extension OrderedSet { /// - Complexity: O(`count`) @inlinable public func filter( - _ isIncluded: (Element) throws -> Bool + _ isIncluded: (Element) throws -> Bool ) rethrows -> Self { - var result: OrderedSet = Self(minimumCapacity: _minimumCapacity) - for element in self where try isIncluded(element) { - result._appendNew(element) + try _UnsafeBitset.withTemporaryBitset(capacity: self.count) { bitset in + for i in _elements.indices where try isIncluded(_elements[i]) { + bitset.insert(i) + } + let result = self._extractSubset(using: bitset) + result._checkInvariants() + return result } - result._checkInvariants() - return result } }