[stdlib] Resolving some FIXME comments on Set type. (#20631)

* Fixing some fixmes on stdlib Set

* Adding @inline attr

* Fixing spaces

* Adding isEmpty as fast path in other places where is possible.

* Quotes on variable name on comment.

* Update stdlib/public/core/Set.swift

Co-Authored-By: LucianoPAlmeida <passos.luciano@outlook.com>

* Adding benchmark for isDisjoint Set method

* Adding empty sets to benchmark

* Fixing the factor on benchmarks and naming warnings for empty 5 words
This commit is contained in:
Luciano Almeida
2018-12-15 02:11:12 -02:00
committed by Nate Cook
parent 5c7fd17c3c
commit 2bc5623bdf
2 changed files with 107 additions and 10 deletions

View File

@@ -16,6 +16,10 @@ let size = 400
let half = size / 2 let half = size / 2
let quarter = size / 4 let quarter = size / 4
// Construction of empty sets.
let setE: Set<Int> = []
let setOE: Set<Box<Int>> = []
// Construction kit for sets with 25% overlap // Construction kit for sets with 25% overlap
let setAB = Set(0 ..< size) // 0 ..< 400 let setAB = Set(0 ..< size) // 0 ..< 400
let setCD = Set(size ..< 2 * size) // 400 ..< 800 let setCD = Set(size ..< 2 * size) // 400 ..< 800
@@ -53,6 +57,11 @@ let setQ: Set<Int> = {
public let SetTests = [ public let SetTests = [
// Mnemonic: number after name is percentage of common elements in input sets. // Mnemonic: number after name is percentage of common elements in input sets.
BenchmarkInfo(
name: "Set.Empty.IsSubsetInt0",
runFunction: { n in run_SetIsSubsetInt(setE, setAB, true, 5000 * n) },
tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setE, setAB]) }),
BenchmarkInfo( BenchmarkInfo(
name: "SetIsSubsetInt0", name: "SetIsSubsetInt0",
runFunction: { n in run_SetIsSubsetInt(setAB, setCD, false, 5000 * n) }, runFunction: { n in run_SetIsSubsetInt(setAB, setCD, false, 5000 * n) },
@@ -84,6 +93,47 @@ public let SetTests = [
tags: [.validation, .api, .Set], tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setP, setQ]) }), setUpFunction: { blackHole([setP, setQ]) }),
BenchmarkInfo(
name: "Set.Empty.IsDisjointInt0",
runFunction: { n in run_SetIsDisjointInt(setE, setAB, true, 50 * n) },
tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setE, setAB]) }),
BenchmarkInfo(
name: "Set.Empty.IsDisjointBox0",
runFunction: { n in run_SetIsDisjointBox(setOE, setOAB, true, 50 * n) },
tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setOE, setOAB]) }),
BenchmarkInfo(
name: "SetIsDisjointInt0",
runFunction: { n in run_SetIsDisjointInt(setAB, setCD, true, 50 * n) },
tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setAB, setCD]) }),
BenchmarkInfo(
name: "SetIsDisjointBox0",
runFunction: { n in run_SetIsDisjointBox(setOAB, setOCD, true, 50 * n) },
tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setOAB, setOCD]) }),
BenchmarkInfo(
name: "SetIsDisjointInt25",
runFunction: { n in run_SetIsDisjointInt(setB, setAB, false, 50 * n) },
tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setB, setAB]) }),
BenchmarkInfo(
name: "SetIsDisjointBox25",
runFunction: { n in run_SetIsDisjointBox(setOB, setOAB, false, 50 * n) },
tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setOB, setOAB]) }),
BenchmarkInfo(
name: "SetIsDisjointInt50",
runFunction: { n in run_SetIsDisjointInt(setY, setXY, false, 50 * n) },
tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setY, setXY]) }),
BenchmarkInfo(
name: "SetIsDisjointInt100",
runFunction: { n in run_SetIsDisjointInt(setP, setQ, false, 50 * n) },
tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setP, setQ]) }),
BenchmarkInfo( BenchmarkInfo(
name: "SetSymmetricDifferenceInt0", name: "SetSymmetricDifferenceInt0",
runFunction: { n in run_SetSymmetricDifferenceInt(setAB, setCD, countABCD, 10 * n) }, runFunction: { n in run_SetSymmetricDifferenceInt(setAB, setCD, countABCD, 10 * n) },
@@ -177,6 +227,16 @@ public let SetTests = [
tags: [.validation, .api, .Set], tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setP, setQ]) }), setUpFunction: { blackHole([setP, setQ]) }),
BenchmarkInfo(
name: "Set.Empty.SubtractingInt0",
runFunction: { n in run_SetSubtractingInt(setE, setAB, 0, 10 * n) },
tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setE, setAB]) }),
BenchmarkInfo(
name: "Set.Empty.SubtractingBox0",
runFunction: { n in run_SetSubtractingBox(setOE, setOAB, 0, 10 * n) },
tags: [.validation, .api, .Set],
setUpFunction: { blackHole([setOE, setOAB]) }),
BenchmarkInfo( BenchmarkInfo(
name: "SetSubtractingInt0", name: "SetSubtractingInt0",
runFunction: { n in run_SetSubtractingInt(setAB, setCD, countAB, 10 * n) }, runFunction: { n in run_SetSubtractingInt(setAB, setCD, countAB, 10 * n) },
@@ -296,6 +356,18 @@ public func run_SetSubtractingInt(
} }
} }
@inline(never)
public func run_SetIsDisjointInt(
_ a: Set<Int>,
_ b: Set<Int>,
_ r: Bool,
_ n: Int) {
for _ in 0 ..< n {
let isDisjoint = a.isDisjoint(with: identity(b))
CheckResults(isDisjoint == r)
}
}
class Box<T : Hashable> : Hashable { class Box<T : Hashable> : Hashable {
var value: T var value: T
@@ -371,3 +443,15 @@ func run_SetSubtractingBox(
CheckResults(and.count == r) CheckResults(and.count == r)
} }
} }
@inline(never)
func run_SetIsDisjointBox(
_ a: Set<Box<Int>>,
_ b: Set<Box<Int>>,
_ r: Bool,
_ n: Int) {
for _ in 0 ..< n {
let isDisjoint = a.isDisjoint(with: identity(b))
CheckResults(isDisjoint == r)
}
}

View File

@@ -712,7 +712,8 @@ extension Set: SetAlgebra {
@inlinable @inlinable
public func isSubset<S: Sequence>(of possibleSuperset: S) -> Bool public func isSubset<S: Sequence>(of possibleSuperset: S) -> Bool
where S.Element == Element { where S.Element == Element {
// FIXME(performance): isEmpty fast path, here and elsewhere. guard !isEmpty else { return true }
let other = Set(possibleSuperset) let other = Set(possibleSuperset)
return isSubset(of: other) return isSubset(of: other)
} }
@@ -763,10 +764,12 @@ extension Set: SetAlgebra {
@inlinable @inlinable
public func isSuperset<S: Sequence>(of possibleSubset: __owned S) -> Bool public func isSuperset<S: Sequence>(of possibleSubset: __owned S) -> Bool
where S.Element == Element { where S.Element == Element {
// FIXME(performance): Don't build a set; just ask if every element is in for member in possibleSubset {
// `self`. if !contains(member) {
let other = Set(possibleSubset) return false
return other.isSubset(of: self) }
}
return true
} }
/// Returns a Boolean value that indicates whether the set is a strict /// Returns a Boolean value that indicates whether the set is a strict
@@ -811,9 +814,7 @@ extension Set: SetAlgebra {
@inlinable @inlinable
public func isDisjoint<S: Sequence>(with other: S) -> Bool public func isDisjoint<S: Sequence>(with other: S) -> Bool
where S.Element == Element { where S.Element == Element {
// FIXME(performance): Don't need to build a set. return _isDisjoint(with: other)
let otherSet = Set(other)
return isDisjoint(with: otherSet)
} }
/// Returns a new set with the elements of both this set and the given /// Returns a new set with the elements of both this set and the given
@@ -920,6 +921,10 @@ extension Set: SetAlgebra {
@inlinable @inlinable
internal mutating func _subtract<S: Sequence>(_ other: S) internal mutating func _subtract<S: Sequence>(_ other: S)
where S.Element == Element { where S.Element == Element {
// If self is empty we don't need to iterate over `other` because there's
// nothing to remove on self.
guard !isEmpty else { return }
for item in other { for item in other {
remove(item) remove(item)
} }
@@ -1121,8 +1126,16 @@ extension Set {
/// otherwise, `false`. /// otherwise, `false`.
@inlinable @inlinable
public func isDisjoint(with other: Set<Element>) -> Bool { public func isDisjoint(with other: Set<Element>) -> Bool {
for member in self { return _isDisjoint(with: other)
if other.contains(member) { }
@inlinable
internal func _isDisjoint<S: Sequence>(with other: S) -> Bool
where S.Element == Element {
guard !isEmpty else { return true }
for member in other {
if contains(member) {
return false return false
} }
} }