Skip to content

Commit 3b6d832

Browse files
authored
Merge pull request #17073 from dabrahams/algorithms-standalone
2 parents e785319 + 9b7821d commit 3b6d832

File tree

1 file changed

+110
-87
lines changed

1 file changed

+110
-87
lines changed

test/Prototypes/Algorithms.swift

Lines changed: 110 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -9,57 +9,27 @@
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12-
// RUN: %target-run-stdlib-swift
12+
// RUN: %empty-directory(%t)
13+
// RUN: %target-build-swift -g -Onone -DUSE_STDLIBUNITTEST %s -o %t/a.out
14+
// RUN: %target-run %t/a.out
1315
// REQUIRES: executable_test
1416

17+
#if USE_STDLIBUNITTEST
1518
import Swift
1619
import StdlibUnittest
20+
#endif
1721

1822
//===--- Rotate -----------------------------------------------------------===//
1923
//===----------------------------------------------------------------------===//
2024

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-
60-
// In the stdlib, this would simply be MutableCollection
61-
public protocol MutableCollectionAlgorithms
62-
: MutableCollection, CollectionAlgorithms
25+
/// Provides customization points for `MutableCollection` algorithms.
26+
///
27+
/// If incorporated into the standard library, these requirements would just be
28+
/// part of `MutableCollection`. In the meantime, you can declare conformance
29+
/// of a collection to `MutableCollectionAlgorithms` to get these customization
30+
/// points to be used from other algorithms defined on
31+
/// `MutableCollectionAlgorithms`.
32+
public protocol MutableCollectionAlgorithms : MutableCollection
6333
where SubSequence : MutableCollectionAlgorithms
6434
{
6535
/// Rotates the elements of the collection so that the element
@@ -72,15 +42,14 @@ public protocol MutableCollectionAlgorithms
7242
mutating func rotate(shiftingToStart middle: Index) -> Index
7343
}
7444

75-
// In the stdlib, these conformances wouldn't be needed
45+
// Conformances of common collection types to MutableCollectionAlgorithms.
46+
// If rotate was a requirement of MutableCollection, these would not be needed.
7647
extension Array : MutableCollectionAlgorithms { }
7748
extension ArraySlice : MutableCollectionAlgorithms { }
78-
79-
extension Slice : MutableCollectionAlgorithms, CollectionAlgorithms
49+
extension Slice : MutableCollectionAlgorithms
8050
where Base: MutableCollection { }
8151

82-
/// In the stdlib, this would simply be MutableCollection
83-
extension MutableCollectionAlgorithms {
52+
extension MutableCollection {
8453
/// Swaps the elements of the two given subranges, up to the upper bound of
8554
/// the smaller subrange. The returned indices are the ends of the two ranges
8655
/// that were actually swapped.
@@ -557,55 +526,58 @@ extension Collection {
557526
//===--- Stable Partition -------------------------------------------------===//
558527
//===----------------------------------------------------------------------===//
559528

560-
extension Collection
561-
where Self : MutableCollectionAlgorithms {
562-
529+
extension MutableCollectionAlgorithms {
530+
/// Moves all elements satisfying `isSuffixElement` into a suffix of the
531+
/// collection, preserving their relative order, and returns the start of the
532+
/// resulting suffix.
533+
///
534+
/// - Complexity: O(n) where n is the number of elements.
563535
@discardableResult
564536
mutating func stablePartition(
565537
isSuffixElement: (Element) throws -> Bool
566538
) 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)
539+
return try stablePartition(count: count, isSuffixElement: isSuffixElement)
540+
}
541+
542+
/// Moves all elements satisfying `isSuffixElement` into a suffix of the
543+
/// collection, preserving their relative order, and returns the start of the
544+
/// resulting suffix.
545+
///
546+
/// - Complexity: O(n) where n is the number of elements.
547+
/// - Precondition: `n == self.count`
548+
fileprivate mutating func stablePartition(
549+
count n: Int, isSuffixElement: (Element) throws-> Bool
550+
) rethrows -> Index {
551+
if n == 0 { return startIndex }
552+
if n == 1 {
553+
return try isSuffixElement(self[startIndex]) ? startIndex : endIndex
589554
}
555+
let h = n / 2, i = index(startIndex, offsetBy: h)
556+
let j = try self[..<i].stablePartition(
557+
count: h, isSuffixElement: isSuffixElement)
558+
let k = try self[i...].stablePartition(
559+
count: n - h, isSuffixElement: isSuffixElement)
560+
return self[j..<k].rotate(shiftingToStart: i)
561+
}
590562
}
591563

592564
extension Collection {
593-
func stablyPartitioned(
594-
isSuffixElement p: (Element) -> Bool
595-
) -> [Element] {
596-
var a = Array(self)
597-
a.stablePartition(isSuffixElement: p)
598-
return a
599-
}
565+
func stablyPartitioned(
566+
isSuffixElement p: (Element) -> Bool
567+
) -> [Element] {
568+
var a = Array(self)
569+
a.stablePartition(isSuffixElement: p)
570+
return a
571+
}
600572
}
601573

602574
extension LazyCollectionProtocol
603575
where Element == Elements.Element {
604-
func stablyPartitioned(
605-
isSuffixElement p: (Element) -> Bool
606-
) -> LazyCollection<[Element]> {
607-
return elements.stablyPartitioned(isSuffixElement: p).lazy
608-
}
576+
func stablyPartitioned(
577+
isSuffixElement p: (Element) -> Bool
578+
) -> LazyCollection<[Element]> {
579+
return elements.stablyPartitioned(isSuffixElement: p).lazy
580+
}
609581
}
610582

611583
extension Collection {
@@ -635,9 +607,60 @@ extension Collection {
635607
}
636608
}
637609

610+
//===--- Minimal subset of StdlibUnittest for standalone testing ----------===//
611+
//===----------------------------------------------------------------------===//
612+
#if !USE_STDLIBUNITTEST
613+
class TestSuite {
614+
let name: String
615+
var tests: [(name: String, body: ()->())] = []
616+
static var all: [TestSuite] = []
617+
init(_ name: String) {
618+
self.name = name
619+
TestSuite.all.append(self)
620+
}
621+
622+
func test(_ name: String, body: @escaping ()->()) {
623+
tests.append((name, body))
624+
}
625+
}
626+
627+
func runAllTests() {
628+
for s in TestSuite.all {
629+
for (testName, f) in s.tests {
630+
print("\(s.name)/\(testName)...")
631+
f()
632+
print("done.")
633+
}
634+
}
635+
}
636+
637+
func expectEqual<T : Equatable>(
638+
_ expected: T, _ x: T, file: StaticString = #file, line: UInt = #line
639+
) {
640+
precondition(
641+
x == expected, "Expected \(x) == \(expected)", file: file, line: line)
642+
}
643+
644+
func expectGE<T: Comparable>(
645+
_ a: T, _ b: T, _ message: @autoclosure ()->String = "",
646+
file: StaticString = #file, line: UInt = #line
647+
) {
648+
precondition(a >= b, message(), file: file, line: line)
649+
}
650+
651+
func expectLE<T: Comparable>(
652+
_ a: T, _ b: T, _ message: @autoclosure ()->String = "",
653+
file: StaticString = #file, line: UInt = #line
654+
) {
655+
precondition(a <= b, message(), file: file, line: line)
656+
}
657+
#endif
658+
659+
638660
//===--- Tests ------------------------------------------------------------===//
639661
//===----------------------------------------------------------------------===//
640662

663+
641664
func address<T>(_ p: UnsafePointer<T>) -> UInt { return UInt(bitPattern: p )}
642665

643666
var suite = TestSuite("Algorithms")
@@ -799,8 +822,8 @@ suite.test("partitionPoint") {
799822
for j in i..<11 {
800823
for k in i...j {
801824
let p = (i..<j).partitionPoint { $0 >= k }
802-
expectGE(p, i)
803-
expectLE(p, j)
825+
expectGE(p, i, "\(p) >= \(i)")
826+
expectLE(p, j, "\(p) <= \(j)")
804827
expectEqual(p, k)
805828
}
806829
}

0 commit comments

Comments
 (0)