Skip to content

Commit ae4ffd1

Browse files
author
Dave Abrahams
committed
Make algorithms prototype standalone-testable and work with 4.1
Also, - strip out currently-unused flotsam - begin making comments more descriptive - fix indentation
1 parent 526632c commit ae4ffd1

File tree

1 file changed

+109
-87
lines changed

1 file changed

+109
-87
lines changed

test/Prototypes/Algorithms.swift

Lines changed: 109 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -9,57 +9,26 @@
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12-
// RUN: %target-run-stdlib-swift
12+
// RUN: %target-build-swift -g -Onone -DUSE_STDLIBUNITTEST %s -o %t/Algorithms
13+
// RUN: %target-run %t/Algorithms
1314
// REQUIRES: executable_test
1415

16+
#if USE_STDLIBUNITTEST
1517
import Swift
1618
import StdlibUnittest
19+
#endif
1720

1821
//===--- Rotate -----------------------------------------------------------===//
1922
//===----------------------------------------------------------------------===//
2023

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
24+
/// Provides customization points for `MutableCollection` algorithms.
25+
///
26+
/// If incorporated into the standard library, these requirements would just be
27+
/// part of `MutableCollection`. In the meantime, you can declare conformance
28+
/// of a collection to `MutableCollectionAlgorithms` to get these customization
29+
/// points to be used from other algorithms defined on
30+
/// `MutableCollectionAlgorithms`.
31+
public protocol MutableCollectionAlgorithms : MutableCollection
6332
where SubSequence : MutableCollectionAlgorithms
6433
{
6534
/// Rotates the elements of the collection so that the element
@@ -72,15 +41,14 @@ public protocol MutableCollectionAlgorithms
7241
mutating func rotate(shiftingToStart middle: Index) -> Index
7342
}
7443

75-
// In the stdlib, these conformances wouldn't be needed
44+
// Conformances of common collection types to MutableCollectionAlgorithms.
45+
// If rotate was a requirement of MutableCollection, these would not be needed.
7646
extension Array : MutableCollectionAlgorithms { }
7747
extension ArraySlice : MutableCollectionAlgorithms { }
78-
79-
extension Slice : MutableCollectionAlgorithms, CollectionAlgorithms
48+
extension Slice : MutableCollectionAlgorithms
8049
where Base: MutableCollection { }
8150

82-
/// In the stdlib, this would simply be MutableCollection
83-
extension MutableCollectionAlgorithms {
51+
extension MutableCollection {
8452
/// Swaps the elements of the two given subranges, up to the upper bound of
8553
/// the smaller subrange. The returned indices are the ends of the two ranges
8654
/// that were actually swapped.
@@ -557,55 +525,58 @@ extension Collection {
557525
//===--- Stable Partition -------------------------------------------------===//
558526
//===----------------------------------------------------------------------===//
559527

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

592563
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-
}
564+
func stablyPartitioned(
565+
isSuffixElement p: (Element) -> Bool
566+
) -> [Element] {
567+
var a = Array(self)
568+
a.stablePartition(isSuffixElement: p)
569+
return a
570+
}
600571
}
601572

602573
extension LazyCollectionProtocol
603574
where Element == Elements.Element {
604-
func stablyPartitioned(
605-
isSuffixElement p: (Element) -> Bool
606-
) -> LazyCollection<[Element]> {
607-
return elements.stablyPartitioned(isSuffixElement: p).lazy
608-
}
575+
func stablyPartitioned(
576+
isSuffixElement p: (Element) -> Bool
577+
) -> LazyCollection<[Element]> {
578+
return elements.stablyPartitioned(isSuffixElement: p).lazy
579+
}
609580
}
610581

611582
extension Collection {
@@ -635,9 +606,60 @@ extension Collection {
635606
}
636607
}
637608

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

662+
641663
func address<T>(_ p: UnsafePointer<T>) -> UInt { return UInt(bitPattern: p )}
642664

643665
var suite = TestSuite("Algorithms")
@@ -799,8 +821,8 @@ suite.test("partitionPoint") {
799821
for j in i..<11 {
800822
for k in i...j {
801823
let p = (i..<j).partitionPoint { $0 >= k }
802-
expectGE(p, i)
803-
expectLE(p, j)
824+
expectGE(p, i, "\(p) >= \(i)")
825+
expectLE(p, j, "\(p) <= \(j)")
804826
expectEqual(p, k)
805827
}
806828
}

0 commit comments

Comments
 (0)