[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 quarter = size / 4
// Construction of empty sets.
let setE: Set<Int> = []
let setOE: Set<Box<Int>> = []
// Construction kit for sets with 25% overlap
let setAB = Set(0 ..< size) // 0 ..< 400
let setCD = Set(size ..< 2 * size) // 400 ..< 800
@@ -53,6 +57,11 @@ let setQ: Set<Int> = {
public let SetTests = [
// 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(
name: "SetIsSubsetInt0",
runFunction: { n in run_SetIsSubsetInt(setAB, setCD, false, 5000 * n) },
@@ -84,6 +93,47 @@ public let SetTests = [
tags: [.validation, .api, .Set],
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(
name: "SetSymmetricDifferenceInt0",
runFunction: { n in run_SetSymmetricDifferenceInt(setAB, setCD, countABCD, 10 * n) },
@@ -177,6 +227,16 @@ public let SetTests = [
tags: [.validation, .api, .Set],
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(
name: "SetSubtractingInt0",
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 {
var value: T
@@ -371,3 +443,15 @@ func run_SetSubtractingBox(
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
public func isSubset<S: Sequence>(of possibleSuperset: S) -> Bool
where S.Element == Element {
// FIXME(performance): isEmpty fast path, here and elsewhere.
guard !isEmpty else { return true }
let other = Set(possibleSuperset)
return isSubset(of: other)
}
@@ -763,10 +764,12 @@ extension Set: SetAlgebra {
@inlinable
public func isSuperset<S: Sequence>(of possibleSubset: __owned S) -> Bool
where S.Element == Element {
// FIXME(performance): Don't build a set; just ask if every element is in
// `self`.
let other = Set(possibleSubset)
return other.isSubset(of: self)
for member in possibleSubset {
if !contains(member) {
return false
}
}
return true
}
/// Returns a Boolean value that indicates whether the set is a strict
@@ -811,9 +814,7 @@ extension Set: SetAlgebra {
@inlinable
public func isDisjoint<S: Sequence>(with other: S) -> Bool
where S.Element == Element {
// FIXME(performance): Don't need to build a set.
let otherSet = Set(other)
return isDisjoint(with: otherSet)
return _isDisjoint(with: other)
}
/// Returns a new set with the elements of both this set and the given
@@ -920,6 +921,10 @@ extension Set: SetAlgebra {
@inlinable
internal mutating func _subtract<S: Sequence>(_ other: S)
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 {
remove(item)
}
@@ -1121,8 +1126,16 @@ extension Set {
/// otherwise, `false`.
@inlinable
public func isDisjoint(with other: Set<Element>) -> Bool {
for member in self {
if other.contains(member) {
return _isDisjoint(with: other)
}
@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
}
}