mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
stdlib: add an extension point for SequenceType.contains()
This makes the protocol extension as fast as static dispatch for Set.contains(). Swift SVN r27396
This commit is contained in:
@@ -82,6 +82,12 @@ extension _SequenceDefaultsType {
|
||||
final public func _prext_underestimateCount() -> Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
final public func _customContainsEquatableElement(
|
||||
element: Generator.Element
|
||||
) -> Bool? {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// This protocol is an implementation detail of `SequenceType`; do
|
||||
@@ -108,6 +114,10 @@ public protocol _Sequence_Type
|
||||
///
|
||||
/// Complexity: O(N)
|
||||
func _prext_underestimateCount() -> Int
|
||||
|
||||
func _customContainsEquatableElement(
|
||||
element: Generator.Element
|
||||
) -> Bool?
|
||||
}
|
||||
|
||||
/// A type that can be iterated with a `for`\ ...\ `in` loop.
|
||||
|
||||
@@ -632,6 +632,14 @@ public struct Set<T : Hashable> :
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
//
|
||||
// `SequenceType` conformance
|
||||
//
|
||||
|
||||
public func _customContainsEquatableElement(member: T) -> Bool? {
|
||||
return contains(member)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check for both subset and equality relationship between
|
||||
|
||||
@@ -261,7 +261,10 @@ extension SequenceType ${"" if preds else "where Self.Generator.Element : Compar
|
||||
extension SequenceType where Self.Generator.Element : Equatable {
|
||||
/// Return `true` iff `x` is in `self`.
|
||||
final public func _prext_contains(element: ${GElement}) -> Bool {
|
||||
// FIXME: dynamic dispatch for Set and Dictionary.
|
||||
if let result? = _customContainsEquatableElement(element) {
|
||||
return result
|
||||
}
|
||||
|
||||
for e in self {
|
||||
if e == element {
|
||||
return true
|
||||
|
||||
@@ -1179,6 +1179,93 @@ SequenceTypeAlgorithms.test("contains/WhereElementIsEquatable/${dispatch}") {
|
||||
|
||||
% end
|
||||
|
||||
struct SequenceWithCustomContainsMethod : SequenceType {
|
||||
static var timesContainsWasCalled: Int = 0
|
||||
|
||||
internal let _elements: [Int]
|
||||
|
||||
init(_ elements: [Int]) {
|
||||
self._elements = elements
|
||||
}
|
||||
|
||||
func generate() -> MinimalGenerator<MinimalEquatableValue> {
|
||||
// Lie from our generate() method about sequence contents.
|
||||
// Tests using this type should not call generate() anyway.
|
||||
expectUnreachable()
|
||||
return MinimalSequence<MinimalEquatableValue>([]).generate()
|
||||
}
|
||||
|
||||
func _customContainsEquatableElement(
|
||||
element: MinimalEquatableValue
|
||||
) -> Bool? {
|
||||
++SequenceWithCustomContainsMethod.timesContainsWasCalled
|
||||
for e in _elements {
|
||||
if e == element.value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func callStaticContains(
|
||||
sequence: SequenceWithCustomContainsMethod,
|
||||
element: MinimalEquatableValue) -> Bool {
|
||||
return sequence._prext_contains(element)
|
||||
}
|
||||
|
||||
% for dispatch in [ 'Static', 'Generic' ]:
|
||||
|
||||
SequenceTypeAlgorithms.test("contains/WhereElementIsEquatable/CustomImplementation/${dispatch}") {
|
||||
for test in findTests {
|
||||
let s = SequenceWithCustomContainsMethod(test.sequence)
|
||||
SequenceWithCustomContainsMethod.timesContainsWasCalled = 0
|
||||
expectEqual(
|
||||
test.expected != nil,
|
||||
call${dispatch}Contains(s, MinimalEquatableValue(test.element)),
|
||||
stackTrace: test.loc.withCurrentLoc())
|
||||
expectEqual(1, SequenceWithCustomContainsMethod.timesContainsWasCalled)
|
||||
}
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
% for dispatch in [ 'Static', 'Generic' ]:
|
||||
|
||||
// FIXME: implement the same optimization for Dictionary.
|
||||
// FIXME: move to the file where other Set tests live.
|
||||
SequenceTypeAlgorithms.test("Set<T>.contains/WhereElementIsEquatable/CustomImplementation/${dispatch}") {
|
||||
for test in findTests {
|
||||
let s = Set<MinimalHashableValue>(
|
||||
test.sequence.map { MinimalHashableValue($0) })
|
||||
MinimalHashableValue.timesEqualEqualWasCalled = 0
|
||||
MinimalHashableValue.timesHashValueWasCalled = 0
|
||||
expectEqual(
|
||||
test.expected != nil,
|
||||
s._prext_contains(MinimalHashableValue(test.element)),
|
||||
stackTrace: test.loc.withCurrentLoc())
|
||||
if test.sequence.isEmpty {
|
||||
expectEqual(
|
||||
0, MinimalHashableValue.timesEqualEqualWasCalled,
|
||||
stackTrace: test.loc.withCurrentLoc())
|
||||
expectEqual(
|
||||
0, MinimalHashableValue.timesHashValueWasCalled,
|
||||
stackTrace: test.loc.withCurrentLoc())
|
||||
} else {
|
||||
expectNotEqual(
|
||||
0, MinimalHashableValue.timesHashValueWasCalled,
|
||||
stackTrace: test.loc.withCurrentLoc())
|
||||
}
|
||||
if test.expected != nil {
|
||||
expectNotEqual(
|
||||
0, MinimalHashableValue.timesEqualEqualWasCalled,
|
||||
stackTrace: test.loc.withCurrentLoc())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
SequenceTypeAlgorithms.test("contains/Predicate") {
|
||||
for test in findTests {
|
||||
let s = MinimalSequence<OpaqueValue<Int>>(
|
||||
|
||||
Reference in New Issue
Block a user