Skip to content

Commit 81e0679

Browse files
authored
Merge pull request #17051 from dabrahams/algorithms-prototype-updates
2 parents 63c9cb9 + 7e1a05f commit 81e0679

File tree

1 file changed

+96
-64
lines changed

1 file changed

+96
-64
lines changed

test/Prototypes/Algorithms.swift

Lines changed: 96 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,48 @@ import StdlibUnittest
1818
//===--- Rotate -----------------------------------------------------------===//
1919
//===----------------------------------------------------------------------===//
2020

21+
public protocol CollectionAlgorithms : Collection
22+
where SubSequence : CollectionAlgorithms
23+
{
24+
func lastIndex(where predicate: (Element) throws->Bool) rethrows -> Index?
25+
func _indexAfterLastIndex(
26+
where predicate: (Element) throws->Bool
27+
) rethrows -> Index?
28+
}
29+
30+
extension Collection {
31+
public func lastIndex(
32+
where predicate: (Element) throws->Bool
33+
) rethrows -> Index? {
34+
return try indices.reduce(nil) {
35+
r, i in try predicate(self[i]) ? i as Optional : r
36+
}
37+
}
38+
39+
public func _indexAfterLastIndex(
40+
where predicate: (Element) throws->Bool
41+
) rethrows -> Index? {
42+
return try lastIndex(where: predicate).map { index(after: $0) }
43+
}
44+
}
45+
46+
extension BidirectionalCollection {
47+
public func lastIndex(
48+
where predicate: (Element) throws->Bool
49+
) rethrows -> Index? {
50+
return try indices.reversed().first { try predicate(self[$0]) }
51+
}
52+
53+
public func _indexAfterLastIndex(
54+
where predicate: (Element) throws->Bool
55+
) rethrows -> Index? {
56+
return try self.reversed().firstIndex(where: predicate)?.base
57+
}
58+
}
59+
2160
// In the stdlib, this would simply be MutableCollection
22-
public protocol MutableCollectionAlgorithms : MutableCollection
61+
public protocol MutableCollectionAlgorithms
62+
: MutableCollection, CollectionAlgorithms
2363
where SubSequence : MutableCollectionAlgorithms
2464
{
2565
/// Rotates the elements of the collection so that the element
@@ -36,7 +76,8 @@ public protocol MutableCollectionAlgorithms : MutableCollection
3676
extension Array : MutableCollectionAlgorithms { }
3777
extension ArraySlice : MutableCollectionAlgorithms { }
3878

39-
extension Slice : MutableCollectionAlgorithms where Base: MutableCollection { }
79+
extension Slice : MutableCollectionAlgorithms, CollectionAlgorithms
80+
where Base: MutableCollection { }
4081

4182
/// In the stdlib, this would simply be MutableCollection
4283
extension MutableCollectionAlgorithms {
@@ -516,64 +557,55 @@ extension Collection {
516557
//===--- Stable Partition -------------------------------------------------===//
517558
//===----------------------------------------------------------------------===//
518559

519-
extension BidirectionalCollection
520-
where Self : MutableCollectionAlgorithms {
560+
extension Collection
561+
where Self : MutableCollectionAlgorithms {
521562

522563
@discardableResult
523564
mutating func stablePartition(
524-
choosingStartGroupBy p: (Element) -> Bool
525-
) -> Index {
526-
return _stablePartition(
527-
distance: distance(from: startIndex, to: endIndex),
528-
choosingStartGroupBy: p
529-
)
530-
}
531-
532-
mutating func _stablePartition(
533-
distance n: Int,
534-
choosingStartGroupBy p: (Element) -> Bool
535-
) -> Index {
536-
assert(n >= 0)
537-
assert(n == distance(from: startIndex, to: endIndex))
538-
if n == 0 { return startIndex }
539-
if n == 1 {
540-
return p(self[startIndex]) ? endIndex : startIndex
565+
isSuffixElement: (Element) throws -> Bool
566+
) rethrows -> Index {
567+
return try stablePartition(
568+
count: count, isSuffixElement: isSuffixElement)
569+
}
570+
571+
/// Moves all elements satisfying `isSuffixElement` into a suffix of the collection,
572+
/// preserving their relative order, returning the start of the resulting suffix.
573+
///
574+
/// - Complexity: O(n) where n is the number of elements.
575+
/// - Precondition: `n == self.count`
576+
fileprivate mutating func stablePartition(
577+
count n: Int, isSuffixElement: (Element) throws-> Bool
578+
) rethrows -> Index {
579+
if n == 0 { return startIndex }
580+
if n == 1 {
581+
return try isSuffixElement(self[startIndex]) ? startIndex : endIndex
582+
}
583+
let h = n / 2, i = index(startIndex, offsetBy: h)
584+
let j = try self[..<i].stablePartition(
585+
count: h, isSuffixElement: isSuffixElement)
586+
let k = try self[i...].stablePartition(
587+
count: n - h, isSuffixElement: isSuffixElement)
588+
return self[j..<k].rotate(shiftingToStart: i)
541589
}
542-
543-
// divide and conquer.
544-
let d = n / numericCast(2)
545-
let m = index(startIndex, offsetBy: d)
546-
547-
// TTTTTTTTT s FFFFFFF m ?????????????
548-
let s = self[..<m]._stablePartition(
549-
distance: numericCast(d), choosingStartGroupBy: p)
550-
551-
// TTTTTTTTT s FFFFFFF m TTTTTTT e FFFFFFFF
552-
let e = self[m...]._stablePartition(
553-
distance: numericCast(n - d), choosingStartGroupBy: p)
554-
555-
// TTTTTTTTT s TTTTTTT m FFFFFFF e FFFFFFFF
556-
return self[s..<e].rotate(shiftingToStart: m)
557-
}
558590
}
559591

560592
extension Collection {
561-
func stablyPartitioned(
562-
choosingStartGroupBy p: (Element) -> Bool
563-
) -> [Element] {
564-
var a = Array(self)
565-
a.stablePartition(choosingStartGroupBy: p)
566-
return a
567-
}
593+
func stablyPartitioned(
594+
isSuffixElement p: (Element) -> Bool
595+
) -> [Element] {
596+
var a = Array(self)
597+
a.stablePartition(isSuffixElement: p)
598+
return a
599+
}
568600
}
569601

570602
extension LazyCollectionProtocol
571-
where Element == Elements.Element {
572-
func stablyPartitioned(
573-
choosingStartGroupBy p: (Element) -> Bool
574-
) -> LazyCollection<[Element]> {
575-
return elements.stablyPartitioned(choosingStartGroupBy: p).lazy
576-
}
603+
where Element == Elements.Element {
604+
func stablyPartitioned(
605+
isSuffixElement p: (Element) -> Bool
606+
) -> LazyCollection<[Element]> {
607+
return elements.stablyPartitioned(isSuffixElement: p).lazy
608+
}
577609
}
578610

579611
extension Collection {
@@ -722,41 +754,41 @@ suite.test("stablePartition") {
722754
let subrange = a[p..<q]
723755

724756
for modulus in 1...5 {
725-
let f = { $0 % modulus == 0 }
757+
let f = { $0 % modulus != 0 }
726758
let notf = { !f($0) }
727759

728760
var b = a
729761
b.reserveCapacity(b.count) // guarantee unique storage
730762
let id = address(b)
731763

732-
var r = b[p..<q].stablePartition(choosingStartGroupBy: f)
764+
var r = b[p..<q].stablePartition(isSuffixElement: f)
733765
expectEqual(b[..<p], prefix)
734766
expectEqual(b.suffix(from:q), suffix)
735-
expectEqual(b[p..<r], ArraySlice(subrange.filter(f)))
736-
expectEqual(b[r..<q], ArraySlice(subrange.filter(notf)))
767+
expectEqual(b[p..<r], ArraySlice(subrange.filter(notf)))
768+
expectEqual(b[r..<q], ArraySlice(subrange.filter(f)))
737769
expectEqual(address(b), id)
738770

739771
b = a
740-
r = b[p..<q].stablePartition(choosingStartGroupBy: notf)
772+
r = b[p..<q].stablePartition(isSuffixElement: notf)
741773
expectEqual(b[..<p], prefix)
742774
expectEqual(b.suffix(from:q), suffix)
743-
expectEqual(b[p..<r], ArraySlice(subrange.filter(notf)))
744-
expectEqual(b[r..<q], ArraySlice(subrange.filter(f)))
775+
expectEqual(b[p..<r], ArraySlice(subrange.filter(f)))
776+
expectEqual(b[r..<q], ArraySlice(subrange.filter(notf)))
745777
}
746778
}
747779

748780
for modulus in 1...5 {
749-
let f = { $0 % modulus == 0 }
781+
let f = { $0 % modulus != 0 }
750782
let notf = { !f($0) }
751783
var b = a
752-
var r = b.stablePartition(choosingStartGroupBy: f)
753-
expectEqual(b[..<r], ArraySlice(a.filter(f)))
754-
expectEqual(b[r...], ArraySlice(a.filter(notf)))
755-
756-
b = a
757-
r = b.stablePartition(choosingStartGroupBy: notf)
784+
var r = b.stablePartition(isSuffixElement: f)
758785
expectEqual(b[..<r], ArraySlice(a.filter(notf)))
759786
expectEqual(b[r...], ArraySlice(a.filter(f)))
787+
788+
b = a
789+
r = b.stablePartition(isSuffixElement: notf)
790+
expectEqual(b[..<r], ArraySlice(a.filter(f)))
791+
expectEqual(b[r...], ArraySlice(a.filter(notf)))
760792
}
761793
}
762794
}

0 commit comments

Comments
 (0)