mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
stdlib: add a hook for dynamic dispatch in CollectionType.find()
This hook allows Set.find() to be equally efficient in static and generic contexts. This time, with correct tests. Swift SVN r27404
This commit is contained in:
@@ -2292,6 +2292,132 @@ SequenceTypeAlgorithms.test("find/WhereElementIsEquatable/${dispatch}") {
|
||||
|
||||
% end
|
||||
|
||||
struct CollectionWithCustomFindMethod : CollectionType {
|
||||
static var timesFindWasCalled: 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()
|
||||
}
|
||||
|
||||
var startIndex: MinimalForwardIndex {
|
||||
return MinimalForwardIndex(
|
||||
position: 0, startIndex: 0, endIndex: _elements.endIndex)
|
||||
}
|
||||
|
||||
var endIndex: MinimalForwardIndex {
|
||||
return MinimalForwardIndex(
|
||||
position: _elements.endIndex,
|
||||
startIndex: 0,
|
||||
endIndex: _elements.endIndex)
|
||||
}
|
||||
|
||||
subscript(i: MinimalForwardIndex) -> MinimalEquatableValue {
|
||||
return MinimalEquatableValue(_elements[i.position])
|
||||
}
|
||||
|
||||
func _customFindEquatableElement(
|
||||
element: MinimalEquatableValue
|
||||
) -> MinimalForwardIndex?? {
|
||||
++CollectionWithCustomFindMethod.timesFindWasCalled
|
||||
for i in _elements._prext_indices {
|
||||
if _elements[i] == element.value {
|
||||
return MinimalForwardIndex(
|
||||
position: i,
|
||||
startIndex: 0,
|
||||
endIndex: _elements.endIndex)
|
||||
}
|
||||
}
|
||||
return Optional(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func callStaticFind(
|
||||
sequence: CollectionWithCustomFindMethod,
|
||||
element: MinimalEquatableValue
|
||||
) -> CollectionWithCustomFindMethod.Index? {
|
||||
return sequence._prext_find(element)
|
||||
}
|
||||
|
||||
% for dispatch in [ 'Static', 'Generic' ]:
|
||||
|
||||
SequenceTypeAlgorithms.test("find/WhereElementIsEquatable/CustomImplementation/${dispatch}") {
|
||||
for test in findTests {
|
||||
let s = CollectionWithCustomFindMethod(test.sequence)
|
||||
CollectionWithCustomFindMethod.timesFindWasCalled = 0
|
||||
expectEqual(
|
||||
test.expected,
|
||||
call${dispatch}Find(s, MinimalEquatableValue(test.element))
|
||||
.map { $0.position },
|
||||
stackTrace: test.loc.withCurrentLoc())
|
||||
expectEqual(1, CollectionWithCustomFindMethod.timesFindWasCalled)
|
||||
}
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
// FIXME: underscores are a workaround for:
|
||||
// <rdar://problem/20582358> Commenting out one line determines whether a
|
||||
// completely different line type-checks
|
||||
func callGenericFind_<
|
||||
C : CollectionType where C.Generator.Element : Equatable
|
||||
>(collection: C, element: C.Generator.Element) -> C.Index? {
|
||||
return collection._prext_find(element)
|
||||
}
|
||||
|
||||
func callStaticFind_(
|
||||
set: Set<MinimalHashableValue>,
|
||||
element: MinimalHashableValue
|
||||
) -> Set<MinimalHashableValue>.Index? {
|
||||
return set._prext_find(element)
|
||||
}
|
||||
|
||||
% 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>.find/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
|
||||
.map { _ in MinimalHashableValue(test.element) },
|
||||
call${dispatch}Find_(s, MinimalHashableValue(test.element))
|
||||
.map { s[$0] },
|
||||
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("find/Predicate") {
|
||||
for test in findTests {
|
||||
let s = MinimalForwardCollection<MinimalEquatableValue>(
|
||||
|
||||
Reference in New Issue
Block a user