blob: 33d1bc450a007dbf4ea6b8fc068944cddddb8c37 [file] [log] [blame]
//===--- ExistentialCollection.swift.gyb ----------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// RUN: %target-run-simple-swiftgyb
// REQUIRES: executable_test
%{
from gyb_stdlib_support import (
TRAVERSALS,
collectionForTraversal
)
}%
import StdlibUnittest
import StdlibCollectionUnittest
// Check that the generic parameter is called 'Element'.
protocol TestProtocol1 {}
extension AnyIterator where Element : TestProtocol1 {
var _elementIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
extension AnySequence where Element : TestProtocol1 {
var _elementIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
extension AnyCollection where Element : TestProtocol1 {
var _elementIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
extension AnyBidirectionalCollection where Element : TestProtocol1 {
var _elementIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
extension AnyRandomAccessCollection where Element : TestProtocol1 {
var _elementIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
func storesSameUnderlyingCollection<
L: _AnyCollectionProtocol, R: _AnyCollectionProtocol
>(_ lhs: L, _ rhs: R) -> Bool {
return lhs._boxID == rhs._boxID
}
var tests = TestSuite("ExistentialCollection")
tests.test("AnyIterator") {
func digits() -> AnyIterator<OpaqueValue<Int>> {
let integers: CountableRange = 0..<5
let lazyStrings = integers.lazy.map { OpaqueValue($0) }
// This is a really complicated type of no interest to our
// clients.
let iterator: LazyMapSequence<
CountableRange<Int>, OpaqueValue<Int>
>.Iterator = lazyStrings.makeIterator()
return AnyIterator(iterator)
}
expectEqual([0, 1, 2, 3, 4], Array(digits()).map { $0.value })
var x = 7
let iterator = AnyIterator<Int> {
if x >= 15 { return nil }
x += 1
return x-1
}
expectEqual([ 7, 8, 9, 10, 11, 12, 13, 14 ], Array(iterator))
}
tests.test("AnySequence.init(Sequence)") {
do {
let base = MinimalSequence<OpaqueValue<Int>>(elements: [])
var s = AnySequence(base)
expectType(AnySequence<OpaqueValue<Int>>.self, &s)
checkSequence([], s, resiliencyChecks: .none) { $0.value == $1.value }
}
do {
let intData = [ 1, 2, 3, 5, 8, 13, 21 ]
let data = intData.map(OpaqueValue.init)
let base = MinimalSequence(elements: data)
var s = AnySequence(base)
expectType(AnySequence<OpaqueValue<Int>>.self, &s)
checkSequence(data, s, resiliencyChecks: .none) { $0.value == $1.value }
}
}
tests.test("AnySequence.init(() -> Generator)") {
do {
var s = AnySequence {
return MinimalIterator<OpaqueValue<Int>>([])
}
expectType(AnySequence<OpaqueValue<Int>>.self, &s)
checkSequence([], s, resiliencyChecks: .none) { $0.value == $1.value }
}
do {
let intData = [ 1, 2, 3, 5, 8, 13, 21 ]
let data = intData.map(OpaqueValue.init)
var s = AnySequence {
return MinimalIterator(data)
}
expectType(AnySequence<OpaqueValue<Int>>.self, &s)
checkSequence(data, s, resiliencyChecks: .none) { $0.value == $1.value }
}
}
% for Traversal in ['Sequence'] + TRAVERSALS:
% if Traversal == 'Sequence':
% TestedType = 'AnySequence'
% LoggingWrapper = 'LoggingSequence'
% MinimalBase = 'MinimalSequence'
% else:
% TestedType = 'Any' + collectionForTraversal(Traversal)
% LoggingWrapper = 'Logging' + collectionForTraversal(Traversal)
% MinimalBase = 'Minimal' + collectionForTraversal(Traversal)
% end
tests.test("${TestedType}: dispatch to wrapped, SequenceLog") {
typealias Base = ${LoggingWrapper}<${MinimalBase}<OpaqueValue<Int>>>
typealias Log = SequenceLog
let base = Base(wrapping:
${MinimalBase}(elements: (0..<10).map(OpaqueValue.init)))
var s = ${TestedType}(base)
expectType(${TestedType}<OpaqueValue<Int>>.self, &s)
Log.makeIterator.expectIncrement(Base.self) {
_ = s.makeIterator()
}
Log.underestimatedCount.expectIncrement(Base.self) {
_ = s.underestimatedCount
}
Log._customContainsEquatableElement.expectIncrement(Base.self) {
_ = s._customContainsEquatableElement(OpaqueValue(42))
}
Log._copyToContiguousArray.expectIncrement(Base.self) {
_ = s._copyToContiguousArray()
}
do {
var result = Array(repeating: OpaqueValue(0), count: 10)
Log._copyContents.expectIncrement(Base.self) {
result.withUnsafeMutableBufferPointer {
_ = s._copyContents(initializing: $0)
}
}
}
}
% if Traversal != 'Sequence':
tests.test("${TestedType}: dispatch to wrapped, CollectionLog") {
typealias Base = ${LoggingWrapper}<${MinimalBase}<OpaqueValue<Int>>>
typealias Log = CollectionLog
let base = Base(wrapping:
${MinimalBase}(elements: (0..<10).map(OpaqueValue.init)))
var c = ${TestedType}(base)
expectType(${TestedType}<OpaqueValue<Int>>.self, &c)
do {
var i = c.startIndex
// `startIndex` is cached in the type erased wrapper, so first mutation
// makes a unique copy.
Log.successor.expectIncrement(Base.self) {
Log.formSuccessor.expectUnchanged(Base.self) {
c.formIndex(after: &i)
}
}
Log.successor.expectUnchanged(Base.self) {
Log.formSuccessor.expectIncrement(Base.self) {
c.formIndex(after: &i)
}
}
}
% if Traversal in ['Bidirectional', 'RandomAccess']:
do {
typealias Log = BidirectionalCollectionLog
var i = c.endIndex
// `startIndex` is cached in the type erased wrapper, so first mutation
// makes a unique copy.
Log.predecessor.expectIncrement(Base.self) {
Log.formPredecessor.expectUnchanged(Base.self) {
c.formIndex(before: &i)
}
}
Log.predecessor.expectUnchanged(Base.self) {
Log.formPredecessor.expectIncrement(Base.self) {
c.formIndex(before: &i)
}
}
}
% end
do {
let startIndex = c.startIndex
var badBounds = c.index(c.startIndex, offsetBy: 3)..<c.endIndex
Log.subscriptIndex.expectIncrement(Base.self) {
Log.subscriptRange.expectUnchanged(Base.self) {
_ = c[startIndex]
}
}
Log.subscriptIndex.expectUnchanged(Base.self) {
Log.subscriptRange.expectIncrement(Base.self) {
_ = c[startIndex..<startIndex]
}
}
Log._failEarlyRangeCheckIndex.expectUnchanged(Base.self) {
Log._failEarlyRangeCheckRange.expectUnchanged(Base.self) {
// Early range checks are not forwarded for performance reasons.
_ = c._failEarlyRangeCheck(startIndex, bounds: badBounds)
_ = c._failEarlyRangeCheck(startIndex..<startIndex, bounds: badBounds)
}
}
}
do {
var i = c.startIndex
Log.successor.expectIncrement(Base.self) {
Log.formSuccessor.expectUnchanged(Base.self) {
i = c.index(after: i)
}
}
Log.successor.expectUnchanged(Base.self) {
Log.formSuccessor.expectIncrement(Base.self) {
c.formIndex(after: &i)
}
}
var x = i
Log.successor.expectIncrement(Base.self) {
Log.formSuccessor.expectUnchanged(Base.self) {
i = c.index(after: i)
}
}
_blackHole(x)
}
% if Traversal in ['Bidirectional', 'RandomAccess']:
do {
typealias Log = BidirectionalCollectionLog
var i = c.endIndex
Log.predecessor.expectIncrement(Base.self) {
Log.formPredecessor.expectUnchanged(Base.self) {
i = c.index(before: i)
}
}
Log.predecessor.expectUnchanged(Base.self) {
Log.formPredecessor.expectIncrement(Base.self) {
c.formIndex(before: &i)
}
}
var x = i
Log.predecessor.expectIncrement(Base.self) {
Log.formPredecessor.expectUnchanged(Base.self) {
i = c.index(before: i)
}
}
_blackHole(x)
}
% end
}
% end
% end
tests.test("ForwardCollection") {
let a0: ContiguousArray = [1, 2, 3, 5, 8, 13, 21]
let fc0 = AnyCollection(a0)
let a1 = ContiguousArray(fc0)
expectEqual(a0, a1)
for e in a0 {
let i = fc0.firstIndex(of: e)
expectNotNil(i)
expectEqual(e, fc0[i!])
}
for i in fc0.indices {
expectNotEqual(fc0.endIndex, i)
expectEqual(1, fc0.indices.filter { $0 == i }.count)
}
}
tests.test("BidirectionalCollection") {
let a0: ContiguousArray = [1, 2, 3, 5, 8, 13, 21]
let fc0 = AnyCollection(a0.lazy.reversed())
let bc0_ = AnyBidirectionalCollection(fc0) // upgrade!
expectNotNil(bc0_)
let bc0 = bc0_!
expectTrue(storesSameUnderlyingCollection(fc0, bc0))
let fc1 = AnyCollection(a0.lazy.reversed()) // new collection
expectFalse(storesSameUnderlyingCollection(fc1, fc0))
let fc2 = AnyCollection(bc0) // downgrade
expectTrue(storesSameUnderlyingCollection(fc2, bc0))
let a1 = ContiguousArray(bc0.lazy.reversed())
expectEqual(a0, a1)
for e in a0 {
let i = bc0.firstIndex(of: e)
expectNotNil(i)
expectEqual(e, bc0[i!])
}
for i in bc0.indices {
expectNotEqual(bc0.endIndex, i)
expectEqual(1, bc0.indices.filter { $0 == i }.count)
}
// Can't upgrade a non-random-access collection to random access
let s0 = "Hello, Woyld"
let bc1 = AnyBidirectionalCollection(s0)
let fc3 = AnyCollection(bc1)
expectTrue(storesSameUnderlyingCollection(fc3, bc1))
expectNil(AnyRandomAccessCollection(bc1))
expectNil(AnyRandomAccessCollection(fc3))
}
tests.test("RandomAccessCollection") {
let a0: ContiguousArray = [1, 2, 3, 5, 8, 13, 21]
let fc0 = AnyCollection(a0.lazy.reversed())
let rc0_ = AnyRandomAccessCollection(fc0) // upgrade!
expectNotNil(rc0_)
let rc0 = rc0_!
expectTrue(storesSameUnderlyingCollection(rc0, fc0))
let bc1 = AnyBidirectionalCollection(rc0) // downgrade
expectTrue(storesSameUnderlyingCollection(bc1, rc0))
let fc1 = AnyBidirectionalCollection(rc0) // downgrade
expectTrue(storesSameUnderlyingCollection(fc1, rc0))
let a1 = ContiguousArray(rc0.lazy.reversed())
expectEqual(a0, a1)
for e in a0 {
let i = rc0.firstIndex(of: e)
expectNotNil(i)
expectEqual(e, rc0[i!])
}
for i in rc0.indices {
expectNotEqual(rc0.endIndex, i)
expectEqual(1, rc0.indices.filter { $0 == i }.count)
}
}
% for Traversal in TRAVERSALS:
% AnyCollection = 'Any' + collectionForTraversal(Traversal)
% Base = 'Minimal' + collectionForTraversal(Traversal)
do {
var AnyCollectionTests = TestSuite("${AnyCollection}")
func makeCollection(elements: [OpaqueValue<Int>])
-> ${AnyCollection}<OpaqueValue<Int>> {
let base = ${Base}(elements: elements)
return ${AnyCollection}(base)
}
func makeCollectionOfEquatable(elements: [MinimalEquatableValue])
-> ${AnyCollection}<MinimalEquatableValue> {
let base = ${Base}(elements: elements)
return ${AnyCollection}(base)
}
func makeCollectionOfComparable(elements: [MinimalComparableValue])
-> ${AnyCollection}<MinimalComparableValue> {
let base = ${Base}(elements: elements)
return ${AnyCollection}(base)
}
AnyCollectionTests.add${collectionForTraversal(Traversal)}Tests(
"tests.",
makeCollection: makeCollection,
wrapValue: identity,
extractValue: identity,
makeCollectionOfEquatable: makeCollectionOfEquatable,
wrapValueIntoEquatable: identityEq,
extractValueFromEquatable: identityEq,
resiliencyChecks: CollectionMisuseResiliencyChecks.all,
collectionIsBidirectional: ${'false' if Traversal == 'Forward' else 'true'}
)
}
% end
runAllTests()