Files
swift-mirror/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb
Dave Abrahams ad43a596bd [stdlib] Retire the old lazy subsystem...
...replacing it with the new, after passing API review!

* The lazy free function has become a property.

* Before we could extend protocols, we lacked a means for value types to
  share implementations, and each new lazy algorithm had to be added to
  each of up to four types: LazySequence, LazyForwardCollection,
  LazyBidirectionalCollection, and LazyRandomAccessCollection. These
  generic adapters hid the usual algorithms by defining their own
  versions that returned new lazy generic adapters. Now users can extend
  just one of two protocols to do the same thing: LazySequenceType or
  LazyCollectionType.

* To avoid making the code duplication worse than it already was, the
  generic adapters mentioned above were used to add the lazy generic
  algorithms around simpler adapters such as MapSequence that just
  provided the basic requirements of SequenceType by applying a
  transformation to some base sequence, resulting in deeply nested
  generic types as shown here. Now, MapSequence is an instance of
  LazySequenceType (and is renamed LazyMapSequence), and thus transmits
  laziness to its algorithms automatically.

* Documentation comments have been rewritten.

* The .array property was retired

* various renamings

* A bunch of Gyb files were retired.

Swift SVN r30902
2015-08-01 03:52:13 +00:00

3762 lines
107 KiB
Swift

//===--- StdlibUnittest.swift.gyb -----------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import SwiftPrivate
import SwiftPrivatePthreadExtras
import SwiftPrivateDarwinExtras
#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
import Darwin
#elseif os(Linux)
import Glibc
#endif
#if _runtime(_ObjC)
import ObjectiveC
#endif
public struct SourceLoc {
public let file: String
public let line: UInt
public let comment: String?
public init(_ file: String, _ line: UInt, comment: String? = nil) {
self.file = file
self.line = line
self.comment = comment
}
public func withCurrentLoc(
file: String = __FILE__, line: UInt = __LINE__
) -> SourceLocStack {
return SourceLocStack(self).with(SourceLoc(file, line))
}
}
public struct SourceLocStack {
let locs: [SourceLoc]
public init() {
locs = []
}
public init(_ loc: SourceLoc) {
locs = [ loc ]
}
init(_locs: [SourceLoc]) {
locs = _locs
}
var isEmpty: Bool {
return locs.isEmpty
}
public func with(loc: SourceLoc) -> SourceLocStack {
var locs = self.locs
locs.append(loc)
return SourceLocStack(_locs: locs)
}
public func pushIf(
showFrame: Bool, file: String, line: UInt
) -> SourceLocStack {
return showFrame ? self.with(SourceLoc(file, line)) : self
}
public func withCurrentLoc(
file: String = __FILE__, line: UInt = __LINE__
) -> SourceLocStack {
return with(SourceLoc(file, line))
}
public func print() {
let top = locs.first!
Swift.print("check failed at \(top.file), line \(top.line)")
_printStackTrace(SourceLocStack(_locs: Array(locs.dropFirst())))
}
}
%{
TRACE = '''@autoclosure _ message: ()->String = "",
showFrame: Bool = true,
stackTrace: SourceLocStack = SourceLocStack(),
file: String = __FILE__, line: UInt = __LINE__'''
# When the parameter list would start with a ${TRACE}, we use
# ${TRACE1} instead, to avoid the warning about an extraneous
# '_' on the first parameter.
TRACE1 = TRACE.replace(' _ ', ' ', 1)
stackTrace = 'stackTrace.pushIf(showFrame, file: file, line: line)'
trace = 'message(),\n stackTrace: ' + stackTrace
}%
func _printStackTrace(stackTrace: SourceLocStack?) {
guard let s = stackTrace else { return }
print("stacktrace:")
for i in 0..<s.locs.count {
let loc = s.locs[s.locs.count - i - 1]
let comment = (loc.comment != nil) ? " ; \(loc.comment!)" : ""
print(" #\(i): \(loc.file):\(loc.line)\(comment)")
}
}
// FIXME: these variables should be atomic, since multiple threads can call
// `expect*()` functions.
var _anyExpectFailed = false
var _seenExpectCrash = false
/// Run `body` and expect a failure to happen.
///
/// The check passes iff `body` triggers one or more failures.
public func expectFailure(${TRACE1}, body: () -> ()) {
let startAnyExpectFailed = _anyExpectFailed
_anyExpectFailed = false
body()
let endAnyExpectFailed = _anyExpectFailed
_anyExpectFailed = false
expectTrue(
endAnyExpectFailed, "running `body` should produce an expected failure",
stackTrace: ${stackTrace}
)
_anyExpectFailed = _anyExpectFailed || startAnyExpectFailed
}
public func identity(element: OpaqueValue<Int>) -> OpaqueValue<Int> {
return element
}
public func identityEq(element: MinimalEquatableValue) -> MinimalEquatableValue {
return element
}
public func identityComp(element: MinimalComparableValue)
-> MinimalComparableValue {
return element
}
public func expectEqual<T : Equatable>(expected: T, _ actual: T, ${TRACE}) {
expectEqual(expected, actual, ${trace}, showFrame: false) {$0 == $1}
}
public func expectEqual<T : Equatable, U : Equatable>(
expected: (T, U), _ actual: (T, U), ${TRACE}) {
expectEqual(expected.0, actual.0, ${trace}, showFrame: false) {$0 == $1}
expectEqual(expected.1, actual.1, ${trace}, showFrame: false) {$0 == $1}
}
public func expectationFailure(
reason: String,
trace message: String,
stackTrace: SourceLocStack) {
_anyExpectFailed = true
stackTrace.print()
print(reason, appendNewline: reason != "")
print(message, appendNewline: message != "")
}
public func expectEqual<T>(
expected: T, _ actual: T, ${TRACE}, sameValue equal: (T,T)->Bool
) {
if !equal(expected, actual) {
expectationFailure(
"expected: \(String(reflecting: expected)) (of type \(String(reflecting: expected.dynamicType)))\n"
+ "actual: \(String(reflecting: actual)) (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace}
)
}
}
public func expectNotEqual<T : Equatable>(expected: T, _ actual: T, ${TRACE}) {
if expected == actual {
expectationFailure(
"unexpected value: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace}
)
}
}
// Can not write a sane set of overloads using generics because of:
// <rdar://problem/17015923> Array->NSArray implicit conversion insanity
public func expectOptionalEqual<T : Equatable>(
expected: T, _ actual: T?, ${TRACE}
) {
expectOptionalEqual(expected, actual, ${trace}, showFrame: false) {$0 == $1}
}
public func expectOptionalEqual<T>(
expected: T, _ actual: T?, ${TRACE}, sameValue equal: (T,T)->Bool
) {
if (actual == nil) || !equal(expected, actual!) {
expectationFailure(
"expected: \"\(expected)\" (of type \(String(reflecting: expected.dynamicType)))\n"
+ "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace})
}
}
public func expectEqual<T : Equatable>(expected: T?, _ actual: T?, ${TRACE}) {
if (actual == nil) != (expected == nil)
|| actual != nil && expected! != actual! {
expectationFailure(
"expected: \"\(expected)\" (of type \(String(reflecting: expected.dynamicType)))\n"
+ "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace})
}
}
// Array<T> is not Equatable if T is. Provide additional overloads.
// Same for Dictionary.
%for (Generic, EquatableType) in [
% ('<T : Equatable>', 'ContiguousArray<T>'),
% ('<T : Equatable>', 'ArraySlice<T>'),
% ('<T : Equatable>', 'Array<T>'),
% ('<T, U : Equatable>', 'Dictionary<T, U>')]:
public func expectEqual${Generic}(
expected: ${EquatableType}, _ actual: ${EquatableType}, ${TRACE}
) {
expectEqual(expected, actual, ${trace}, showFrame: false) { $0 == $1 }
}
public func expectOptionalEqual${Generic}(
expected: ${EquatableType}, _ actual: ${EquatableType}?, ${TRACE}) {
if (actual == nil) || expected != actual! {
expectationFailure(
"expected: \"\(expected)\" (of type \(String(reflecting: expected.dynamicType)))"
+ "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace})
}
}
%end
public func expectLT(lhs: Int, _ rhs: Int, ${TRACE}) {
if !(lhs < rhs) {
expectationFailure("\(lhs) < \(rhs)", trace: ${trace})
}
}
public func expectLE(lhs: Int, _ rhs: Int, ${TRACE}) {
if !(lhs <= rhs) {
expectationFailure("\(lhs) <= \(rhs)", trace: ${trace})
}
}
public func expectGT(lhs: Int, _ rhs: Int, ${TRACE}) {
if !(lhs > rhs) {
expectationFailure("\(lhs) > \(rhs)", trace: ${trace})
}
}
public func expectGE(lhs: Int, _ rhs: Int, ${TRACE}) {
if !(lhs >= rhs) {
expectationFailure("\(lhs) >= \(rhs)", trace: ${trace})
}
}
public func expectType<T>(_: T.Type, inout _ x: T) {}
public func expectEqualType<T>(_: T.Type, _: T.Type) {}
public func isSequenceType<X : SequenceType>(x: X) -> X { return x }
public func expectIndexable<X : Indexable>(x: X) -> X { return x }
public func expectCollectionType<X : CollectionType>(x: X) -> X { return x }
/// A slice is a `CollectionType` that when sliced returns an instance of
/// itself.
public func expectSliceType<
X : CollectionType
where
X.SubSequence == X
>(sliceType: X.Type) {}
/// A mutable slice is a `MutableCollectionType` that when sliced returns an
/// instance of itself.
public func expectMutableSliceType<
X : MutableCollectionType
where
X.SubSequence == X
>(mutableSliceType: X.Type) {}
/// Check all associated types of a `CollectionType`.
public func expectCollectionAssociatedTypes<
X : CollectionType,
Generator : GeneratorType,
SubSequence : SequenceType,
Index : ForwardIndexType
where
X.Index == Index
>(
collectionType collectionType: X.Type,
generatorType: Generator.Type,
subSequenceType: SubSequence.Type,
indexType: Index.Type
) {}
public func expectForwardIndexType<X : ForwardIndexType>(x: X) -> X { return x }
public func expectIsBooleanType<X : BooleanType>(inout x: X) -> X { return x }
public struct AssertionResult : CustomStringConvertible, BooleanType {
init(isPass: Bool) {
self._isPass = isPass
}
public var boolValue: Bool {
return _isPass
}
public func withDescription(description: String) -> AssertionResult {
var result = self
result.description += description
return result
}
let _isPass: Bool
public var description: String = ""
}
public func assertionSuccess() -> AssertionResult {
return AssertionResult(isPass: true)
}
public func assertionFailure() -> AssertionResult {
return AssertionResult(isPass: false)
}
public func expectUnreachable(${TRACE1}) {
expectationFailure("this code should not be executed", trace: ${trace})
}
public func expectUnreachableCatch(error: ErrorType, ${TRACE}) {
expectationFailure(
"error should not be thrown: \"\(error)\"", trace: ${trace})
}
%for BoolType in ['Bool', 'AssertionResult']:
public func expectTrue(actual: ${BoolType}, ${TRACE}) {
if !actual {
expectationFailure("expected: true", trace: ${trace})
}
}
public func expectFalse(actual: ${BoolType}, ${TRACE}) {
if actual {
expectationFailure("expected: false", trace: ${trace})
}
}
%end
public func expectEmpty<T>(value: T?, ${TRACE}) {
if value != nil {
expectationFailure(
"expected optional to be empty\nactual: \"\(value)\"", trace: ${trace})
}
}
public func expectNotEmpty<T>(value: T?, ${TRACE}) -> T? {
if value == nil {
expectationFailure("expected optional to be non-empty", trace: ${trace})
}
return value
}
public func expectCrashLater() {
print("\(_stdlibUnittestStreamPrefix);expectCrash;\(_anyExpectFailed)")
var stderr = _Stderr()
print("\(_stdlibUnittestStreamPrefix);expectCrash", &stderr)
_seenExpectCrash = true
}
func _defaultTestSuiteFailedCallback() {
abort()
}
var _testSuiteFailedCallback: () -> () = _defaultTestSuiteFailedCallback
public func _setTestSuiteFailedCallback(callback: () -> ()) {
_testSuiteFailedCallback = callback
}
extension ProcessTerminationStatus {
var isSwiftTrap: Bool {
switch self {
case .Exit(_):
return false
case .Signal(let signal):
return CInt(signal) == SIGILL || CInt(signal) == SIGTRAP
}
}
}
func _stdlib_getline() -> String? {
var result: [UInt8] = []
while true {
let c = getchar()
if c == EOF {
if result.isEmpty {
return nil
}
return String._fromWellFormedCodeUnitSequence(UTF8.self, input: result)
}
if c == CInt(UnicodeScalar("\n").value) {
return String._fromWellFormedCodeUnitSequence(UTF8.self, input: result)
}
result.append(UInt8(c))
}
}
func _printDebuggingAdvice(fullTestName: String) {
print("To debug, run:")
print("$ \(Process.arguments[0]) " +
"--stdlib-unittest-in-process --stdlib-unittest-filter \"\(fullTestName)\"")
}
var _allTestSuites: [TestSuite] = []
var _testSuiteNameToIndex: [String : Int] = [:]
let _stdlibUnittestStreamPrefix = "__STDLIB_UNITTEST__"
@asmname("swift_stdlib_installTrapInterceptor")
func _stdlib_installTrapInterceptor()
func _childProcess() {
_stdlib_installTrapInterceptor()
while let line = _stdlib_getline() {
let parts = line._split(";")
let testSuiteName = parts[0]
let testName = parts[1]
let testSuite = _allTestSuites[_testSuiteNameToIndex[testSuiteName]!]
_anyExpectFailed = false
testSuite._runTest(testName)
print("\(_stdlibUnittestStreamPrefix);end;\(_anyExpectFailed)")
var stderr = _Stderr()
print("\(_stdlibUnittestStreamPrefix);end", &stderr)
if !testSuite._testByName(testName).canReuseChildProcessAfterTest {
return
}
}
}
struct _ParentProcess {
internal var _pid: pid_t = -1
internal var _childStdin: _FDOutputStream = _FDOutputStream(fd: -1)
internal var _childStdout: _FDInputStream = _FDInputStream(fd: -1)
internal var _childStderr: _FDInputStream = _FDInputStream(fd: -1)
internal var _runTestsInProcess: Bool
internal var _filter: String?
init(runTestsInProcess: Bool, filter: String?) {
self._runTestsInProcess = runTestsInProcess
self._filter = filter
}
mutating func _spawnChild() {
let (pid, childStdinFD, childStdoutFD, childStderrFD) =
spawnChild([ "--stdlib-unittest-run-child" ])
_pid = pid
_childStdin = _FDOutputStream(fd: childStdinFD)
_childStdout = _FDInputStream(fd: childStdoutFD)
_childStderr = _FDInputStream(fd: childStderrFD)
}
mutating func _waitForChild() -> ProcessTerminationStatus {
let status = posixWaitpid(_pid)
_pid = -1
_childStdin.close()
_childStdout.close()
_childStderr.close()
_childStdin = _FDOutputStream(fd: -1)
_childStdout = _FDInputStream(fd: -1)
_childStderr = _FDInputStream(fd: -1)
return status
}
/// Returns the values of the corresponding variables in the child process.
mutating func _runTestInChild(testSuite: TestSuite, _ testName: String)
-> (anyExpectFailed: Bool, seenExpectCrash: Bool,
status: ProcessTerminationStatus?,
crashStdout: [String], crashStderr: [String]) {
if _pid <= 0 {
_spawnChild()
}
print("\(testSuite.name);\(testName)", &_childStdin)
let currentTest = testSuite._testByName(testName)
if let stdinText = currentTest.stdinText {
print(stdinText, &_childStdin, appendNewline: false)
}
if currentTest.stdinEndsWithEOF {
_childStdin.close()
}
var readfds = _stdlib_fd_set()
var writefds = _stdlib_fd_set()
var errorfds = _stdlib_fd_set()
var stdoutSeenCrashDelimiter = false
var stderrSeenCrashDelimiter = false
var stdoutEnd = false
var stderrEnd = false
var capturedCrashStdout: [String] = []
var capturedCrashStderr: [String] = []
var anyExpectFailedInChild = false
while !((_childStdout.isEOF && _childStderr.isEOF) ||
(stdoutEnd && stderrEnd)) {
readfds.zero()
errorfds.zero()
if !_childStdout.isEOF {
readfds.set(_childStdout.fd)
errorfds.set(_childStdout.fd)
}
if !_childStderr.isEOF {
readfds.set(_childStderr.fd)
errorfds.set(_childStderr.fd)
}
var ret: CInt
repeat {
ret = _stdlib_select(&readfds, &writefds, &errorfds, nil)
} while ret == -1 && errno == EINTR
if ret <= 0 {
fatalError("select() returned an error")
}
if readfds.isset(_childStdout.fd) || errorfds.isset(_childStdout.fd) {
_childStdout.read()
while var line = _childStdout.getline() {
if let index = findSubstring(line, _stdlibUnittestStreamPrefix) {
let controlMessage = line[index..<line.endIndex]._split(";")
switch controlMessage[1] {
case "expectCrash":
stdoutSeenCrashDelimiter = true
anyExpectFailedInChild = controlMessage[2] == "true"
case "end":
stdoutEnd = true
anyExpectFailedInChild = controlMessage[2] == "true"
default:
fatalError("unexpected message")
}
line = line[line.startIndex..<index]
if line.isEmpty {
continue
}
}
if stdoutSeenCrashDelimiter {
capturedCrashStdout.append(line)
}
print("out>>> \(line)")
}
continue
}
if readfds.isset(_childStderr.fd) || errorfds.isset(_childStderr.fd) {
_childStderr.read()
while var line = _childStderr.getline() {
if let index = findSubstring(line, _stdlibUnittestStreamPrefix) {
let controlMessage = line[index..<line.endIndex]._split(";")
switch controlMessage[1] {
case "expectCrash":
stderrSeenCrashDelimiter = true
case "end":
stderrEnd = true
default:
fatalError("unexpected message")
}
line = line[line.startIndex..<index]
if line.isEmpty {
continue
}
}
if stderrSeenCrashDelimiter {
capturedCrashStderr.append(line)
}
print("err>>> \(line)")
}
continue
}
}
// Check if the child has sent us "end" markers for the current test.
if stdoutEnd && stderrEnd {
testSuite._testByName(testName)
var status: ProcessTerminationStatus? = nil
if !testSuite._testByName(testName).canReuseChildProcessAfterTest {
status = _waitForChild()
switch status! {
case .Exit(0):
status = nil
default:
()
}
}
return (
anyExpectFailedInChild,
stdoutSeenCrashDelimiter || stderrSeenCrashDelimiter, status,
capturedCrashStdout, capturedCrashStderr)
}
// We reached EOF on stdout and stderr and we did not see "end" markers, so
// it looks like child crashed (of course it could have closed the file
// descriptors, but we assume it did not, since it prevent further
// communication with the parent).
let status = _waitForChild()
return (
anyExpectFailedInChild,
stdoutSeenCrashDelimiter || stderrSeenCrashDelimiter, status,
capturedCrashStdout, capturedCrashStderr)
}
mutating func run() {
if let filter = _filter {
print("StdlibUnittest: using filter: \(filter)")
}
for testSuite in _allTestSuites {
var uxpassedTests: [String] = []
var failedTests: [String] = []
var skippedTests: [String] = []
for t in testSuite._tests {
let fullTestName = "\(testSuite.name).\(t.name)"
if let filter = _filter where findSubstring(fullTestName, filter) == nil {
continue
}
let activeSkips = t.getActiveSkipPredicates()
if !activeSkips.isEmpty {
skippedTests += [ t.name ]
print("[ SKIP ] \(fullTestName) (skip: \(activeSkips))")
continue
}
let activeXFails = t.getActiveXFailPredicates()
let expectXFail = !activeXFails.isEmpty
let activeXFailsText = expectXFail ? " (XFAIL: \(activeXFails))" : ""
print("[ RUN ] \(fullTestName)\(activeXFailsText)")
var expectCrash = false
var childTerminationStatus: ProcessTerminationStatus? = nil
var crashStdout: [String] = []
var crashStderr: [String] = []
if _runTestsInProcess {
if t.stdinText != nil {
print("The test \(fullTestName) requires stdin input and can't be run in-process, marking as failed")
_anyExpectFailed = true
} else {
_anyExpectFailed = false
testSuite._runTest(t.name)
}
} else {
(_anyExpectFailed, expectCrash, childTerminationStatus, crashStdout,
crashStderr) =
_runTestInChild(testSuite, t.name)
}
// Determine if the test passed, not taking XFAILs into account.
var testPassed = false
switch (childTerminationStatus, expectCrash) {
case (.None, false):
testPassed = !_anyExpectFailed
case (.None, true):
testPassed = false
print("expecting a crash, but the test did not crash")
case (.Some(_), false):
testPassed = false
print("the test crashed unexpectedly")
case (.Some(_), true):
testPassed = !_anyExpectFailed
}
if testPassed && t.crashOutputMatches.count > 0 {
// If we still think that the test passed, check if the crash
// output matches our expectations.
let crashOutput = crashStdout + crashStderr
for expectedCrashOutput in t.crashOutputMatches {
var found = false
for s in crashOutput {
if findSubstring(s, expectedCrashOutput) != nil {
found = true
break
}
}
if !found {
print("did not find expected string after crash: \(expectedCrashOutput.debugDescription)")
testPassed = false
}
}
}
// Apply XFAILs.
switch (testPassed, expectXFail) {
case (true, false):
print("[ OK ] \(fullTestName)")
case (true, true):
uxpassedTests += [ t.name ]
print("[ UXPASS ] \(fullTestName)")
case (false, false):
failedTests += [ t.name ]
print("[ FAIL ] \(fullTestName)")
case (false, true):
print("[ XFAIL ] \(fullTestName)")
}
}
if !uxpassedTests.isEmpty || !failedTests.isEmpty {
print("\(testSuite.name): Some tests failed, aborting")
print("UXPASS: \(uxpassedTests)")
print("FAIL: \(failedTests)")
print("SKIP: \(skippedTests)")
if !uxpassedTests.isEmpty {
_printDebuggingAdvice(uxpassedTests[0])
}
if !failedTests.isEmpty {
_printDebuggingAdvice(failedTests[0])
}
_testSuiteFailedCallback()
} else {
print("\(testSuite.name): All tests passed")
}
}
}
}
public func runAllTests() {
struct PersistentState {
static var runAllTestsWasCalled: Bool = false
}
if PersistentState.runAllTestsWasCalled {
print("runAllTests() called twice. It is not allowed, aborting.")
_testSuiteFailedCallback()
return
}
PersistentState.runAllTestsWasCalled = true
#if _runtime(ObjC)
autoreleasepool {
_stdlib_initializeReturnAutoreleased()
}
#endif
let _isChildProcess: Bool =
Process.arguments.contains("--stdlib-unittest-run-child")
if _isChildProcess {
_childProcess()
} else {
var runTestsInProcess: Bool = false
var filter: String? = nil
for var i = 0; i < Process.arguments.count; {
let arg = Process.arguments[i]
if arg == "--stdlib-unittest-in-process" {
runTestsInProcess = true
++i
continue
}
if arg == "--stdlib-unittest-filter" {
filter = Process.arguments[i + 1]
i += 2
continue
}
if arg == "--help" {
let message =
"optional arguments:\n" +
"--stdlib-unittest-in-process\n" +
" run tests in-process without intercepting crashes.\n" +
" Useful for running under a debugger.\n" +
"--stdlib-unittest-filter FILTER-STRING\n" +
" only run tests whose names contain FILTER-STRING as\n" +
" a substring."
print(message)
return
}
// FIXME: skipping unrecognized parameters.
++i
}
var parent = _ParentProcess(
runTestsInProcess: runTestsInProcess, filter: filter)
parent.run()
}
}
public class TestSuite {
public init(_ name: String) {
self.name = name
_precondition(
_testNameToIndex[name] == nil,
"test suite with the same name already exists")
_allTestSuites.append(self)
_testSuiteNameToIndex[name] = _allTestSuites.count - 1
}
public func test(
name: String,
file: String = __FILE__, line: UInt = __LINE__,
_ testFunction: () -> ()) {
_TestBuilder(testSuite: self, name: name, loc: SourceLoc(file, line))
.code(testFunction)
}
public func test(
name: String, file: String = __FILE__, line: UInt = __LINE__
) -> _TestBuilder {
return _TestBuilder(testSuite: self, name: name, loc: SourceLoc(file, line))
}
public func setUp(code: () -> ()) {
_precondition(_testSetUpCode == nil, "set-up code already set")
_testSetUpCode = code
}
public func tearDown(code: () -> ()) {
_precondition(_testTearDownCode == nil, "tear-down code already set")
_testTearDownCode = code
}
func _runTest(testName: String) {
for r in _allResettables {
r.reset()
}
LifetimeTracked.instances = 0
if let f = _testSetUpCode {
f()
}
let test = _testByName(testName)
test.code()
if let f = _testTearDownCode {
f()
}
expectEqual(
0, LifetimeTracked.instances, "leaked LifetimeTracked instances:",
file: test.testLoc.file, line: test.testLoc.line)
}
func _testByName(testName: String) -> _Test {
return _tests[_testNameToIndex[testName]!]
}
struct _Test {
let name: String
let testLoc: SourceLoc
let xfail: [TestRunPredicate]
let skip: [TestRunPredicate]
let stdinText: String?
let stdinEndsWithEOF: Bool
let crashOutputMatches: [String]
let code: () -> ()
/// Whether the test harness should stop reusing the child process after
/// running this test.
var canReuseChildProcessAfterTest: Bool {
return stdinText == nil
}
func getActiveXFailPredicates() -> [TestRunPredicate] {
return xfail.filter { $0.evaluate() }
}
func getActiveSkipPredicates() -> [TestRunPredicate] {
return skip.filter { $0.evaluate() }
}
}
public struct _TestBuilder {
let _testSuite: TestSuite
var _name: String
var _data: _Data = _Data()
class _Data {
var _xfail: [TestRunPredicate] = []
var _skip: [TestRunPredicate] = []
var _stdinText: String? = nil
var _stdinEndsWithEOF: Bool = false
var _crashOutputMatches: [String] = []
var _testLoc: SourceLoc? = nil
}
init(testSuite: TestSuite, name: String, loc: SourceLoc) {
_testSuite = testSuite
_name = name
_data._testLoc = loc
}
public func xfail(predicate: TestRunPredicate) -> _TestBuilder {
_data._xfail.append(predicate)
return self
}
public func skip(predicate: TestRunPredicate) -> _TestBuilder {
_data._skip.append(predicate)
return self
}
public func stdin(stdinText: String, eof: Bool = false) -> _TestBuilder {
_data._stdinText = stdinText
_data._stdinEndsWithEOF = eof
return self
}
public func crashOutputMatches(string: String) -> _TestBuilder {
_data._crashOutputMatches.append(string)
return self
}
public func code(testFunction: () -> ()) {
_testSuite._tests.append(
_Test(
name: _name, testLoc: _data._testLoc!, xfail: _data._xfail,
skip: _data._skip,
stdinText: _data._stdinText,
stdinEndsWithEOF: _data._stdinEndsWithEOF,
crashOutputMatches: _data._crashOutputMatches, code: testFunction))
_testSuite._testNameToIndex[_name] = _testSuite._tests.count - 1
}
}
var name: String
var _tests: [_Test] = []
/// Code that is run before every test.
var _testSetUpCode: (() -> ())?
/// Code that is run after every test.
var _testTearDownCode: (() -> ())?
/// Maps test name to index in `_tests`.
var _testNameToIndex: [String : Int] = [:]
}
#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
@asmname("swift_stdlib_getSystemVersionPlistProperty")
func _stdlib_getSystemVersionPlistPropertyImpl(
propertyName: UnsafePointer<CChar>) -> UnsafePointer<CChar>
func _stdlib_getSystemVersionPlistProperty(propertyName: String) -> String? {
return String.fromCString(
_stdlib_getSystemVersionPlistPropertyImpl(propertyName))
}
#endif
public enum OSVersion : CustomStringConvertible {
case OSX(major: Int, minor: Int, bugFix: Int)
case iOS(major: Int, minor: Int, bugFix: Int)
case TVOS(major: Int, minor: Int, bugFix: Int)
case watchOS(major: Int, minor: Int, bugFix: Int)
case iOSSimulator
case TVOSSimulator
case watchOSSimulator
case Linux
public var description: String {
switch self {
case OSX(let major, let minor, let bugFix):
return "OS X \(major).\(minor).\(bugFix)"
case iOS(let major, let minor, let bugFix):
return "iOS \(major).\(minor).\(bugFix)"
case TVOS(let major, let minor, let bugFix):
return "TVOS \(major).\(minor).\(bugFix)"
case watchOS(let major, let minor, let bugFix):
return "watchOS \(major).\(minor).\(bugFix)"
case iOSSimulator:
return "iOSSimulator"
case TVOSSimulator:
return "TVOSSimulator"
case watchOSSimulator:
return "watchOSSimulator"
case Linux:
return "Linux"
}
}
}
func _parseDottedVersion(s: String) -> [Int] {
return Array(s._split(".").lazy.map { Int($0)! })
}
public func _parseDottedVersionTriple(s: String) -> (Int, Int, Int) {
var array = _parseDottedVersion(s)
if array.count >= 4 {
fatalError("unexpected version")
}
return (
array.count >= 1 ? array[0] : 0,
array.count >= 2 ? array[1] : 0,
array.count >= 3 ? array[2] : 0)
}
func _getOSVersion() -> OSVersion {
#if os(iOS) && (arch(i386) || arch(x86_64))
// On simulator, the plist file that we try to read turns out to be host's
// plist file, which indicates OS X.
//
// FIXME: how to get the simulator version *without* UIKit?
return .iOSSimulator
#elseif os(tvOS) && (arch(i386) || arch(x86_64))
return .TVOSSimulator
#elseif os(watchOS) && (arch(i386) || arch(x86_64))
return .watchOSSimulator
#elseif os(Linux)
return .Linux
#else
let productName = _stdlib_getSystemVersionPlistProperty("ProductName")!
let productVersion = _stdlib_getSystemVersionPlistProperty("ProductVersion")!
let (major, minor, bugFix) = _parseDottedVersionTriple(productVersion)
switch productName {
case "Mac OS X":
return .OSX(major: major, minor: minor, bugFix: bugFix)
case "iPhone OS":
return .iOS(major: major, minor: minor, bugFix: bugFix)
case "tvOS":
return .TVOS(major: major, minor: minor, bugFix: bugFix)
case "Watch OS":
return .watchOS(major: major, minor: minor, bugFix: bugFix)
default:
fatalError("could not determine OS version")
}
#endif
}
var _runningOSVersion: OSVersion = _getOSVersion()
var _overrideOSVersion: OSVersion? = nil
/// Override the OS version for testing.
public func _setOverrideOSVersion(v: OSVersion) {
_overrideOSVersion = v
}
func _getRunningOSVersion() -> OSVersion {
// Allow overriding the OS version for testing.
return _overrideOSVersion ?? _runningOSVersion
}
public enum TestRunPredicate : CustomStringConvertible {
case Custom(() -> Bool, reason: String)
case OSXAny(/*reason:*/ String)
case OSXMajor(Int, reason: String)
case OSXMinor(Int, Int, reason: String)
case OSXMinorRange(Int, Range<Int>, reason: String)
case OSXBugFix(Int, Int, Int, reason: String)
case OSXBugFixRange(Int, Int, Range<Int>, reason: String)
case iOSAny(/*reason:*/ String)
case iOSMajor(Int, reason: String)
case iOSMinor(Int, Int, reason: String)
case iOSMinorRange(Int, Range<Int>, reason: String)
case iOSBugFix(Int, Int, Int, reason: String)
case iOSBugFixRange(Int, Int, Range<Int>, reason: String)
case iOSSimulatorAny(/*reason:*/ String)
case TVOSAny(/*reason:*/ String)
case TVOSMajor(Int, reason: String)
case TVOSMinor(Int, Int, reason: String)
case TVOSMinorRange(Int, Range<Int>, reason: String)
case TVOSBugFix(Int, Int, Int, reason: String)
case TVOSBugFixRange(Int, Int, Range<Int>, reason: String)
case TVOSSimulatorAny(/*reason:*/ String)
case watchOSAny(/*reason:*/ String)
case watchOSMajor(Int, reason: String)
case watchOSMinor(Int, Int, reason: String)
case watchOSMinorRange(Int, Range<Int>, reason: String)
case watchOSBugFix(Int, Int, Int, reason: String)
case watchOSBugFixRange(Int, Int, Range<Int>, reason: String)
case watchOSSimulatorAny(/*reason:*/ String)
case LinuxAny(reason: String)
public var description: String {
switch self {
case Custom(_, let reason):
return "Custom(reason: \(reason))"
case OSXAny(let reason):
return "OSX(*, reason: \(reason))"
case OSXMajor(let major, let reason):
return "OSX(\(major).*, reason: \(reason))"
case OSXMinor(let major, let minor, let reason):
return "OSX(\(major).\(minor), reason: \(reason))"
case OSXMinorRange(let major, let minorRange, let reason):
return "OSX(\(major).[\(minorRange)], reason: \(reason))"
case OSXBugFix(let major, let minor, let bugFix, let reason):
return "OSX(\(major).\(minor).\(bugFix), reason: \(reason))"
case OSXBugFixRange(let major, let minor, let bugFixRange, let reason):
return "OSX(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"
case iOSAny(let reason):
return "iOS(*, reason: \(reason))"
case iOSMajor(let major, let reason):
return "iOS(\(major).*, reason: \(reason))"
case iOSMinor(let major, let minor, let reason):
return "iOS(\(major).\(minor), reason: \(reason))"
case iOSMinorRange(let major, let minorRange, let reason):
return "iOS(\(major).[\(minorRange)], reason: \(reason))"
case iOSBugFix(let major, let minor, let bugFix, let reason):
return "iOS(\(major).\(minor).\(bugFix), reason: \(reason))"
case iOSBugFixRange(let major, let minor, let bugFixRange, let reason):
return "iOS(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"
case iOSSimulatorAny(let reason):
return "iOSSimulatorAny(*, reason: \(reason))"
case TVOSAny(let reason):
return "TVOS(*, reason: \(reason))"
case TVOSMajor(let major, let reason):
return "TVOS(\(major).*, reason: \(reason))"
case TVOSMinor(let major, let minor, let reason):
return "TVOS(\(major).\(minor), reason: \(reason))"
case TVOSMinorRange(let major, let minorRange, let reason):
return "TVOS(\(major).[\(minorRange)], reason: \(reason))"
case TVOSBugFix(let major, let minor, let bugFix, let reason):
return "TVOS(\(major).\(minor).\(bugFix), reason: \(reason))"
case TVOSBugFixRange(let major, let minor, let bugFixRange, let reason):
return "TVOS(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"
case TVOSSimulatorAny(let reason):
return "TVOSSimulatorAny(*, reason: \(reason))"
case watchOSAny(let reason):
return "watchOS(*, reason: \(reason))"
case watchOSMajor(let major, let reason):
return "watchOS(\(major).*, reason: \(reason))"
case watchOSMinor(let major, let minor, let reason):
return "watchOS(\(major).\(minor), reason: \(reason))"
case watchOSMinorRange(let major, let minorRange, let reason):
return "watchOS(\(major).[\(minorRange)], reason: \(reason))"
case watchOSBugFix(let major, let minor, let bugFix, let reason):
return "watchOS(\(major).\(minor).\(bugFix), reason: \(reason))"
case watchOSBugFixRange(let major, let minor, let bugFixRange, let reason):
return "watchOS(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"
case watchOSSimulatorAny(let reason):
return "watchOSSimulatorAny(*, reason: \(reason))"
case LinuxAny(reason: let reason):
return "LinuxAny(*, reason: \(reason))"
}
}
public func evaluate() -> Bool {
switch self {
case Custom(let predicate, _):
return predicate()
case OSXAny:
switch _getRunningOSVersion() {
case .OSX:
return true
default:
return false
}
case OSXMajor(let major, _):
switch _getRunningOSVersion() {
case .OSX(major, _, _):
return true
default:
return false
}
case OSXMinor(let major, let minor, _):
switch _getRunningOSVersion() {
case .OSX(major, minor, _):
return true
default:
return false
}
case OSXMinorRange(let major, let minorRange, _):
switch _getRunningOSVersion() {
case .OSX(major, let runningMinor, _):
return minorRange.contains(runningMinor)
default:
return false
}
case OSXBugFix(let major, let minor, let bugFix, _):
switch _getRunningOSVersion() {
case .OSX(major, minor, bugFix):
return true
default:
return false
}
case OSXBugFixRange(let major, let minor, let bugFixRange, _):
switch _getRunningOSVersion() {
case .OSX(major, minor, let runningBugFix):
return bugFixRange.contains(runningBugFix)
default:
return false
}
case iOSAny:
switch _getRunningOSVersion() {
case .iOS:
return true
default:
return false
}
case iOSMajor(let major, _):
switch _getRunningOSVersion() {
case .iOS(major, _, _):
return true
default:
return false
}
case iOSMinor(let major, let minor, _):
switch _getRunningOSVersion() {
case .iOS(major, minor, _):
return true
default:
return false
}
case iOSMinorRange(let major, let minorRange, _):
switch _getRunningOSVersion() {
case .iOS(major, let runningMinor, _):
return minorRange.contains(runningMinor)
default:
return false
}
case iOSBugFix(let major, let minor, let bugFix, _):
switch _getRunningOSVersion() {
case .iOS(major, minor, bugFix):
return true
default:
return false
}
case iOSBugFixRange(let major, let minor, let bugFixRange, _):
switch _getRunningOSVersion() {
case .iOS(major, minor, let runningBugFix):
return bugFixRange.contains(runningBugFix)
default:
return false
}
case iOSSimulatorAny:
switch _getRunningOSVersion() {
case .iOSSimulator:
return true
default:
return false
}
case TVOSAny:
switch _getRunningOSVersion() {
case .TVOS:
return true
default:
return false
}
case TVOSMajor(let major, _):
switch _getRunningOSVersion() {
case .TVOS(major, _, _):
return true
default:
return false
}
case TVOSMinor(let major, let minor, _):
switch _getRunningOSVersion() {
case .TVOS(major, minor, _):
return true
default:
return false
}
case TVOSMinorRange(let major, let minorRange, _):
switch _getRunningOSVersion() {
case .TVOS(major, let runningMinor, _):
return minorRange.contains(runningMinor)
default:
return false
}
case TVOSBugFix(let major, let minor, let bugFix, _):
switch _getRunningOSVersion() {
case .TVOS(major, minor, bugFix):
return true
default:
return false
}
case TVOSBugFixRange(let major, let minor, let bugFixRange, _):
switch _getRunningOSVersion() {
case .TVOS(major, minor, let runningBugFix):
return bugFixRange.contains(runningBugFix)
default:
return false
}
case TVOSSimulatorAny:
switch _getRunningOSVersion() {
case .TVOSSimulator:
return true
default:
return false
}
case watchOSAny:
switch _getRunningOSVersion() {
case .watchOS:
return true
default:
return false
}
case watchOSMajor(let major, _):
switch _getRunningOSVersion() {
case .watchOS(major, _, _):
return true
default:
return false
}
case watchOSMinor(let major, let minor, _):
switch _getRunningOSVersion() {
case .watchOS(major, minor, _):
return true
default:
return false
}
case watchOSMinorRange(let major, let minorRange, _):
switch _getRunningOSVersion() {
case .watchOS(major, let runningMinor, _):
return minorRange.contains(runningMinor)
default:
return false
}
case watchOSBugFix(let major, let minor, let bugFix, _):
switch _getRunningOSVersion() {
case .watchOS(major, minor, bugFix):
return true
default:
return false
}
case watchOSBugFixRange(let major, let minor, let bugFixRange, _):
switch _getRunningOSVersion() {
case .watchOS(major, minor, let runningBugFix):
return bugFixRange.contains(runningBugFix)
default:
return false
}
case watchOSSimulatorAny:
switch _getRunningOSVersion() {
case .watchOSSimulator:
return true
default:
return false
}
case LinuxAny:
switch _getRunningOSVersion() {
case .Linux:
return true
default:
return false
}
}
}
}
//
// Semantic tests for protocol conformance
//
/// Test that the elements of `instances` satisfy the semantic
/// requirements of `Equatable`, using `oracle` to generate equality
/// expectations from pairs of positions in `instances`.
///
/// - Note: `oracle` is also checked for conformance to the
/// laws.
public func checkEquatable<
Instances: CollectionType where Instances.Generator.Element : Equatable
>(
instances: Instances,
oracle: (Instances.Index, Instances.Index) -> Bool,
${TRACE}
) {
for i in instances.indices {
expectTrue(oracle(i, i), "bad oracle: broken reflexivity at index \(i)")
let x = instances[i]
// Reflexivity
expectEqual(x, x, ${trace})
for j in instances.indices {
let predictedXY = oracle(i, j)
expectEqual(
predictedXY, oracle(j, i),
"bad oracle: broken symmetry between indices \(i), \(j)")
let y = instances[j]
let xy = x == y
expectEqual(predictedXY, xy, ${trace})
// Not-equal is an inverse of equal
expectNotEqual(xy, x != y, ${trace})
// Symmetry
expectEqual(xy, y == x, ${trace})
for k in instances.indices {
let z = instances[k]
// Transitivity
if xy && y == z {
expectTrue(
oracle(i, k),
"bad oracle: broken transitivity at indices \(i), \(j), \(k)")
expectEqual(x, z, ${trace})
}
}
}
}
}
public func checkEquatable<T : Equatable>(
expectedEqual: Bool, _ lhs: T, _ rhs: T, ${TRACE}
) {
checkEquatable(
[lhs, rhs],
oracle: { expectedEqual || $0 == $1 }, ${trace}, showFrame: false)
}
/// Test that the elements of `instances` satisfy the semantic
/// requirements of `Hashable`, using `equalityOracle` to generate
/// equality expectations from pairs of positions in `instances`.
public func checkHashable<
Instances: CollectionType where Instances.Generator.Element : Hashable
>(
instances: Instances,
equalityOracle: (Instances.Index, Instances.Index)->Bool,
${TRACE}
) {
checkEquatable(instances, oracle: equalityOracle, ${trace})
for x in instances {
for y in instances {
if x == y {
expectEqual(x.hashValue, y.hashValue, ${trace})
}
}
}
}
public func checkHashable<T : Hashable>(
expectedEqual: Bool, _ lhs: T, _ rhs: T, ${TRACE}
) {
checkHashable(
[lhs, rhs], equalityOracle: { expectedEqual || $0 == $1 }, ${trace})
}
% for inc, protocol, op, successor, end in (
% ('inc', '_Incrementable', '++', 'successor', 'end'),
% ('dec', 'BidirectionalIndexType', '--', 'predecessor', 'start')):
/// Test that the elements of `instances` satisfy
/// ${'some of ' if inc == 'dec' else ''}the semantic
/// requirements of `${protocol}`, using `equalityOracle` to
/// generate equality expectations from pairs of positions in
/// `instances`.
///
/// - Precondition: ${'''`endIndex` is reachable from all
/// elements of `instances`.''' if inc == 'inc' else '''all
/// elements of `instances` are reachable from `startIndex`.'''}
public func check${inc.capitalize()}rementable<
Instances: CollectionType
where Instances.Generator.Element : ${protocol}
>(
instances: Instances,
equalityOracle: (Instances.Index, Instances.Index)->Bool,
${end}Index: Instances.Generator.Element, ${TRACE}
) {
checkEquatable(instances, oracle: equalityOracle, ${trace})
for i in instances {
if i != ${end}Index {
let next = i.${successor}()
// ${successor} gets us a new index value
expectNotEqual(i, next, ${trace})
// Which is the same as if we apply _${successor}InPlace
var j = i
j._${successor}InPlace()
expectEqual(j, next, ${trace})
// Post-${inc}rement works
j = i
expectEqual(j${op}, i, ${trace})
expectEqual(j, next, ${trace})
// Pre-${inc}rement works
j = i
expectEqual(${op}j, next, ${trace})
expectEqual(j, next, ${trace})
}
}
}
%end
public enum ExpectedComparisonResult {
case LT, EQ, GT
public func isLT() -> Bool {
return self == .LT
}
public func isEQ() -> Bool {
return self == .EQ
}
public func isGT() -> Bool {
return self == .GT
}
public func isLE() -> Bool {
return isLT() || isEQ()
}
public func isGE() -> Bool {
return isGT() || isEQ()
}
public func isNE() -> Bool {
return !isEQ()
}
public func flip() -> ExpectedComparisonResult {
switch self {
case .LT:
return .GT
case .EQ:
return .EQ
case .GT:
return .LT
}
}
}
extension ExpectedComparisonResult : CustomStringConvertible {
public var description: String {
switch self {
case .LT:
return "<"
case .EQ:
return "=="
case .GT:
return ">"
}
}
}
/// Test that the elements of `instances` satisfy the semantic
/// requirements of `Comparable`, using `oracle` to generate comparison
/// expectations from pairs of positions in `instances`.
///
/// - Note: `oracle` is also checked for conformance to the
/// laws.
public func checkComparable<
Instances: CollectionType where Instances.Generator.Element : Comparable
>(
instances: Instances,
oracle: (Instances.Index, Instances.Index) -> ExpectedComparisonResult,
${TRACE}
) {
// Also checks that equality is consistent with comparison and that
// the oracle obeys the equality laws
checkEquatable(instances, oracle: { oracle($0, $1).isEQ() }, ${trace})
for i in instances.indices {
let x = instances[i]
expectFalse(x < x, ${trace})
expectFalse(x > x, ${trace})
expectTrue(x <= x, ${trace})
expectTrue(x >= x, ${trace})
for j in instances.indices where i != j {
let y = instances[j]
let expected = oracle(i, j)
expectEqual(
expected.flip(), oracle(j, i),
"bad oracle: missing antisymmetry: "
+ "(\(String(reflecting: i)), \(String(reflecting: j)))",
stackTrace: ${stackTrace})
expectEqual(expected.isLT(), x < y, ${trace})
expectEqual(expected.isLE(), x <= y, ${trace})
expectEqual(expected.isGE(), x >= y, ${trace})
expectEqual(expected.isGT(), x > y, ${trace})
for k in instances.indices {
let expected2 = oracle(j, k)
if expected == expected2 {
expectEqual(
expected, oracle(i, k),
"bad oracle: missing transitivity "
+ "(\(String(reflecting: i)), \(String(reflecting: j)), "
+ "\(String(reflecting: k)))", stackTrace: ${stackTrace})
}
}
}
}
}
public func checkComparable<T : Comparable>(
expected: ExpectedComparisonResult, _ lhs: T, _ rhs: T, ${TRACE}
) {
checkComparable(
[lhs, rhs],
oracle: { [[ .EQ, expected], [ expected.flip(), .EQ]][$0][$1] },
${trace})
}
/// Test that the elements of `instances` satisfy the semantic
/// requirements of `Strideable`, using `advanceOracle` and
/// 'distanceOracle' to generate expectations about the results of
/// `advancedBy` and `distanceTo` from pairs of positions in
/// `instances` and `strides`.
///
/// - Note: `oracle` is also checked for conformance to the
/// laws.
public func checkStrideable<
Instances: CollectionType, Strides: CollectionType
where Instances.Generator.Element : Strideable,
Strides.Generator.Element == Instances.Generator.Element.Stride
>(
instances: Instances, strides: Strides,
distanceOracle:
(Instances.Index, Instances.Index) -> Strides.Generator.Element,
advanceOracle:
(Instances.Index, Strides.Index) -> Instances.Generator.Element,
${TRACE}
) {
checkComparable(
instances,
oracle: {
let d = distanceOracle($1, $0);
return d < 0 ? .LT : d == 0 ? .EQ : .GT
},
${trace})
for i in instances.indices {
let x = instances[i]
expectEqual(x, x.advancedBy(0))
for j in strides.indices {
let y = strides[j]
expectEqual(advanceOracle(i, j), x.advancedBy(y))
}
for j in instances.indices {
let y = instances[j]
expectEqual(distanceOracle(i, j), x.distanceTo(y))
}
}
}
public struct CollectionMisuseResiliencyChecks {
public enum FailureKind {
case None
case Trap
case ExpectationFailure
}
public var callNextOnExhaustedGenerator: Bool = true
public var creatingOutOfBoundsIndicesBehavior: FailureKind = .Trap
public var subscriptOnOutOfBoundsIndicesBehavior: FailureKind = .Trap
public var subscriptRangeOnOutOfBoundsRangesBehavior: FailureKind = .Trap
public static var all: CollectionMisuseResiliencyChecks {
return CollectionMisuseResiliencyChecks()
}
public static var none: CollectionMisuseResiliencyChecks {
return CollectionMisuseResiliencyChecks(
callNextOnExhaustedGenerator: false,
creatingOutOfBoundsIndicesBehavior: .None,
subscriptOnOutOfBoundsIndicesBehavior: .None,
subscriptRangeOnOutOfBoundsRangesBehavior: .None)
}
}
internal func _checkIncrementalAdvance<
Instances: CollectionType where Instances.Generator.Element : ForwardIndexType
>(
instances: Instances,
equalityOracle: (Instances.Index, Instances.Index)->Bool,
limit: Instances.Generator.Element,
sign: Instances.Generator.Element.Distance, // 1 or -1
next: (Instances.Generator.Element)->Instances.Generator.Element,
${TRACE}
) {
for i in instances {
let d = sign > 0 ? distance(i, limit) : -distance(limit, i)
var offset: Instances.Generator.Element.Distance = 0
for _ in 0...(d * sign).toIntMax() {
let j = advance(i, offset)
let k = advance(i, offset + sign, limit)
let jAtLimit = offset == d
if jAtLimit {
expectEqual(limit, j, ${trace})
}
expectEqual(jAtLimit ? j : next(j), k, ${trace})
offset += sign
}
}
}
/// Test that the elements of `instances` satisfy the semantic
/// requirements of `ForwardIndexType`, using `equalityOracle` to
/// generate equality expectations from pairs of positions in
/// `instances`.
///
/// - Precondition: `endIndex` is reachable from all elements of
/// `instances`
public func checkForwardIndex<
Instances: CollectionType where Instances.Generator.Element : ForwardIndexType
>(
instances: Instances,
equalityOracle: (Instances.Index, Instances.Index)->Bool,
endIndex: Instances.Generator.Element, ${TRACE}
) {
typealias Index = Instances.Generator.Element
checkIncrementable(
instances, equalityOracle: equalityOracle, endIndex: endIndex, ${trace})
_checkIncrementalAdvance(
instances, equalityOracle: equalityOracle, limit: endIndex,
sign: 1, next: { $0.successor() }, ${trace})
}
/// Test that the elements of `instances` satisfy the semantic
/// requirements of `BidirectionalIndexType`, using `equalityOracle`
/// to generate equality expectations from pairs of positions in
/// `instances`.
///
/// - Preconditions:
/// - all elements of `instances` are reachable from `startIndex`.
/// - `endIndex` is reachable from all elements of `instances`.
public func checkBidirectionalIndex<
Instances: CollectionType
where Instances.Generator.Element : BidirectionalIndexType
>(
instances: Instances,
equalityOracle: (Instances.Index, Instances.Index)->Bool,
startIndex: Instances.Generator.Element,
endIndex: Instances.Generator.Element,
${TRACE}
) {
typealias Index = Instances.Generator.Element
checkForwardIndex(
instances, equalityOracle: equalityOracle, endIndex: endIndex)
checkDecrementable(
instances, equalityOracle: equalityOracle, startIndex: startIndex, ${trace})
_checkIncrementalAdvance(
instances, equalityOracle: equalityOracle, limit: startIndex,
sign: -1, next: { $0.predecessor() }, ${trace})
}
/// Test that the elements of `instances` satisfy the semantic
/// requirements of `RandomAccessIndexType`, using
/// `advanceOracle` and 'distanceOracle' to generate expectations
/// about the results of `advancedBy` and `distanceTo` from pairs of
/// positions in `instances` and `distances`.
///
/// - Preconditions:
/// - all elements of `instances` are reachable from `startIndex`.
/// - `endIndex` is reachable from all elements of `instances`.
public func checkRandomAccessIndex<
Instances: CollectionType, Distances: CollectionType
where Instances.Generator.Element : RandomAccessIndexType,
Distances.Generator.Element == Instances.Generator.Element.Distance,
Instances.Generator.Element.Distance == Instances.Generator.Element.Stride
>(
instances: Instances, distances: Distances,
distanceOracle:
(Instances.Index, Instances.Index) -> Distances.Generator.Element,
advanceOracle:
(Instances.Index, Distances.Index) -> Instances.Generator.Element,
startIndex: Instances.Generator.Element,
endIndex: Instances.Generator.Element,
${TRACE}
) {
checkBidirectionalIndex(
instances, equalityOracle: { distanceOracle($0, $1) == 0 },
startIndex: startIndex, endIndex: endIndex, ${trace})
checkStrideable(
instances, strides: distances,
distanceOracle: distanceOracle,
advanceOracle: advanceOracle, ${trace})
}
// Generate two overloads: one for Array (which will get
// picked up when the caller passes a literal), and another that
// accepts any appropriate Collection type.
% for genericParam, Element, Expected in zip(
% ('Expected: CollectionType', 'Element'),
% ('Expected.Generator.Element', 'Element'),
% ('Expected', 'Array<Element>')):
public func checkGenerator<
${genericParam}, G : GeneratorType
where G.Element == ${Element}
>(
expected: ${Expected},
_ generator: G,
${TRACE},
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
sameValue: (${Element}, ${Element}) -> Bool
) {
// Copying a `GeneratorType` is allowed.
var mutableGen = generator
var actual: [${Element}] = []
while let e = mutableGen.next() {
actual.append(e)
}
expectEqualSequence(
expected, actual, ${trace}, sameValue: sameValue)
if resiliencyChecks.callNextOnExhaustedGenerator {
// Having returned `.None` once, a `GeneratorType` should not generate more
// elements.
for _ in 0..<10 {
expectEmpty(mutableGen.next(), ${trace})
}
}
}
public func checkGenerator<
${genericParam}, G : GeneratorType
where G.Element == ${Element}, ${Element} : Equatable
>(
expected: ${Expected},
_ generator: G,
${TRACE},
resiliencyChecks: CollectionMisuseResiliencyChecks = .all
) {
checkGenerator(
expected, generator, ${trace},
resiliencyChecks: resiliencyChecks, showFrame: false
) { $0 == $1 }
}
public func checkSequence<
${genericParam}, S : SequenceType
where S.Generator.Element == ${Element}
>(
expected: ${Expected},
_ sequence: S,
${TRACE},
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
sameValue: (${Element}, ${Element}) -> Bool
) {
let expectedCount: Int = numericCast(expected.count)
checkGenerator(
expected, sequence.generate(), ${trace},
resiliencyChecks: resiliencyChecks,
sameValue: sameValue)
expectGE(
expectedCount, sequence.underestimateCount(), ${trace})
// Check that _initializeTo does the right thing if we can do so
// without destroying the sequence.
sequence._preprocessingPass { (sequence)->Void in
var count = 0
for _ in sequence { ++count }
let buf = UnsafeMutablePointer<S.Generator.Element>.alloc(count)
let end = sequence._initializeTo(buf)
expectTrue(end == buf + count, "_initializeTo returned the wrong value")
var j = expected.startIndex
for i in 0..<(end - buf) {
expectTrue(sameValue(expected[j++], buf[i]))
}
buf.destroy(end - buf)
buf.dealloc(count)
}
}
public func checkSequence<
${genericParam}, S : SequenceType
where S.Generator.Element == ${Element}, S.Generator.Element : Equatable
>(
expected: ${Expected},
_ sequence: S,
${TRACE},
resiliencyChecks: CollectionMisuseResiliencyChecks = .all
) {
checkSequence(
expected, sequence, ${trace},
resiliencyChecks: resiliencyChecks, showFrame: false
) { $0 == $1 }
}
%for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]:
public func check${traversal}Collection<
${genericParam}, C : CollectionType
where
C.Generator.Element == ${Element},
C.Index : ${traversal}IndexType
% if traversal == 'RandomAccess':
, C.Index.Stride == C.Index.Distance
% end
>(
expected: ${Expected}, _ collection: C,
${TRACE},
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
sameValue: (${Element}, ${Element}) -> Bool
) {
// A `CollectionType` is a multi-pass `SequenceType`.
for _ in 0..<3 {
checkSequence(
expected, collection, ${trace},
resiliencyChecks: resiliencyChecks, sameValue: sameValue)
}
// advances up to 1 positions without passing endIndex. Don't use
// advance() to do this because it's under test here.
let next = { $0 == collection.endIndex ? $0 : $0.successor() }
// advances up to 5 positions without passing endIndex. Picking a
// small constant to avoid complexity explosion on large input
// collections.
let next5 = { next(next(next(next(next($0))))) }
let partWay0 = next5(collection.startIndex)
let partWay1 = next5(partWay0)
% if traversal == 'Forward':
checkForwardIndex(
collection.startIndex..<partWay0, equalityOracle: { $0 == $1 },
endIndex: partWay1, ${trace})
% elif traversal == 'Bidirectional':
checkBidirectionalIndex(
partWay0..<partWay1, equalityOracle: { $0 == $1 },
startIndex: collection.startIndex,
endIndex: next5(partWay1), ${trace})
% else:
% assert(traversal == 'RandomAccess')
typealias Distance = C.Index.Distance
let count: Distance = collection.count
let offset0 = min(5, count)
let offset1 = min(10, count)
let offset2 = min(15, count)
let distanceCandidates: [Distance] = [
-11, -7, -5, -3, -2, -1, 0, 1, 2, 3, 5, 7, 11]
let distances = distanceCandidates.filter { (x: Distance) -> Bool in
x + offset0 >= 0 && x + offset1 <= count
}
func nextN(n: C.Index.Distance, var _ i: C.Index) -> C.Index {
if n < 0 {
for _ in 0 ..< -(n.toIntMax()) {
--i
}
}
else {
for _ in 0..<n.toIntMax() {
++i
}
}
return i
}
let instances = Array(partWay0..<partWay1)
typealias Distances = [Distance]
checkRandomAccessIndex(
instances,
distances: distances,
distanceOracle: { (x:Int,y:Int) in Distance(IntMax(y - x)) },
advanceOracle: { x,y in nextN(distances[y], instances[x]) },
startIndex: collection.startIndex,
endIndex: next5(partWay1), ${trace})
% end
let expectedArray = Array(expected)
expectEqual(
expectedArray.count.toIntMax(), collection.count.toIntMax(), ${trace})
for _ in 0..<3 {
if true {
let startIndex = collection.startIndex
let endIndex = collection.endIndex
for _ in collection.indices {
expectEqual(
startIndex, collection.startIndex,
"Iteration should not change startIndex",
stackTrace: ${stackTrace})
expectEqual(
endIndex, collection.endIndex,
"Iteration should not change endIndex",
stackTrace: ${stackTrace})
}
}
var allIndices = Array(collection.indices)
if expectedArray.count >= 2 {
for i in 0..<allIndices.count-1 {
let successor1 = allIndices[i].successor()
var successor2 = allIndices[i]
successor2++
var successor3 = allIndices[i]
++successor3
for s in [ successor1, successor2, successor3 ] {
expectEqual(allIndices[i + 1], s, ${trace})
expectEqual(
expectedArray[i + 1], collection[s], ${trace}, sameValue: sameValue)
}
}
% if traversal == "Bidirectional":
for i in 1..<allIndices.count {
let predecessor1 = allIndices[i].predecessor()
var predecessor2 = allIndices[i]
predecessor2--
var predecessor3 = allIndices[i]
--predecessor3
for p in [ predecessor1, predecessor2, predecessor3 ] {
expectEqual(allIndices[i - 1], p, ${trace})
expectEqual(
expectedArray[i - 1], collection[p], ${trace}, sameValue: sameValue)
}
}
for i in 1..<allIndices.count {
var index = allIndices[i]
--index
++index
expectEqual(allIndices[i], index, ${trace})
expectEqual(
expectedArray[i], collection[index], ${trace}, sameValue: sameValue)
}
% end
}
if true {
var allIndices2: [C.Index] = []
for i in collection.indices {
allIndices2.append(i)
}
expectEqualSequence(
allIndices, allIndices2, "iteration should not invalidate indices",
stackTrace: ${stackTrace})
expectEqualSequence(
expectedArray, allIndices.map { collection[$0] },
stackTrace: ${stackTrace}, sameValue: sameValue)
expectEqualSequence(
expectedArray, allIndices2.map { collection[$0] },
stackTrace: ${stackTrace}, sameValue: sameValue)
}
}
// FIXME: more checks for bidirectional and random access collections.
}
public func check${traversal}Collection<
${genericParam}, C : CollectionType
where
C.Generator.Element == ${Element},
C.Index : ${traversal}IndexType,
${Element} : Equatable
% if traversal == 'RandomAccess':
, C.Index.Stride == C.Index.Distance
% end
>(
expected: ${Expected}, _ collection: C,
${TRACE},
resiliencyChecks: CollectionMisuseResiliencyChecks = .all
) {
check${traversal}Collection(
expected, collection, ${trace},
resiliencyChecks: resiliencyChecks) { $0 == $1 }
}
% end
// FIXME: merge into checkCollection()
public func checkSliceableWithBidirectionalIndex<
${genericParam}, S : CollectionType
where
S.Generator.Element == ${Element},
S.SubSequence.Generator.Element == ${Element},
S.Index : BidirectionalIndexType,
S.SubSequence : CollectionType,
S.SubSequence.Index : BidirectionalIndexType,
${Element} : Equatable
>(
expected: ${Expected}, _ sliceable: S, ${TRACE}
) {
// A `Sliceable` is a `CollectionType`.
checkBidirectionalCollection(expected, sliceable, ${trace})
let expectedArray = Array(expected)
var start = sliceable.startIndex
for startNumericIndex in 0...expectedArray.count {
if start != sliceable.endIndex {
++start
--start
++start
--start
}
var end = start
for endNumericIndex in startNumericIndex...expectedArray.count {
if end != sliceable.endIndex {
++end
--end
++end
--end
}
let expectedSlice = expectedArray[startNumericIndex..<endNumericIndex]
let slice = sliceable[start..<end]
checkBidirectionalCollection(expectedSlice, slice, ${trace})
if end != sliceable.endIndex {
++end
}
}
if start != sliceable.endIndex {
++start
}
}
}
% end
public func nthIndex<C: CollectionType>(x: C, _ n: Int) -> C.Index {
return advance(x.startIndex, numericCast(n))
}
public func nth<C: CollectionType>(x: C, _ n: Int) -> C.Generator.Element {
return x[nthIndex(x, n)]
}
public func checkRangeReplaceable<
C: RangeReplaceableCollectionType,
N: CollectionType
where
C.Generator.Element : Equatable, C.Generator.Element == N.Generator.Element
>(
makeCollection: ()->C,
_ makeNewValues: (Int)->N
) {
typealias A = C
// First make an independent copy of the array that we can use for
// comparison later.
let source = Array<A.Generator.Element>(makeCollection())
for (ix, i) in source.indices.enumerate() {
for (jx_, j) in (i..<source.endIndex).enumerate() {
let jx = jx_ + ix
let oldCount = jx - ix
for newCount in 0..<(2 * oldCount) {
let newValues = makeNewValues(newCount)
func reportFailure(inout a: A, _ message: String) {
print("\(message) when replacing indices \(ix)...\(jx)")
print(" in \(Array(source)) with \(Array(newValues))")
print(" yielding \(Array(a))")
print("====================================")
expectTrue(false)
}
var a = makeCollection()
a.replaceRange(nthIndex(a, ix)..<nthIndex(a, jx), with: newValues)
let growth = newCount - oldCount
let expectedCount = source.count + growth
let actualCount = numericCast(a.count) as Int
if actualCount != expectedCount {
reportFailure(
&a, "\(actualCount) != expected count \(expectedCount)")
}
for (kx, k) in a.indices.enumerate() {
let expectedValue = kx < ix ? nth(source, kx)
: kx < jx + growth ? nth(newValues, kx - ix)
: nth(source, kx - growth)
if a[k] != expectedValue {
reportFailure(
&a,
// FIXME: why do we need to break this string into two parts?
"a[\(kx)] = "
+ "\(a[k]) != expected value \(expectedValue)")
}
}
}
}
}
}
public func expectEqualSequence<
Expected: SequenceType,
Actual: SequenceType
where Expected.Generator.Element == Actual.Generator.Element,
Expected.Generator.Element : Equatable
>(expected: Expected, _ actual: Actual, ${TRACE}) {
expectEqualSequence(expected, actual, ${trace}) { $0 == $1 }
}
public func expectEqualSequence<
Expected : SequenceType,
Actual : SequenceType,
T : Equatable,
U : Equatable
where Expected.Generator.Element == Actual.Generator.Element,
Expected.Generator.Element == (T, U)
>(expected: Expected, _ actual: Actual, ${TRACE}) {
expectEqualSequence(
expected, actual, ${trace}) {
(lhs: (T, U), rhs: (T, U)) -> Bool in
lhs.0 == rhs.0 && lhs.1 == rhs.1
}
}
public func expectEqualSequence<
Expected: SequenceType,
Actual: SequenceType
where Expected.Generator.Element == Actual.Generator.Element
>(expected: Expected, _ actual: Actual, ${TRACE},
sameValue: (Expected.Generator.Element, Expected.Generator.Element)->Bool) {
if !expected.elementsEqual(actual, isEquivalent: sameValue) {
expectationFailure("expected elements: \"\(expected)\"\n"
+ "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace})
}
}
public func expectEqualsUnordered<
Expected : SequenceType,
Actual : SequenceType
where Expected.Generator.Element == Actual.Generator.Element
>(
expected: Expected, _ actual: Actual, ${TRACE},
compare: (Expected.Generator.Element, Expected.Generator.Element)
-> ExpectedComparisonResult
) {
let x: [Expected.Generator.Element] =
expected.sort(compose(compare, { $0.isLT() }))
let y: [Actual.Generator.Element] =
actual.sort(compose(compare, { $0.isLT() }))
expectEqualSequence(
x, y, ${trace}, sameValue: compose(compare, { $0.isEQ() }))
}
public func expectEqualsUnordered<
Expected : SequenceType,
Actual : SequenceType
where
Expected.Generator.Element == Actual.Generator.Element,
Expected.Generator.Element : Comparable
>(
expected: Expected, _ actual: Actual, ${TRACE}
) {
expectEqualsUnordered(expected, actual, ${trace}) {
$0 < $1 ? .LT : $0 == $1 ? .EQ : .GT
}
}
public func expectEqualsUnordered<T : Comparable>(
expected: [T], _ actual: [T], ${TRACE}
) {
let x = expected.sort()
let y = actual.sort()
expectEqualSequence(x, y, ${trace})
}
/// A nominal type that is equivalent to a tuple of two elements.
///
/// We need a nominal type because we can't add protocol conformances to
/// tuples.
struct Pair<T : Comparable> : Comparable {
init(_ first: T, _ second: T) {
self.first = first
self.second = second
}
var first: T
var second: T
}
func == <T>(lhs: Pair<T>, rhs: Pair<T>) -> Bool {
return lhs.first == rhs.first && lhs.second == rhs.second
}
func < <T>(lhs: Pair<T>, rhs: Pair<T>) -> Bool {
return [ lhs.first, lhs.second ].lexicographicalCompare(
[ rhs.first, rhs.second ])
}
public func expectEqualsUnordered<
Expected : SequenceType,
Actual : SequenceType,
T : Comparable
where
Expected.Generator.Element == Actual.Generator.Element,
Expected.Generator.Element == (T, T)
>(
expected: Expected, _ actual: Actual, ${TRACE}
) {
func comparePairLess(lhs: (T, T), rhs: (T, T)) -> Bool {
return [ lhs.0, lhs.1 ].lexicographicalCompare([ rhs.0, rhs.1 ])
}
let x: [(T, T)] = Array(expected).sort(comparePairLess)
let y: [(T, T)] = Array(actual).sort(comparePairLess)
func comparePairEquals(lhs: (T, T), rhs: (T, T)) -> Bool {
return lhs.0 == rhs.0 && lhs.1 == rhs.1
}
expectEqualSequence(x, y, ${trace}, sameValue: comparePairEquals)
}
public func expectEqualFunctionsForDomain<ArgumentType, Result : Equatable>(
arguments: [ArgumentType], _ function1: ArgumentType -> Result,
_ function2: ArgumentType -> Result
) {
for a in arguments {
let expected = function1(a)
let actual = function2(a)
expectEqual(expected, actual, "where the argument is: \(a)")
}
}
public func expectEqualMethodsForDomain<
SelfType, ArgumentType, Result : Equatable
>(
selfs: [SelfType], _ arguments: [ArgumentType],
_ function1: SelfType -> ArgumentType -> Result,
_ function2: SelfType -> ArgumentType -> Result
) {
for s in selfs {
for a in arguments {
let expected = function1(s)(a)
let actual = function2(s)(a)
expectEqual(
expected, actual,
"where the first argument is: \(s)\nand the second argument is: \(a)"
)
}
}
}
public func expectEqualUnicodeScalars(
expected: [UInt32], _ actual: String, ${TRACE}) {
let actualUnicodeScalars = Array(
actual.unicodeScalars.lazy.map { $0.value })
if !expected.elementsEqual(actualUnicodeScalars) {
expectationFailure(
"expected elements: \"\(asHex(expected))\"\n"
+ "actual: \"\(asHex(actualUnicodeScalars))\"",
trace: ${trace})
}
}
public func expectPrinted<T>(
expectedOneOf patterns: [String], _ object: T, ${TRACE}
) {
let actual = String(object)
if !patterns.contains(actual) {
expectationFailure(
"expected: any of \(String(reflecting: patterns))\n"
+ "actual: \(String(reflecting: actual))",
trace: ${trace})
}
}
public func expectPrinted<T>(
expected: String, _ object: T, ${TRACE}
) {
expectPrinted(expectedOneOf: [expected], object, ${trace})
}
public func expectDebugPrinted<T>(
expectedOneOf patterns: [String], _ object: T, ${TRACE}
) {
expectPrinted(expectedOneOf: patterns, String(reflecting: object), ${trace})
}
public func expectDebugPrinted<T>(
expected: String, _ object: T, ${TRACE}
) {
expectDebugPrinted(expectedOneOf: [expected], object, ${trace})
}
func compose<A, B, C>(f: A -> B, _ g: B -> C) -> A -> C {
return { a in
return g(f(a))
}
}
/// State that is created every time a fresh generator is created with
/// `MinimalSequence.generate()`.
internal class _MinimalGeneratorPrivateState<T> {
internal init() {}
internal var returnedNilCounter: Int = 0
}
/// State shared by all generators of a MinimalSequence.
internal class _MinimalGeneratorSharedState<T> {
internal init(_ data: [T]) {
self.data = data
}
internal let data: [T]
internal var i: Int = 0
internal var underestimatedCount: Int = 0
}
//===----------------------------------------------------------------------===//
// MinimalGenerator
//===----------------------------------------------------------------------===//
/// A GeneratorType that implements the protocol contract in the most
/// narrow way possible.
///
/// This generator will return `nil` only once.
public struct MinimalGenerator<T> : GeneratorType {
public init<S : SequenceType where S.Generator.Element == T>(_ s: S) {
self._sharedState = _MinimalGeneratorSharedState(Array(s))
}
public init(_ data: [T]) {
self._sharedState = _MinimalGeneratorSharedState(data)
}
internal init(_ _sharedState: _MinimalGeneratorSharedState<T>) {
self._sharedState = _sharedState
}
public func next() -> T? {
if _sharedState.i == _sharedState.data.count {
if isConsumed {
expectUnreachable("next() was called on a consumed generator")
}
++_privateState.returnedNilCounter
return nil
}
return _sharedState.data[_sharedState.i++]
}
public var isConsumed: Bool {
return returnedNilCounter >= 1
}
public var returnedNilCounter: Int {
return _privateState.returnedNilCounter
}
internal let _privateState: _MinimalGeneratorPrivateState<T> =
_MinimalGeneratorPrivateState()
internal let _sharedState: _MinimalGeneratorSharedState<T>
}
// A protocol to identify MinimalGenerator.
public protocol _MinimalGeneratorType {}
extension MinimalGenerator : _MinimalGeneratorType {}
//===----------------------------------------------------------------------===//
// MinimalSequence
//===----------------------------------------------------------------------===//
public enum UnderestimateCountBehavior {
/// Return the actual number of elements.
case Precise
/// Return the actual number of elements divided by 2.
case Half
/// Return an overestimated count. Useful to test how algorithms reserve
/// memory.
case Overestimate
/// Return the provided value.
case Value(Int)
}
public protocol StrictSequenceType : SequenceType {
typealias Element
init(base: MinimalSequence<Element>)
var base: MinimalSequence<Element> { get }
}
extension StrictSequenceType {
public init<S : SequenceType where S.Generator.Element == Element>(
elements: S,
underestimatedCount: UnderestimateCountBehavior = .Value(0)
) {
self.init(base: MinimalSequence(
elements: elements, underestimatedCount: underestimatedCount))
}
public func underestimateCount() -> Int {
return base.underestimateCount()
}
}
extension StrictSequenceType where Generator : _MinimalGeneratorType {
public func generate() -> MinimalGenerator<Element> {
return base.generate()
}
}
/// A SequenceType that implements the protocol contract in the most
/// narrow way possible.
///
/// This sequence is consumed when its generator is advanced.
public struct MinimalSequence<T> : SequenceType, CustomDebugStringConvertible {
public init<S : SequenceType where S.Generator.Element == T>(
elements: S,
underestimatedCount: UnderestimateCountBehavior = .Value(0)
) {
let data = Array(elements)
self._sharedState = _MinimalGeneratorSharedState(data)
switch underestimatedCount {
case .Precise:
self._sharedState.underestimatedCount = data.count
case .Half:
self._sharedState.underestimatedCount = data.count / 2
case .Overestimate:
self._sharedState.underestimatedCount = data.count * 3 + 5
case .Value(let count):
self._sharedState.underestimatedCount = count
}
}
public func generate() -> MinimalGenerator<T> {
return MinimalGenerator(_sharedState)
}
public func underestimateCount() -> Int {
return max(0, self._sharedState.underestimatedCount - self._sharedState.i)
}
public var debugDescription: String {
return "MinimalSequence(\(_sharedState.data[_sharedState.i..<_sharedState.data.count]))"
}
internal let _sharedState: _MinimalGeneratorSharedState<T>
}
//===----------------------------------------------------------------------===//
// Index invalidation checking
//===----------------------------------------------------------------------===//
internal enum _CollectionOperation : Equatable {
case ReserveCapacity(capacity: Int)
case Append
case AppendContentsOf(count: Int)
case ReplaceRange(subRange: Range<Int>, replacementCount: Int)
case Insert(atIndex: Int)
case InsertContentsOf(atIndex: Int, count: Int)
case RemoveAtIndex(index: Int)
case RemoveLast
case RemoveRange(subRange: Range<Int>)
case RemoveAll(keepCapacity: Bool)
internal func _applyTo(
elementsLastMutatedStateIds: [Int], nextStateId: Int) -> [Int] {
var result = elementsLastMutatedStateIds
switch self {
case ReserveCapacity:
let invalidIndices = result.indices
result.replaceRange(
invalidIndices,
with: Repeat(count: invalidIndices.count, repeatedValue: nextStateId))
case Append:
result.append(nextStateId)
case AppendContentsOf(let count):
result.appendContentsOf(
Repeat(count: count, repeatedValue: nextStateId))
case ReplaceRange(let subRange, let replacementCount):
result.replaceRange(
subRange,
with: Repeat(count: replacementCount, repeatedValue: nextStateId))
let invalidIndices = subRange.startIndex..<result.endIndex
result.replaceRange(
invalidIndices,
with: Repeat(count: invalidIndices.count, repeatedValue: nextStateId))
case Insert(let atIndex):
result.insert(nextStateId, atIndex: atIndex)
let invalidIndices = atIndex..<result.endIndex
result.replaceRange(
invalidIndices,
with: Repeat(count: invalidIndices.count, repeatedValue: nextStateId))
case InsertContentsOf(let atIndex, let count):
result.insertContentsOf(
Repeat(count: count, repeatedValue: nextStateId),
at: atIndex)
let invalidIndices = atIndex..<result.endIndex
result.replaceRange(
invalidIndices,
with: Repeat(count: invalidIndices.count, repeatedValue: nextStateId))
case RemoveAtIndex(let index):
result.removeAtIndex(index)
let invalidIndices = index..<result.endIndex
result.replaceRange(
invalidIndices,
with: Repeat(count: invalidIndices.count, repeatedValue: nextStateId))
case RemoveLast:
result.removeLast()
case RemoveRange(let subRange):
result.removeRange(subRange)
let invalidIndices = subRange.startIndex..<result.endIndex
result.replaceRange(
invalidIndices,
with: Repeat(count: invalidIndices.count, repeatedValue: nextStateId))
case RemoveAll(let keepCapacity):
result.removeAll(keepCapacity: keepCapacity)
}
return result
}
}
internal func == (
lhs: _CollectionOperation,
rhs: _CollectionOperation
) -> Bool {
switch (lhs, rhs) {
case (.ReserveCapacity(let lhsCapacity), .ReserveCapacity(let rhsCapacity)):
return lhsCapacity == rhsCapacity
case (.Append, .Append):
return true
case (.AppendContentsOf(let lhsCount), .AppendContentsOf(let rhsCount)):
return lhsCount == rhsCount
case (
.ReplaceRange(let lhsSubRange, let lhsReplacementCount),
.ReplaceRange(let rhsSubRange, let rhsReplacementCount)):
return lhsSubRange == rhsSubRange &&
lhsReplacementCount == rhsReplacementCount
case (.Insert(let lhsAtIndex), .Insert(let rhsAtIndex)):
return lhsAtIndex == rhsAtIndex
case (
.InsertContentsOf(let lhsAtIndex, let lhsCount),
.InsertContentsOf(let rhsAtIndex, let rhsCount)):
return lhsAtIndex == rhsAtIndex && lhsCount == rhsCount
case (.RemoveAtIndex(let lhsIndex), .RemoveAtIndex(let rhsIndex)):
return lhsIndex == rhsIndex
case (.RemoveLast, .RemoveLast):
return true
case (.RemoveRange(let lhsSubRange), .RemoveRange(let rhsSubRange)):
return lhsSubRange == rhsSubRange
case (.RemoveAll(let lhsKeepCapacity), .RemoveAll(let rhsKeepCapacity)):
return lhsKeepCapacity == rhsKeepCapacity
default:
return false
}
}
public struct _CollectionState : Equatable, Hashable {
internal static var _nextUnusedState: Int = 0
internal static var _namedStates: [String : _CollectionState] = [:]
internal let _id: Int
internal let _elementsLastMutatedStateIds: [Int]
internal init(id: Int, elementsLastMutatedStateIds: [Int]) {
self._id = id
self._elementsLastMutatedStateIds = elementsLastMutatedStateIds
}
internal init(newRootStateForElementCount count: Int) {
self._id = _CollectionState._nextUnusedState++
self._elementsLastMutatedStateIds =
Array(Repeat(count: count, repeatedValue: self._id))
}
internal init(name: String, elementCount: Int) {
if let result = _CollectionState._namedStates[name] {
self = result
} else {
self = _CollectionState(newRootStateForElementCount: elementCount)
_CollectionState._namedStates[name] = self
}
}
public var hashValue: Int {
return _id.hashValue
}
}
public func == (lhs: _CollectionState, rhs: _CollectionState) -> Bool {
return lhs._id == rhs._id
}
internal struct _CollectionStateTransition {
internal let _previousState: _CollectionState
internal let _operation: _CollectionOperation
internal let _nextState: _CollectionState
internal static var _allTransitions:
[_CollectionState : Box<[_CollectionStateTransition]>] = [:]
internal init(
previousState: _CollectionState,
operation: _CollectionOperation,
nextState: _CollectionState
) {
var transitions =
_CollectionStateTransition._allTransitions[previousState]
if transitions == nil {
transitions = Box<[_CollectionStateTransition]>([])
_CollectionStateTransition._allTransitions[previousState] = transitions
}
if let i = transitions!.value.indexOf({ $0._operation == operation }) {
self = transitions!.value[i]
return
}
self._previousState = previousState
self._operation = operation
self._nextState = nextState
transitions!.value.append(self)
}
internal init(
previousState: _CollectionState,
operation: _CollectionOperation
) {
let nextStateId = _CollectionState._nextUnusedState++
let newElementStates = operation._applyTo(
previousState._elementsLastMutatedStateIds, nextStateId: nextStateId)
let nextState = _CollectionState(
id: nextStateId, elementsLastMutatedStateIds: newElementStates)
self = _CollectionStateTransition(
previousState: previousState,
operation: operation,
nextState: nextState)
}
}
//===----------------------------------------------------------------------===//
// MinimalForwardIndex
//===----------------------------------------------------------------------===//
/// Asserts that the two indices are allowed to participate in a binary
/// operation.
internal func _expectCompatibleIndices<Index : _MinimalIndexType>(
first: Index,
_ second: Index,
${TRACE}
) {
if let firstStateId = first._collectionState?._id,
let secondStateId = second._collectionState?._id
where firstStateId == secondStateId {
// The indices are derived from the same state.
return
}
// The indices are derived from different states. Check that they point
// to elements that persisted from the same state.
func getLastMutatedStateId(i: Index) -> Int? {
guard let state = i._collectionState else { return nil }
let offset = i._offset
if offset == state._elementsLastMutatedStateIds.endIndex {
return state._id
}
return state._elementsLastMutatedStateIds[offset]
}
let firstElementLastMutatedStateId = getLastMutatedStateId(first)
let secondElementLastMutatedStateId = getLastMutatedStateId(second)
expectEqual(
firstElementLastMutatedStateId,
secondElementLastMutatedStateId,
"Indices are not compatible:\n" +
"first: \(first)\n" +
"second: \(second)\n" +
"first element last mutated in state id: \(firstElementLastMutatedStateId)\n" +
"second element last mutated in state id: \(secondElementLastMutatedStateId)\n",
stackTrace: ${stackTrace})
// To make writing assertions easier, perform a trap.
if firstElementLastMutatedStateId != secondElementLastMutatedStateId {
fatalError("Indices are not compatible")
}
}
public protocol _MinimalIndexType {
/// Distance from start index.
var _offset: Int { get }
var _collectionState: _CollectionState? { get }
}
% for Distance in [ '', 'Int32' ]:
% Index = 'MinimalForward%sIndex' % Distance
public struct ${Index} : ForwardIndexType {
% if Distance != '':
public typealias Distance = ${Distance}
% end
public init(position: Int, startIndex: Int, endIndex: Int) {
self = ${Index}(
collectionState: nil,
position: position,
startIndex: startIndex,
endIndex: endIndex)
}
internal init(
collectionState: _CollectionState?,
position: Int,
startIndex: Int,
endIndex: Int
) {
expectLE(startIndex, position)
expectGE(endIndex, position)
self._collectionState = collectionState
self.position = position
self.startIndex = startIndex
self.endIndex = endIndex
}
public func successor() -> ${Index} {
expectNotEqual(endIndex, position)
return ${Index}(
collectionState: _collectionState,
position: position + 1, startIndex: startIndex, endIndex: endIndex)
}
public static func _failEarlyRangeCheck(
index: ${Index}, bounds: Range<${Index}>
) {
expectLE(bounds.startIndex.position, index.position)
expectGT(bounds.endIndex.position, index.position)
if ${Index}.trapOnRangeCheckFailure.value {
Int._failEarlyRangeCheck(
index.position,
bounds: bounds.startIndex.position..<bounds.endIndex.position)
}
}
public static func _failEarlyRangeCheck2(
rangeStart: ${Index}, rangeEnd: ${Index},
boundsStart: ${Index}, boundsEnd: ${Index}
) {
let range = rangeStart..<rangeEnd
let bounds = boundsStart..<boundsEnd
expectLE(bounds.startIndex.position, range.startIndex.position)
expectGE(bounds.endIndex.position, range.startIndex.position)
expectLE(bounds.startIndex.position, range.endIndex.position)
expectGE(bounds.endIndex.position, range.endIndex.position)
if ${Index}.trapOnRangeCheckFailure.value {
Int._failEarlyRangeCheck2(
rangeStart.position,
rangeEnd: rangeEnd.position,
boundsStart: boundsStart.position,
boundsEnd: boundsEnd.position)
}
}
public let _collectionState: _CollectionState?
public let position: Int
public let startIndex: Int
public let endIndex: Int
public static var trapOnRangeCheckFailure = ResettableValue(true)
}
public func == (lhs: ${Index}, rhs: ${Index}) -> Bool {
_expectCompatibleIndices(lhs, rhs)
return lhs.position == rhs.position
}
extension ${Index} : _MinimalIndexType {
public var _offset: Int {
return position - startIndex
}
}
% end
//===----------------------------------------------------------------------===//
// MinimalBidirectionalIndex
//===----------------------------------------------------------------------===//
public struct MinimalBidirectionalIndex : BidirectionalIndexType {
public init(position: Int, startIndex: Int, endIndex: Int) {
self = MinimalBidirectionalIndex(
collectionState: nil,
position: position,
startIndex: startIndex,
endIndex: endIndex)
}
internal init(
collectionState: _CollectionState?,
position: Int,
startIndex: Int,
endIndex: Int
) {
expectLE(startIndex, position)
expectGE(endIndex, position)
self._collectionState = collectionState
self.position = position
self.startIndex = startIndex
self.endIndex = endIndex
}
public func successor() -> MinimalBidirectionalIndex {
expectNotEqual(endIndex, position)
return MinimalBidirectionalIndex(
collectionState: _collectionState,
position: position + 1, startIndex: startIndex, endIndex: endIndex)
}
public func predecessor() -> MinimalBidirectionalIndex {
expectNotEqual(startIndex, position)
return MinimalBidirectionalIndex(
collectionState: _collectionState,
position: position - 1, startIndex: startIndex, endIndex: endIndex)
}
public static func _failEarlyRangeCheck(
index: MinimalBidirectionalIndex,
bounds: Range<MinimalBidirectionalIndex>
) {
expectLE(bounds.startIndex.position, index.position)
expectGT(bounds.endIndex.position, index.position)
if MinimalBidirectionalIndex.trapOnRangeCheckFailure.value {
Int._failEarlyRangeCheck(
index.position,
bounds: bounds.startIndex.position..<bounds.endIndex.position)
}
}
public static func _failEarlyRangeCheck2(
rangeStart: MinimalBidirectionalIndex,
rangeEnd: MinimalBidirectionalIndex,
boundsStart: MinimalBidirectionalIndex,
boundsEnd: MinimalBidirectionalIndex
) {
let range = rangeStart..<rangeEnd
let bounds = boundsStart..<boundsEnd
expectLE(bounds.startIndex.position, range.startIndex.position)
expectGE(bounds.endIndex.position, range.startIndex.position)
expectLE(bounds.startIndex.position, range.endIndex.position)
expectGE(bounds.endIndex.position, range.endIndex.position)
if MinimalBidirectionalIndex.trapOnRangeCheckFailure.value {
Int._failEarlyRangeCheck2(
rangeStart.position,
rangeEnd: rangeEnd.position,
boundsStart: boundsStart.position,
boundsEnd: boundsEnd.position)
}
}
public let _collectionState: _CollectionState?
public let position: Int
public let startIndex: Int
public let endIndex: Int
public static var trapOnRangeCheckFailure = ResettableValue(true)
}
public func == (
lhs: MinimalBidirectionalIndex,
rhs: MinimalBidirectionalIndex
) -> Bool {
_expectCompatibleIndices(lhs, rhs)
return lhs.position == rhs.position
}
extension MinimalBidirectionalIndex : _MinimalIndexType {
public var _offset: Int {
return position - startIndex
}
}
//===----------------------------------------------------------------------===//
// MinimalRandomAccessIndex
//===----------------------------------------------------------------------===//
public struct MinimalRandomAccessIndex : RandomAccessIndexType {
public init(position: Int, startIndex: Int, endIndex: Int) {
self = MinimalRandomAccessIndex(
collectionState: nil,
position: position,
startIndex: startIndex,
endIndex: endIndex)
}
internal init(
collectionState: _CollectionState?,
position: Int,
startIndex: Int,
endIndex: Int
) {
expectLE(startIndex, position)
expectGE(endIndex, position) /*{
"position=\(self.position) startIndex=\(self.startIndex) endIndex=\(self.endIndex)"
}*/
self._collectionState = collectionState
self.position = position
self.startIndex = startIndex
self.endIndex = endIndex
}
public func successor() -> MinimalRandomAccessIndex {
expectNotEqual(endIndex, position)
return MinimalRandomAccessIndex(
collectionState: _collectionState,
position: position + 1, startIndex: startIndex, endIndex: endIndex)
}
public func predecessor() -> MinimalRandomAccessIndex {
expectNotEqual(startIndex, position)
return MinimalRandomAccessIndex(
collectionState: _collectionState,
position: position - 1, startIndex: startIndex, endIndex: endIndex)
}
public func distanceTo(other: MinimalRandomAccessIndex) -> Int {
_expectCompatibleIndices(self, other)
return other.position - position
}
public func advancedBy(n: Int) -> MinimalRandomAccessIndex {
let newPosition = position + n
expectLE(startIndex, newPosition)
expectGE(
endIndex, newPosition,
"position=\(self.position) startIndex=\(self.startIndex)")
return MinimalRandomAccessIndex(
collectionState: _collectionState,
position: newPosition, startIndex: startIndex, endIndex: endIndex)
}
public static func _failEarlyRangeCheck(
index: MinimalRandomAccessIndex,
bounds: Range<MinimalRandomAccessIndex>
) {
expectLE(bounds.startIndex.position, index.position)
expectGT(bounds.endIndex.position, index.position)
if MinimalRandomAccessIndex.trapOnRangeCheckFailure.value {
Int._failEarlyRangeCheck(
index.position,
bounds: bounds.startIndex.position..<bounds.endIndex.position)
}
}
public static func _failEarlyRangeCheck2(
rangeStart: MinimalRandomAccessIndex,
rangeEnd: MinimalRandomAccessIndex,
boundsStart: MinimalRandomAccessIndex,
boundsEnd: MinimalRandomAccessIndex
) {
let range = rangeStart..<rangeEnd
let bounds = boundsStart..<boundsEnd
expectLE(bounds.startIndex.position, range.startIndex.position)
expectGE(bounds.endIndex.position, range.startIndex.position)
expectLE(bounds.startIndex.position, range.endIndex.position)
expectGE(bounds.endIndex.position, range.endIndex.position)
if MinimalRandomAccessIndex.trapOnRangeCheckFailure.value {
Int._failEarlyRangeCheck2(
rangeStart.position,
rangeEnd: rangeEnd.position,
boundsStart: boundsStart.position,
boundsEnd: boundsEnd.position)
}
}
public let _collectionState: _CollectionState?
public let position: Int
public let startIndex: Int
public let endIndex: Int
public static var trapOnRangeCheckFailure = ResettableValue(true)
}
public func == (
lhs: MinimalRandomAccessIndex,
rhs: MinimalRandomAccessIndex
) -> Bool {
_expectCompatibleIndices(lhs, rhs)
return lhs.position == rhs.position
}
extension MinimalRandomAccessIndex : _MinimalIndexType {
public var _offset: Int {
return position - startIndex
}
}
//===----------------------------------------------------------------------===//
// Minimal***[Mutable]?Collection
//===----------------------------------------------------------------------===//
% for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]:
% for mutable in [ False, True ]:
// This comment is a workaround for <rdar://problem/18900352> gyb miscompiles nested loops
% Protocol = 'Strict%s%sCollectionType' % (traversal, 'Mutable' if mutable else '')
% Self = 'Minimal%s%sCollection' % (traversal, 'Mutable' if mutable else '')
% Index = 'Minimal%sIndex' % traversal
public protocol ${Protocol} : ${'MutableCollectionType' if mutable else 'CollectionType'} {
typealias Element
init(base: ${Self}<Element>)
% if mutable:
var base: ${Self}<Element> { get set }
% else:
var base: ${Self}<Element> { get }
% end
}
extension ${Protocol} {
public init<S : SequenceType where S.Generator.Element == Element>(
elements: S,
underestimatedCount: UnderestimateCountBehavior = .Value(0)
) {
self.init(base:
${Self}(elements: elements, underestimatedCount: underestimatedCount))
}
public func underestimateCount() -> Int {
return base.underestimateCount()
}
}
extension ${Protocol} where Generator : _MinimalGeneratorType {
public func generate() -> MinimalGenerator<Element> {
return base.generate()
}
}
extension ${Protocol} where Index : _MinimalIndexType {
public var startIndex: ${Index} {
return base.startIndex
}
public var endIndex: ${Index} {
return base.endIndex
}
public subscript(i: ${Index}) -> Element {
get {
_expectCompatibleIndices(self.startIndex, i)
return base[i]
}
% if mutable:
set {
_expectCompatibleIndices(self.startIndex, i)
base[i] = newValue
}
% end
}
}
/// A minimal implementation of `CollectionType` with extra checks.
public struct ${Self}<T> : ${'MutableCollectionType' if mutable else 'CollectionType'} {
public init<S : SequenceType where S.Generator.Element == T>(
elements: S,
underestimatedCount: UnderestimateCountBehavior = .Value(0)
) {
self._elements = Array(elements)
self._collectionState = _CollectionState(
newRootStateForElementCount: self._elements.count)
switch underestimatedCount {
case .Precise:
self.underestimatedCount = _elements.count
case .Half:
self.underestimatedCount = _elements.count / 2
case .Overestimate:
self.underestimatedCount = _elements.count * 3 + 5
case .Value(let count):
self.underestimatedCount = count
}
}
public func generate() -> MinimalGenerator<T> {
return MinimalGenerator(_elements)
}
public var startIndex: ${Index} {
return ${Index}(
collectionState: _collectionState,
position: 0,
startIndex: 0,
endIndex: _elements.endIndex)
}
public var endIndex: ${Index} {
return ${Index}(
collectionState: _collectionState,
position: _elements.endIndex,
startIndex: 0,
endIndex: _elements.endIndex)
}
public subscript(i: ${Index}) -> T {
get {
_expectCompatibleIndices(self.startIndex, i)
return _elements[i.position]
}
% if mutable:
set {
_expectCompatibleIndices(self.startIndex, i)
_elements[i.position] = newValue
}
% end
}
public func underestimateCount() -> Int {
return underestimatedCount
}
public var underestimatedCount: Int
internal var _elements: [T]
internal let _collectionState: _CollectionState
}
% end
% end
//===----------------------------------------------------------------------===//
// Minimal***RangeReplaceableCollectionType
//===----------------------------------------------------------------------===//
% for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]:
% Protocol = 'Strict%sRangeReplaceableCollectionType' % traversal
% Self = 'Minimal%sRangeReplaceableCollection' % traversal
% Index = 'Minimal%sIndex' % traversal
public protocol ${Protocol} : RangeReplaceableCollectionType {
typealias Element
init(base: ${Self}<Element>)
var base: ${Self}<Element> { get set }
}
extension ${Protocol} {
public mutating func replaceRange<
C: CollectionType where C.Generator.Element == Element
>(subRange: Range<${Self}<Element>.Index>,
with newElements: C) {
base.replaceRange(subRange, with: newElements)
}
public mutating func removeLast() -> Element {
return base.removeLast()
}
}
extension ${Protocol} where Generator : _MinimalGeneratorType {
public func generate() -> MinimalGenerator<Element> {
return base.generate()
}
}
extension ${Protocol} where Index : _MinimalIndexType {
public var startIndex: ${Index} {
return base.startIndex
}
public var endIndex: ${Index} {
return base.endIndex
}
public subscript(i: ${Index}) -> Element {
get {
_expectCompatibleIndices(advance(self.startIndex, i.position), i)
return base[i]
}
set {
_expectCompatibleIndices(advance(self.startIndex, i.position), i)
base[i] = newValue
}
}
}
/// A minimal implementation of `RangeReplaceableCollectionType` with extra
/// checks.
public struct ${Self}<T> : RangeReplaceableCollectionType {
/// Creates a collection with given contents, but a unique modification
/// history. No other instance has the same modification history.
public init<S : SequenceType where S.Generator.Element == T>(
elements: S,
underestimatedCount: UnderestimateCountBehavior = .Value(0)
) {
self.elements = Array(elements)
self._collectionState = _CollectionState(
newRootStateForElementCount: self.elements.count)
switch underestimatedCount {
case .Precise:
self.underestimatedCount = self.elements.count
case .Half:
self.underestimatedCount = self.elements.count / 2
case .Overestimate:
self.underestimatedCount = self.elements.count * 3 + 5
case .Value(let count):
self.underestimatedCount = count
}
}
public init() {
self.underestimatedCount = 0
self.elements = []
self._collectionState = _CollectionState(name: "\(self.dynamicType)", elementCount: 0)
}
public func generate() -> MinimalGenerator<T> {
return MinimalGenerator(elements)
}
public func underestimateCount() -> Int {
return underestimatedCount
}
public var startIndex: ${Index} {
return ${Index}(
collectionState: _collectionState,
position: 0,
startIndex: 0,
endIndex: elements.endIndex)
}
public var endIndex: ${Index} {
return ${Index}(
collectionState: _collectionState,
position: elements.endIndex,
startIndex: 0,
endIndex: elements.endIndex)
}
public subscript(i: ${Index}) -> T {
get {
_expectCompatibleIndices(advance(self.startIndex, i.position), i)
return elements[i.position]
}
set {
_expectCompatibleIndices(advance(self.startIndex, i.position), i)
elements[i.position] = newValue
}
}
public mutating func reserveCapacity(n: Int) {
_willMutate(.ReserveCapacity(capacity: n))
elements.reserveCapacity(n)
reservedCapacity = max(reservedCapacity, n)
}
public mutating func append(x: T) {
_willMutate(.Append)
elements.append(x)
}
public mutating func appendContentsOf<
S : SequenceType where S.Generator.Element == T
>(newElements: S) {
let oldCount = count
elements.appendContentsOf(newElements)
let newCount = count
_willMutate(.AppendContentsOf(count: newCount - oldCount))
}
public mutating func replaceRange<
C : CollectionType where C.Generator.Element == T
>(
subRange: Range<${Index}>, with newElements: C
) {
let oldCount = count
elements.replaceRange(
subRange.startIndex.position..<subRange.endIndex.position,
with: newElements)
let newCount = count
_willMutate(.ReplaceRange(
subRange: subRange.startIndex._offset..<subRange.endIndex._offset,
replacementCount: subRange.count + newCount - oldCount))
}
public mutating func insert(newElement: T, atIndex i: ${Index}) {
_willMutate(.Insert(atIndex: i._offset))
elements.insert(newElement, atIndex: i.position)
}
public mutating func insertContentsOf<
S : CollectionType where S.Generator.Element == T
>(newElements: S, at i: ${Index}) {
let oldCount = count
elements.insertContentsOf(newElements, at: i.position)
let newCount = count
if newCount - oldCount != 0 {
_willMutate(.InsertContentsOf(
atIndex: i._offset,
count: newCount - oldCount))
}
}
public mutating func removeAtIndex(i: ${Index}) -> T {
_willMutate(.RemoveAtIndex(index: i._offset))
return elements.removeAtIndex(i.position)
}
public mutating func removeLast() -> T {
_willMutate(.RemoveLast)
return elements.removeLast()
}
public mutating func removeRange(subRange: Range<${Index}>) {
if !subRange.isEmpty {
_willMutate(.RemoveRange(
subRange: subRange.startIndex._offset..<subRange.endIndex._offset))
}
elements.removeRange(
subRange.startIndex.position..<subRange.endIndex.position
)
}
public mutating func removeAll(keepCapacity keepCapacity: Bool = false) {
_willMutate(.RemoveAll(keepCapacity: keepCapacity))
// Ignore the value of `keepCapacity`.
elements.removeAll(keepCapacity: false)
}
internal mutating func _willMutate(operation: _CollectionOperation) {
_collectionState = _CollectionStateTransition(
previousState: _collectionState,
operation: operation)._nextState
}
public var underestimatedCount: Int
public var reservedCapacity: Int = 0
public var elements: [T]
internal var _collectionState: _CollectionState
}
% end
/// A type that does not conform to any protocols.
///
/// This type can be used to check that generic functions don't rely on any
/// conformances.
public struct OpaqueValue<Underlying> {
public var value: Underlying
public var identity: Int
public init(_ value: Underlying) {
self.value = value
self.identity = 0
}
public init(_ value: Underlying, identity: Int) {
self.value = value
self.identity = identity
}
}
/// A type that conforms only to `Equatable`.
///
/// This type can be used to check that generic functions don't rely on any
/// other conformances.
public struct MinimalEquatableValue : Equatable {
public static var timesEqualEqualWasCalled: Int = 0
public var value: Int
public var identity: Int
public init(_ value: Int) {
self.value = value
self.identity = 0
}
public init(_ value: Int, identity: Int) {
self.value = value
self.identity = identity
}
}
public func == (
lhs: MinimalEquatableValue,
rhs: MinimalEquatableValue
) -> Bool {
++MinimalEquatableValue.timesEqualEqualWasCalled
return lhs.value == rhs.value
}
% for kind in [ 'Value', 'Class' ]:
% Self = 'MinimalHashable%s' % kind
/// A type that conforms only to `Equatable` and `Hashable`.
///
/// This type can be used to check that generic functions don't rely on any
/// other conformances.
public struct ${Self} : Equatable, Hashable {
public static var timesEqualEqualWasCalled: Int = 0
public static var timesHashValueWasCalled: Int = 0
public var value: Int
public var identity: Int
public init(_ value: Int) {
self.value = value
self.identity = 0
}
public init(_ value: Int, identity: Int) {
self.value = value
self.identity = identity
}
public var hashValue: Int {
++${Self}.timesHashValueWasCalled
return value.hashValue
}
}
public func == (
lhs: ${Self},
rhs: ${Self}
) -> Bool {
++${Self}.timesEqualEqualWasCalled
return lhs.value == rhs.value
}
% end
/// A type that conforms only to `Equatable` and `Comparable`.
///
/// This type can be used to check that generic functions don't rely on any
/// other conformances.
public struct MinimalComparableValue : Equatable, Comparable {
public static var timesEqualEqualWasCalled = ResettableValue(0)
public static var timesLessWasCalled = ResettableValue(0)
public static var equalImpl =
ResettableValue<(Int, Int) -> Bool>({ $0 == $1 })
public static var lessImpl =
ResettableValue<(Int, Int) -> Bool>({ $0 < $1 })
public var value: Int
public var identity: Int
public init(_ value: Int) {
self.value = value
self.identity = 0
}
public init(_ value: Int, identity: Int) {
self.value = value
self.identity = identity
}
}
public func == (
lhs: MinimalComparableValue,
rhs: MinimalComparableValue
) -> Bool {
++MinimalComparableValue.timesEqualEqualWasCalled.value
return MinimalComparableValue.equalImpl.value(lhs.value, rhs.value)
}
public func < (
lhs: MinimalComparableValue,
rhs: MinimalComparableValue
) -> Bool {
++MinimalComparableValue.timesLessWasCalled.value
return MinimalComparableValue.lessImpl.value(lhs.value, rhs.value)
}
/// A Sequence that uses as many default implementations as
/// `SequenceType` can provide.
public struct DefaultedSequence<Element> : StrictSequenceType {
public let base: MinimalSequence<Element>
public init(base: MinimalSequence<Element>) {
self.base = base
}
}
% for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]:
/// A Collection that uses as many default implementations as
/// `CollectionType` can provide.
public struct Defaulted${traversal}Collection<Element>
: Strict${traversal}CollectionType {
public typealias Base = Minimal${traversal}Collection<Element>
public typealias Generator = MinimalGenerator<Element>
public typealias Index = Minimal${traversal}Index
public let base: Base
public init(base: Base) {
self.base = base
}
public init(_ array: [Element]) {
self.base = Base(elements: array)
}
public init(elements: [Element]) {
self.base = Base(elements: elements)
}
}
public struct Defaulted${traversal}MutableCollection<Element>
: Strict${traversal}MutableCollectionType {
public typealias Base = Minimal${traversal}MutableCollection<Element>
public typealias Generator = MinimalGenerator<Element>
public typealias Index = Minimal${traversal}Index
public var base: Base
public init(base: Base) {
self.base = base
}
public init(_ array: [Element]) {
self.base = Base(elements: array)
}
public init(elements: [Element]) {
self.base = Base(elements: elements)
}
}
public struct Defaulted${traversal}RangeReplaceableCollection<Element>
: Strict${traversal}RangeReplaceableCollectionType {
public typealias Base = Minimal${traversal}RangeReplaceableCollection<Element>
public typealias Generator = MinimalGenerator<Element>
public typealias Index = Minimal${traversal}Index
public var base: Base
public init() {
base = Base()
}
public init(base: Base) {
self.base = base
}
public init(_ array: [Element]) {
self.base = Base(elements: array)
}
public init(elements: [Element]) {
self.base = Base(elements: elements)
}
}
% end
// ${'Local Variables'}:
// eval: (read-only-mode 1)
// End: