mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
1426 lines
45 KiB
Swift
1426 lines
45 KiB
Swift
//===--- Lazy.swift - Tests for LazySequence and LazyCollection -----------===//
|
|
//
|
|
// 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
|
|
// REQUIRES: reflection
|
|
|
|
// With a non-optimized stdlib the test takes very long.
|
|
// REQUIRES: optimized_stdlib
|
|
|
|
import StdlibUnittest
|
|
import StdlibCollectionUnittest
|
|
|
|
% from gyb_stdlib_support import TRAVERSALS, collectionForTraversal
|
|
|
|
var LazyTestSuite = TestSuite("Lazy")
|
|
|
|
protocol TestProtocol1 {}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// repeatElement(), Repeated<Element>
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Check that the generic parameter is called 'Element'.
|
|
extension Repeated where Element : TestProtocol1 {
|
|
var _elementIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
LazyTestSuite.test("Repeated/AssociatedTypes") {
|
|
typealias Subject = Repeated<OpaqueValue<Int>>
|
|
expectRandomAccessCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: IndexingIterator<Subject>.self,
|
|
subSequenceType: Slice<Subject>.self,
|
|
indexType: Int.self,
|
|
indicesType: Range<Int>.self)
|
|
}
|
|
|
|
LazyTestSuite.test("repeatedValue()/TypeInference") {
|
|
var r = repeatElement(OpaqueValue(42), count: 42)
|
|
expectType(Repeated<OpaqueValue<Int>>.self, &r)
|
|
}
|
|
|
|
LazyTestSuite.test("repeatedValue()/NegativeCount") {
|
|
expectCrashLater()
|
|
_ = repeatElement(OpaqueValue(42), count: -1)
|
|
}
|
|
|
|
LazyTestSuite.test("Repeated")
|
|
.forEach(in: [ 0, 1, 3 ]) {
|
|
count in
|
|
|
|
let c = repeatElement(OpaqueValue(42), count: count)
|
|
expectEqual(0, c.startIndex)
|
|
expectEqual(count, c.endIndex)
|
|
expectEqual(count, c.count)
|
|
expectEqual(42, c.repeatedValue.value)
|
|
|
|
let expected = (0..<count).map { _ in OpaqueValue(42) }
|
|
checkRandomAccessCollection(expected, c) { $0.value == $1.value }
|
|
}
|
|
|
|
// FIXME: trap tests.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// IteratorOverOne
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Check that the generic parameter is called 'Element'.
|
|
// FIXME: this should be extension CollectionOfOne.Iterator, but this needs
|
|
// a fix to the compiler.
|
|
extension IteratorOverOne where Element : TestProtocol1 {
|
|
var _elementIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
LazyTestSuite.test("IteratorOverOne") {
|
|
checkIterator(
|
|
[] as Array<OpaqueValue<Int>>,
|
|
CollectionOfOne.Iterator(_elements: nil as Optional<OpaqueValue<Int>>))
|
|
{ $0.value == $1.value }
|
|
|
|
checkIterator(
|
|
[ OpaqueValue(42) ] as Array<OpaqueValue<Int>>,
|
|
CollectionOfOne.Iterator(_elements: OpaqueValue(42)))
|
|
{ $0.value == $1.value }
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// CollectionOfOne
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Check that the generic parameter is called 'Element'.
|
|
extension CollectionOfOne where Element : TestProtocol1 {
|
|
var _elementIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
LazyTestSuite.test("CollectionOfOne") {
|
|
let c = CollectionOfOne(OpaqueValue(42))
|
|
expectEqual(0, c.startIndex)
|
|
expectEqual(1, c.endIndex)
|
|
expectEqual(0..<1, c.indices)
|
|
|
|
checkRandomAccessCollection(
|
|
[ OpaqueValue(42) ], c) { $0.value == $1.value }
|
|
}
|
|
|
|
LazyTestSuite.test("CollectionOfOne/AssociatedTypes") {
|
|
typealias Subject = CollectionOfOne<OpaqueValue<Int>>
|
|
expectRandomAccessCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: Subject.Iterator.self,
|
|
subSequenceType: Slice<Subject>.self,
|
|
indexType: Int.self,
|
|
indicesType: Range<Int>.self)
|
|
}
|
|
|
|
let collectionOfOneIndexTests: [(String,(inout CollectionOfOne<OpaqueValue<Int>>,Int)->Void,[Int])] = [
|
|
("index(after:)", { _ = $0.index(after: $1) }, [-2, -1, 1, 2]),
|
|
("index(before:)", { _ = $0.index(before: $1) }, [-1, 0, 2]),
|
|
("subscript(Index)/Get", { _ = $0[$1] }, [-2, -1, 1, 2]),
|
|
("subscript(Index)/Set", { $0[$1] = OpaqueValue(42) }, [-2, -1, 1, 2]),
|
|
]
|
|
for (name,operation,indices) in collectionOfOneIndexTests {
|
|
LazyTestSuite.test("CollectionOfOne/\(name)")
|
|
.forEach(in: indices) { i in
|
|
var c = CollectionOfOne<OpaqueValue<Int>>(OpaqueValue(42))
|
|
expectCrashLater()
|
|
operation(&c,i)
|
|
}
|
|
}
|
|
|
|
LazyTestSuite.test("CollectionOfOne/index(after:), index(before:)") {
|
|
let c = CollectionOfOne<OpaqueValue<Int>>(OpaqueValue(42))
|
|
expectEqual(1, c.index(after: 0))
|
|
expectEqual(0, c.index(before: 1))
|
|
}
|
|
|
|
LazyTestSuite.test("CollectionOfOne/subscript(Index)/Get/Set/NoTrap") {
|
|
var c = CollectionOfOne<OpaqueValue<Int>>(OpaqueValue(42))
|
|
c[0] = OpaqueValue(4242)
|
|
expectEqual(4242, c[0].value)
|
|
expectEqualSequence([OpaqueValue(4242)], c) { $0.value == $1.value }
|
|
}
|
|
|
|
let collectionOfOneInvalidRanges = [-1 ..< -1, -1..<0, -1..<1, 1..<2, 2..<2]
|
|
LazyTestSuite.test("CollectionOfOne/subscript(Range<Index>)/Get/Trap")
|
|
.forEach(in: collectionOfOneInvalidRanges) { r in
|
|
let c = CollectionOfOne<OpaqueValue<Int>>(OpaqueValue(42))
|
|
expectCrashLater()
|
|
_ = c[r]
|
|
}
|
|
|
|
LazyTestSuite.test("CollectionOfOne/subscript(Range<Index>)/Set/Trap")
|
|
.forEach(in: collectionOfOneInvalidRanges) { r in
|
|
var c = CollectionOfOne<OpaqueValue<Int>>(OpaqueValue(42))
|
|
let slice = r.count == 0 ? c[0..<0] : c[0..<1]
|
|
expectCrashLater()
|
|
c[r] = slice
|
|
}
|
|
|
|
LazyTestSuite.test("CollectionOfOne/subscript(Range<Index>)/Set/DifferentLength/Trap")
|
|
.forEach(in: [ 0..<0, 0..<1, 1..<1 ] as [Range<Int>]) {
|
|
r in
|
|
var c = CollectionOfOne<OpaqueValue<Int>>(OpaqueValue(42))
|
|
let slice = r.count == 0 ? c[0..<1] : c[0..<0]
|
|
expectCrashLater()
|
|
c[r] = slice
|
|
}
|
|
|
|
LazyTestSuite.test("CollectionOfOne/subscript(Range<Index>)/Get/Set/Empty/NoTrap") {
|
|
var c = CollectionOfOne<OpaqueValue<Int>>(OpaqueValue(42))
|
|
let slice0 = c[0..<0]
|
|
let slice1 = c[1..<1]
|
|
checkRandomAccessCollection([], slice0) { $0.value == $1.value }
|
|
checkRandomAccessCollection([], slice1) { $0.value == $1.value }
|
|
c[0..<0] = slice0
|
|
c[0..<0] = slice1
|
|
c[1..<1] = slice0
|
|
c[1..<1] = slice1
|
|
expectEqualSequence([OpaqueValue(42)], c) { $0.value == $1.value }
|
|
}
|
|
|
|
LazyTestSuite.test("CollectionOfOne/{CustomDebugStringConvertible,CustomReflectable}") {
|
|
let c = CollectionOfOne(CustomPrintableValue(42))
|
|
expectPrinted("CollectionOfOne((value: 42).debugDescription)", c)
|
|
expectDebugPrinted("CollectionOfOne((value: 42).debugDescription)", c)
|
|
expectDumped(
|
|
"▿ CollectionOfOne((value: 42).debugDescription)\n" +
|
|
" ▿ element: (value: 42).debugDescription\n" +
|
|
" - value: 42\n" +
|
|
" - identity: 0\n",
|
|
c)
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// EmptyCollection
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Check that the generic parameter is called 'Element'.
|
|
extension EmptyCollection where Element : TestProtocol1 {
|
|
var _elementIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
LazyTestSuite.test("EmptyCollection") {
|
|
let c = EmptyCollection<OpaqueValue<Int>>()
|
|
expectEqual(0, c.startIndex)
|
|
expectEqual(0, c.endIndex)
|
|
expectEqual(0..<0, c.indices)
|
|
|
|
checkRandomAccessCollection([], c) { $0.value == $1.value }
|
|
}
|
|
|
|
LazyTestSuite.test("EmptyCollection/CustomReflectable") {
|
|
let c = EmptyCollection<OpaqueValue<Int>>()
|
|
expectPrinted("EmptyCollection<OpaqueValue<Int>>()", c)
|
|
expectDebugPrinted("Swift.EmptyCollection<StdlibUnittest.OpaqueValue<Swift.Int>>()", c)
|
|
expectDumped(
|
|
"- Swift.EmptyCollection<StdlibUnittest.OpaqueValue<Swift.Int>>\n",
|
|
c)
|
|
}
|
|
|
|
LazyTestSuite.test("EmptyCollection/Equatable") {
|
|
let instances = [ EmptyCollection<OpaqueValue<Int>>() ]
|
|
checkEquatable(instances, oracle: { $0 == $1 })
|
|
}
|
|
|
|
LazyTestSuite.test("EmptyCollection/AssociatedTypes") {
|
|
typealias Subject = EmptyCollection<OpaqueValue<Int>>
|
|
expectRandomAccessCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: EmptyCollection<OpaqueValue<Int>>.Iterator.self,
|
|
subSequenceType: Subject.self,
|
|
indexType: Int.self,
|
|
indicesType: Range<Int>.self)
|
|
}
|
|
|
|
let emptyCollectionIndexTests: [(String,(inout EmptyCollection<OpaqueValue<Int>>,Int)->Void)] = [
|
|
("index(after:)", { _ = $0.index(after: $1) }),
|
|
("index(before:)", { _ = $0.index(before: $1) }),
|
|
("subscript(Index)/Get", { _ = $0[$1] }),
|
|
("subscript(Index)/Set", { $0[$1] = OpaqueValue(42) }),
|
|
]
|
|
for (name,operation) in emptyCollectionIndexTests {
|
|
LazyTestSuite.test("EmptyCollection/\(name)")
|
|
.forEach(in: [-1, 0, 1]) { i in
|
|
var c = EmptyCollection<OpaqueValue<Int>>()
|
|
expectCrashLater()
|
|
operation(&c,i)
|
|
}
|
|
}
|
|
|
|
% for (name, operation) in [
|
|
% ('subscript(Range<Index>)/Get', '_ = c[r]'),
|
|
% ('subscript(Range<Index>)/Set', 'c[r] = c'),
|
|
% ]:
|
|
LazyTestSuite.test("EmptyCollection/${name}/Trap")
|
|
.forEach(in: [-1 ..< -1, -1..<0, -1..<1, 0..<1, 1..<1] as [Range<Int>]) {
|
|
r in
|
|
var c = EmptyCollection<OpaqueValue<Int>>()
|
|
// Access is guarded by a _debugPrecondition in EmptyCollection
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
${operation}
|
|
}
|
|
|
|
LazyTestSuite.test("EmptyCollection/${name}/NoTrap") {
|
|
var c = EmptyCollection<OpaqueValue<Int>>()
|
|
let r: Range<Int> = 0..<0
|
|
${operation}
|
|
expectEqualSequence([], c[0..<0]) { $0.value == $1.value }
|
|
}
|
|
% end
|
|
|
|
LazyTestSuite.test("EmptyCollection/index(_:offsetBy:)/Trap")
|
|
.forEach(in: [
|
|
(-1, -1), (-1, 0), (-1, 1),
|
|
(0, 1), (0, -1),
|
|
(1, -1), (1, 0), (1, 1),
|
|
]) {
|
|
(i, offset) in
|
|
let c = EmptyCollection<OpaqueValue<Int>>()
|
|
// Access is guarded by a _debugPrecondition in EmptyCollection
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
_ = c.index(i, offsetBy: offset)
|
|
}
|
|
|
|
LazyTestSuite.test("EmptyCollection/index(_:offsetBy:)/NoTrap") {
|
|
let c = EmptyCollection<OpaqueValue<Int>>()
|
|
expectEqual(c.startIndex, c.index(c.startIndex, offsetBy: 0))
|
|
}
|
|
|
|
LazyTestSuite.test("EmptyCollection/index(_:offsetBy:limitedBy:)/Trap")
|
|
.forEach(in: [
|
|
(-1, 0, 0), (-1, 1, 0),
|
|
(0, 0, -1), (0, 0, 1),
|
|
(1, -1, 0), (1, 0, 0), (1, 0, 1),
|
|
]) {
|
|
(i, offset, limit) in
|
|
let c = EmptyCollection<OpaqueValue<Int>>()
|
|
// Access is guarded by a _debugPrecondition in EmptyCollection
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
_ = c.index(i, offsetBy: offset, limitedBy: limit)
|
|
}
|
|
|
|
LazyTestSuite.test("EmptyCollection/index(_:offsetBy:limitedBy:)/NoTrap")
|
|
.forEach(in: [
|
|
-10, -1, 0, 1, 10,
|
|
]) {
|
|
offset in
|
|
let c = EmptyCollection<OpaqueValue<Int>>()
|
|
let result =
|
|
c.index(c.startIndex, offsetBy: offset, limitedBy: c.startIndex)
|
|
if offset == 0 {
|
|
expectEqual(c.startIndex, result)
|
|
} else {
|
|
expectNil(result)
|
|
}
|
|
}
|
|
|
|
LazyTestSuite.test("EmptyCollection/distance(from:to:)/Trap")
|
|
.forEach(in: [
|
|
(-1, -1), (-1, 0), (-1, 1),
|
|
(0, 1), (0, -1),
|
|
(1, -1), (1, 0), (1, 1),
|
|
]) {
|
|
(start, end) in
|
|
let c = EmptyCollection<OpaqueValue<Int>>()
|
|
// Access is guarded by a _debugPrecondition in EmptyCollection
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
_ = c.distance(from: start, to: end)
|
|
}
|
|
|
|
LazyTestSuite.test("EmptyCollection/distance(from:to:)/NoTrap") {
|
|
let c = EmptyCollection<OpaqueValue<Int>>()
|
|
expectEqual(0, c.distance(from: 0, to: 0))
|
|
}
|
|
|
|
LazyTestSuite.test("EmptyCollection/_failEarlyRangeCheck/NoTrap") {
|
|
let c = EmptyCollection<OpaqueValue<Int>>()
|
|
c._failEarlyRangeCheck(0, bounds: 0..<0)
|
|
c._failEarlyRangeCheck(0..<0, bounds: 0..<0)
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// EmptyIterator
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Check that the generic parameter is called 'Element'.
|
|
extension EmptyIterator where Element : TestProtocol1 {
|
|
var _elementIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
LazyTestSuite.test("EmptyIterator") {
|
|
checkIterator(
|
|
[] as Array<OpaqueValue<Int>>,
|
|
EmptyCollection<OpaqueValue<Int>>.Iterator())
|
|
{ $0.value == $1.value }
|
|
}
|
|
|
|
// FIXME: trap tests.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// lazy
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
LazyTestSuite.test("isEmpty") {
|
|
expectTrue((0..<0).lazy.isEmpty)
|
|
expectFalse((0...0).lazy.isEmpty)
|
|
}
|
|
|
|
LazyTestSuite.test("first") {
|
|
expectEqual(7, (7..<42).lazy.first)
|
|
}
|
|
|
|
LazyTestSuite.test("first empty") {
|
|
expectNil((7..<7).lazy.first)
|
|
}
|
|
|
|
LazyTestSuite.test("last") {
|
|
expectEqual(41, (7..<42).lazy.last)
|
|
}
|
|
|
|
LazyTestSuite.test("last empty") {
|
|
expectNil((7..<7).lazy.last)
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// LazySequence
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Check that the generic parameter is called 'Base'.
|
|
extension LazySequence where Base : TestProtocol1 {
|
|
var _baseIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
LazyTestSuite.test("LazySequence<Sequence>/underestimatedCount") {
|
|
let s = MinimalSequence(
|
|
elements: [ 0, 30, 10, 90 ].map(OpaqueValue.init),
|
|
underestimatedCount: .value(42))
|
|
var lazySeq = s.lazy
|
|
expectType(LazySequence<MinimalSequence<OpaqueValue<Int>>>.self, &lazySeq)
|
|
expectEqual(42, lazySeq.underestimatedCount)
|
|
}
|
|
|
|
% for Traversal in TRAVERSALS:
|
|
% TraversalCollection = collectionForTraversal(Traversal)
|
|
|
|
LazyTestSuite.test("LazySequence<${TraversalCollection}>/underestimatedCount") {
|
|
let s = Minimal${TraversalCollection}(
|
|
elements: [ 0, 30, 10, 90 ].map(OpaqueValue.init),
|
|
underestimatedCount: .value(42))
|
|
var lazySeq = s.lazy
|
|
expectType(
|
|
LazyCollection<
|
|
Minimal${TraversalCollection}<OpaqueValue<Int>>
|
|
>.self,
|
|
&lazySeq)
|
|
expectEqual(42, lazySeq.underestimatedCount)
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// MapSequence
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
LazyTestSuite.test("MapSequence<Sequence>/underestimatedCount") {
|
|
let s = MinimalSequence(
|
|
elements: [ 0, 30, 10, 90 ].map(OpaqueValue.init),
|
|
underestimatedCount: .value(42))
|
|
var lazyMap = s.lazy.map { OpaqueValue(Int32($0.value)) }
|
|
expectType(
|
|
LazyMapSequence<MinimalSequence<OpaqueValue<Int>>, OpaqueValue<Int32>>.self,
|
|
&lazyMap)
|
|
expectEqual(42, lazyMap.underestimatedCount)
|
|
}
|
|
|
|
struct SequenceWithCustomUnderestimatedCount : Sequence {
|
|
init(_ data: [Int]) {
|
|
self._data = MinimalSequence(elements: data.map(OpaqueValue.init))
|
|
}
|
|
|
|
func makeIterator() -> MinimalSequence<OpaqueValue<Int>>.Iterator {
|
|
return _data.makeIterator()
|
|
}
|
|
|
|
var underestimatedCount: Int {
|
|
SequenceWithCustomUnderestimatedCount.timesUnderestimatedCountWasCalled += 1
|
|
return _data.underestimatedCount
|
|
}
|
|
|
|
static var timesUnderestimatedCountWasCalled: Int = 0
|
|
|
|
let _data: MinimalSequence<OpaqueValue<Int>>
|
|
}
|
|
|
|
LazyTestSuite.test("LazySequence.array") {
|
|
SequenceWithCustomUnderestimatedCount.timesUnderestimatedCountWasCalled = 0
|
|
|
|
let base = SequenceWithCustomUnderestimatedCount([ 0, 30, 10, 90 ])
|
|
|
|
expectEqual([ 0, 30, 10, 90 ], base.lazy.map { $0.value })
|
|
|
|
// Lazy sequences should use underestimated count to preallocate array
|
|
// storage.
|
|
expectEqual(1, SequenceWithCustomUnderestimatedCount.timesUnderestimatedCountWasCalled)
|
|
|
|
expectEqualSequence(
|
|
[], Array(base).map { $0.value }, "sequence should be consumed")
|
|
}
|
|
|
|
% for Traversal in TRAVERSALS:
|
|
% TraversalCollection = collectionForTraversal(Traversal)
|
|
|
|
LazyTestSuite.test("MapCollection<${TraversalCollection}>/underestimatedCount") {
|
|
let s = Minimal${TraversalCollection}(
|
|
elements: [ 0, 30, 10, 90 ].map(OpaqueValue.init),
|
|
underestimatedCount: .value(42))
|
|
var lazyMap = s.lazy.map {
|
|
(input: OpaqueValue<Int>) -> OpaqueValue<Int32> in
|
|
OpaqueValue(Int32(input.value))
|
|
}
|
|
expectType(
|
|
LazyMapCollection<
|
|
Minimal${TraversalCollection}<OpaqueValue<Int>>, OpaqueValue<Int32>
|
|
>.self,
|
|
&lazyMap)
|
|
expectEqual(42, lazyMap.underestimatedCount)
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// LazyCollection
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Check that the generic parameter is called 'Base'.
|
|
extension LazyCollection where Base : TestProtocol1 {
|
|
var _baseIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
%for (Traversal, ReversedType) in [
|
|
% ('Forward', None),
|
|
% ('Bidirectional', 'ReversedCollection'),
|
|
% ('RandomAccess', 'ReversedCollection')
|
|
%]:
|
|
% TraversalCollection = collectionForTraversal(Traversal)
|
|
|
|
LazyTestSuite.test("Lazy${TraversalCollection}.array") {
|
|
let base = Minimal${TraversalCollection}(
|
|
elements: [ 0, 30, 10, 90 ], underestimatedCount: .value(42))
|
|
let arrayFromLazy = Array(base.lazy)
|
|
|
|
expectEqual([ 0, 30, 10, 90 ], arrayFromLazy)
|
|
|
|
// Lazy collections should not use underestimated count to preallocate array
|
|
// storage, since they have access to real count instead.
|
|
expectLE(4, arrayFromLazy.capacity)
|
|
expectGE(40, arrayFromLazy.capacity)
|
|
}
|
|
|
|
% if ReversedType is not None:
|
|
|
|
LazyTestSuite.test("Lazy${TraversalCollection}.reversed") {
|
|
let base = Minimal${TraversalCollection}(
|
|
elements: [ 0, 30, 10, 90 ].map(OpaqueValue.init),
|
|
underestimatedCount: .value(42))
|
|
var reversed = base.lazy.reversed()
|
|
expectType(
|
|
${ReversedType}<LazyCollection
|
|
<Minimal${TraversalCollection}<OpaqueValue<Int>>>
|
|
>.self, &reversed)
|
|
|
|
let expected: [OpaqueValue<Int>] = [ 90, 10, 30, 0 ].map(OpaqueValue.init)
|
|
check${Traversal}Collection(expected, reversed) { $0.value == $1.value }
|
|
|
|
var reversedTwice = reversed.reversed()
|
|
expectType(
|
|
${ReversedType}<${ReversedType}<LazyCollection<
|
|
Minimal${TraversalCollection}<OpaqueValue<Int>>
|
|
>>>.self, &reversedTwice)
|
|
|
|
check${Traversal}Collection(
|
|
[ 0, 30, 10, 90 ].map(OpaqueValue.init) as [OpaqueValue<Int>],
|
|
reversedTwice) { $0.value == $1.value }
|
|
}
|
|
|
|
% end
|
|
|
|
%end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// ReversedCollection
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Check that the generic parameter is called 'Base'.
|
|
extension ReversedCollection where Base : TestProtocol1 {
|
|
var _baseIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// ReversedIndex
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Check that the generic parameter is called 'Base'.
|
|
extension ReversedCollection.Index where Base : TestProtocol1 {
|
|
var _baseIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// RandomAccessReversedCollection
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Check that the generic parameter is called 'Base'.
|
|
extension ReversedCollection
|
|
where Base : TestProtocol1, Base : RandomAccessCollection {
|
|
var _baseIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// ReversedIndex for RandomAccessCollections
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Check that the generic parameter is called 'Base'.
|
|
extension ReversedCollection.Index
|
|
where Base : TestProtocol1, Base : RandomAccessCollection {
|
|
var _baseIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
var tests = TestSuite("NewLazy")
|
|
|
|
tests.test("LazySequence/Sequence") {
|
|
let expected = (0..<100).map(OpaqueValue.init)
|
|
var actual = MinimalSequence(elements: expected).lazy
|
|
|
|
expectType(
|
|
LazySequence<MinimalSequence<OpaqueValue<Int>>>.self, &actual)
|
|
|
|
// Asking for .lazy again doesn't re-wrap the type
|
|
var again = actual.lazy
|
|
expectType(
|
|
LazySequence<MinimalSequence<OpaqueValue<Int>>>.self, &again)
|
|
|
|
var elements = actual.elements
|
|
|
|
// Expect .elements to strip a lazy wrapper
|
|
expectType(MinimalSequence<OpaqueValue<Int>>.self, &elements)
|
|
|
|
checkSequence(expected, actual, resiliencyChecks: .none) {
|
|
$0.value == $1.value
|
|
}
|
|
}
|
|
|
|
func expectSequencePassthrough<
|
|
S : LazySequenceProtocol,
|
|
Base : Sequence
|
|
>(_ s: S, base: Base, arbitraryElement: S.Iterator.Element, count: Int)
|
|
where Base : LoggingType,
|
|
Base.Iterator.Element == S.Iterator.Element {
|
|
let baseType = type(of: base)
|
|
|
|
SequenceLog.makeIterator.expectIncrement(baseType) { _ = s.makeIterator() }
|
|
SequenceLog.underestimatedCount.expectIncrement(baseType) {
|
|
_ = s.underestimatedCount
|
|
}
|
|
SequenceLog._customContainsEquatableElement.expectIncrement(baseType) {
|
|
_ = s._customContainsEquatableElement(arbitraryElement)
|
|
}
|
|
SequenceLog._copyToContiguousArray.expectIncrement(baseType) {
|
|
_ = s._copyToContiguousArray()
|
|
}
|
|
|
|
SequenceLog._copyContents.expectIncrement(baseType) { () -> Void in
|
|
let ptr = UnsafeMutablePointer<S.Iterator.Element>.allocate(capacity: count)
|
|
let buf = UnsafeMutableBufferPointer(start: ptr, count: count)
|
|
var (remainders,writtenUpTo) = s._copyContents(initializing: buf)
|
|
expectTrue(remainders.next() == nil,
|
|
"_copyContents returned unwritten elements")
|
|
expectTrue(writtenUpTo == buf.endIndex,
|
|
"_copyContents failed to use entire buffer")
|
|
ptr.deinitialize(count: count)
|
|
ptr.deallocate()
|
|
}
|
|
}
|
|
|
|
tests.test("LazySequence/Passthrough") {
|
|
// Test that operations that might be optimized are passed
|
|
// through to the underlying sequence.
|
|
let a = (0..<100).map(OpaqueValue.init)
|
|
let base = LoggingSequence(wrapping: a)
|
|
|
|
expectSequencePassthrough(
|
|
base.lazy,
|
|
base: base, arbitraryElement: OpaqueValue(0), count: a.count)
|
|
}
|
|
|
|
% for Traversal in TRAVERSALS:
|
|
% TraversalCollection = collectionForTraversal(Traversal)
|
|
|
|
tests.test("Lazy${TraversalCollection}/Collection") {
|
|
let expected = (0..<100).map(OpaqueValue.init)
|
|
let base = Minimal${TraversalCollection}(elements: expected)
|
|
var actual = base.lazy
|
|
|
|
expectType(LazyCollection<
|
|
Minimal${TraversalCollection}<OpaqueValue<Int>>
|
|
>.self, &actual)
|
|
|
|
// Asking for .lazy again doesn't re-wrap the type
|
|
var again = actual.lazy
|
|
expectType(LazyCollection<
|
|
Minimal${TraversalCollection}<OpaqueValue<Int>>
|
|
>.self, &again)
|
|
|
|
checkOneLevelOf${Traversal}Collection(
|
|
expected, base.lazy, resiliencyChecks: .none
|
|
) { $0.value == $1.value }
|
|
|
|
var elements = base.lazy.elements
|
|
expectType(Minimal${TraversalCollection}<OpaqueValue<Int>>.self, &elements)
|
|
}
|
|
|
|
% end
|
|
|
|
tests.test("LazyCollection/Passthrough") {
|
|
let expected = (0..<100).map(OpaqueValue.init)
|
|
let base = LoggingCollection(wrapping: expected)
|
|
|
|
expectSequencePassthrough(
|
|
base.lazy,
|
|
base: base.lazy.elements,
|
|
arbitraryElement: OpaqueValue(0),
|
|
count: Int(expected.count))
|
|
|
|
let s = base.lazy
|
|
let baseType = type(of: base)
|
|
let startIndex = CollectionLog.startIndex.expectIncrement(baseType) {
|
|
s.startIndex
|
|
}
|
|
|
|
let endIndex = CollectionLog.endIndex.expectIncrement(baseType) {
|
|
s.endIndex
|
|
}
|
|
|
|
CollectionLog.subscriptIndex.expectIncrement(baseType) { _ = s[startIndex] }
|
|
CollectionLog.subscriptRange.expectUnchanged(baseType) {
|
|
_ = s[startIndex..<endIndex]
|
|
}
|
|
CollectionLog.isEmpty.expectIncrement(baseType) { _ = s.isEmpty }
|
|
CollectionLog.count.expectIncrement(baseType) { _ = s.count }
|
|
CollectionLog._customIndexOfEquatableElement.expectIncrement(baseType) {
|
|
_ = s._customIndexOfEquatableElement(OpaqueValue(0))
|
|
}
|
|
}
|
|
|
|
//===--- Map --------------------------------------------------------------===//
|
|
|
|
tests.test("LazyMapSequence") {
|
|
let base = MinimalSequence(
|
|
elements: [2, 3, 5, 7, 11].map(OpaqueValue.init)).lazy
|
|
|
|
var calls = 0
|
|
var mapped = base.map {
|
|
(x: OpaqueValue<Int>) -> OpaqueValue<Double> in
|
|
calls += 1
|
|
return OpaqueValue(Double(x.value) / 2.0)
|
|
}
|
|
|
|
expectEqual(0, calls)
|
|
|
|
expectType(
|
|
LazyMapSequence<
|
|
MinimalSequence<OpaqueValue<Int>>,
|
|
OpaqueValue<Double>>.self,
|
|
&mapped)
|
|
|
|
let expected = [ 1.0, 1.5, 2.5, 3.5, 5.5 ].map(OpaqueValue.init)
|
|
|
|
checkSequence(expected, mapped, resiliencyChecks: .none) {
|
|
$0.value == $1.value
|
|
}
|
|
|
|
expectEqual(expected.count, calls)
|
|
}
|
|
|
|
tests.test("MapSequence/Passthrough") {
|
|
let expected = (0..<100).map(OpaqueValue.init)
|
|
let base = LoggingSequence(wrapping: expected)
|
|
let mapped = base.lazy.map { OpaqueValue(Double($0.value) / 2.0) }
|
|
CollectionLog.underestimatedCount.expectIncrement(type(of: base)) {
|
|
_ = mapped.underestimatedCount
|
|
}
|
|
// Not exactly passthrough because we wrap the result
|
|
CollectionLog.makeIterator.expectIncrement(type(of: base)) {
|
|
_ = mapped.makeIterator()
|
|
}
|
|
}
|
|
|
|
% for Traversal in TRAVERSALS:
|
|
% TraversalCollection = collectionForTraversal(Traversal)
|
|
|
|
tests.test("LazyMap${TraversalCollection}/Collection") {
|
|
let base = Minimal${TraversalCollection}(
|
|
elements: [2, 3, 5, 7, 11].map(OpaqueValue.init)).lazy
|
|
|
|
var calls = 0
|
|
var mapped = base.map {
|
|
(x: OpaqueValue<Int>) -> OpaqueValue<Double> in
|
|
calls += 1
|
|
return OpaqueValue(Double(x.value) / 2.0)
|
|
}
|
|
expectEqual(0, calls)
|
|
|
|
expectType(
|
|
LazyMapCollection<
|
|
Minimal${TraversalCollection}<OpaqueValue<Int>>,
|
|
OpaqueValue<Double>>.self,
|
|
&mapped)
|
|
|
|
let expected = [ 1.0, 1.5, 2.5, 3.5, 5.5 ].map(OpaqueValue.init)
|
|
|
|
check${Traversal}Collection(expected, mapped, resiliencyChecks: .none) {
|
|
$0.value == $1.value
|
|
}
|
|
|
|
// check${Traversal}Collection makes multiple passes over the input,
|
|
// so we test that each element was transformed *at least* once.
|
|
expectLE(expected.count, calls)
|
|
}
|
|
|
|
%end
|
|
|
|
tests.test("LazyMapCollection/Passthrough") {
|
|
let expected = (0..<100).map(OpaqueValue.init)
|
|
let base = LoggingCollection(wrapping: expected)
|
|
let mapped = base.lazy.map { OpaqueValue(Double($0.value) / 2.0) }
|
|
|
|
let startIndex = CollectionLog.startIndex.expectIncrement(type(of: base)) {
|
|
mapped.startIndex
|
|
}
|
|
_ = CollectionLog.endIndex.expectIncrement(type(of: base)) {
|
|
mapped.endIndex
|
|
}
|
|
// Not exactly passthrough, because mapping transforms the result
|
|
CollectionLog.subscriptIndex.expectIncrement(type(of: base)) {
|
|
_ = mapped[startIndex]
|
|
}
|
|
CollectionLog.isEmpty.expectIncrement(type(of: base)) {
|
|
_ = mapped.isEmpty
|
|
}
|
|
CollectionLog.underestimatedCount.expectIncrement(type(of: base)) {
|
|
_ = mapped.underestimatedCount
|
|
}
|
|
// Not exactly passthrough because we wrap the result
|
|
CollectionLog.makeIterator.expectIncrement(type(of: base)) {
|
|
_ = mapped.makeIterator()
|
|
}
|
|
}
|
|
|
|
tests.test("LazyMapSequence/AssociatedTypes") {
|
|
typealias Base = MinimalSequence<OpaqueValue<Int>>
|
|
typealias Subject = LazyMapSequence<Base, OpaqueValue<Int32>>
|
|
expectSequenceAssociatedTypes(
|
|
sequenceType: Subject.self,
|
|
iteratorType: LazyMapSequence<Base, OpaqueValue<Int32>>.Iterator.self)
|
|
}
|
|
|
|
tests.test("LazyMapCollection/AssociatedTypes") {
|
|
typealias Base = MinimalCollection<OpaqueValue<Int>>
|
|
typealias Subject = LazyMapCollection<Base, OpaqueValue<Int32>>
|
|
expectCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: LazyMapCollection<Base, OpaqueValue<Int32>>.Iterator.self,
|
|
subSequenceType: LazyMapCollection<Base.SubSequence, OpaqueValue<Int32>>.self,
|
|
indexType: Base.Index.self,
|
|
indicesType: Base.Indices.self)
|
|
}
|
|
|
|
tests.test("LazyMapBidirectionalCollection/AssociatedTypes") {
|
|
typealias Base = MinimalBidirectionalCollection<OpaqueValue<Int>>
|
|
typealias Subject = LazyMapCollection<Base, OpaqueValue<Int32>>
|
|
expectBidirectionalCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: LazyMapCollection<Base, OpaqueValue<Int32>>.Iterator.self,
|
|
subSequenceType: LazyMapCollection<Base.SubSequence, OpaqueValue<Int32>>.self,
|
|
indexType: Base.Index.self,
|
|
indicesType: Base.Indices.self)
|
|
}
|
|
|
|
tests.test("LazyMapRandomAccessCollection/AssociatedTypes") {
|
|
typealias Base = MinimalRandomAccessCollection<OpaqueValue<Int>>
|
|
typealias Subject = LazyMapCollection<Base, OpaqueValue<Int32>>
|
|
expectRandomAccessCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: LazyMapCollection<Base, OpaqueValue<Int32>>.Iterator.self,
|
|
subSequenceType: LazyMapCollection<Base.SubSequence, OpaqueValue<Int32>>.self,
|
|
indexType: Base.Index.self,
|
|
indicesType: Base.Indices.self)
|
|
}
|
|
|
|
tests.test("lazy.mapped/TypeInference") {
|
|
let baseArray: [OpaqueValue<Int>] = (0..<10).map(OpaqueValue.init)
|
|
do {
|
|
var mapped = MinimalSequence(elements: baseArray)
|
|
.lazy.map { _ in OpaqueValue<Int8>(0) }
|
|
expectType(
|
|
LazyMapSequence<
|
|
MinimalSequence<OpaqueValue<Int>>,
|
|
OpaqueValue<Int8>
|
|
>.self,
|
|
&mapped)
|
|
}
|
|
do {
|
|
var mapped = MinimalCollection(elements: baseArray)
|
|
.lazy.map { _ in OpaqueValue<Int8>(0) }
|
|
expectType(
|
|
LazyMapCollection<
|
|
MinimalCollection<OpaqueValue<Int>>,
|
|
OpaqueValue<Int8>
|
|
>.self,
|
|
&mapped)
|
|
}
|
|
do {
|
|
var mapped = MinimalBidirectionalCollection(elements: baseArray)
|
|
.lazy.map { _ in OpaqueValue<Int8>(0) }
|
|
expectType(
|
|
LazyMapCollection<
|
|
MinimalBidirectionalCollection<OpaqueValue<Int>>,
|
|
OpaqueValue<Int8>
|
|
>.self,
|
|
&mapped)
|
|
}
|
|
do {
|
|
var mapped = MinimalRandomAccessCollection(elements: baseArray)
|
|
.lazy.map { _ in OpaqueValue<Int8>(0) }
|
|
expectType(
|
|
LazyMapCollection<
|
|
MinimalRandomAccessCollection<OpaqueValue<Int>>,
|
|
OpaqueValue<Int8>
|
|
>.self,
|
|
&mapped)
|
|
}
|
|
}
|
|
|
|
//===--- Reverse ----------------------------------------------------------===//
|
|
tests.test("ReversedCollection") {
|
|
let expected = Array(stride(from: 11, through: 0, by: -1))
|
|
let r = 0..<12
|
|
checkRandomAccessCollection(
|
|
expected,
|
|
r.reversed())
|
|
|
|
// Check that the reverse collection is still eager
|
|
do {
|
|
var calls = 0
|
|
_ = r.reversed().map { _ in calls += 1 }
|
|
expectEqual(r.count, calls)
|
|
}
|
|
|
|
checkBidirectionalCollection(
|
|
"raboof",
|
|
"foobar".reversed())
|
|
|
|
// Check that the reverse collection is still eager
|
|
do {
|
|
var calls = 0
|
|
_ = "foobar".reversed().map { _ in calls += 1 }
|
|
expectEqual("foobar".count, calls)
|
|
}
|
|
}
|
|
|
|
enum _Void {}
|
|
struct ExpectType<T> {
|
|
static func test(_: T){ print("T") }
|
|
static func test(_: Any) { fatalError() }
|
|
static func test(_: Any) -> _Void { fatalError() }
|
|
}
|
|
|
|
tests.test("ReversedCollection/Lazy") {
|
|
// Check that reversing a lazy collection, or lazy-ing a reverse
|
|
// collection, produces the same lazy reverse collection.
|
|
do {
|
|
|
|
let base = Array(stride(from: 11, through: 0, by: -1)).lazy.map { $0 }
|
|
|
|
typealias Base = LazyMapCollection<[Int], Int>
|
|
ExpectType<Base>.test(base)
|
|
|
|
typealias LazyReversedBase = ReversedCollection<Base>
|
|
|
|
let reversed = base.reversed()
|
|
ExpectType<LazyReversedBase>.test(reversed)
|
|
|
|
var calls = 0
|
|
let reversedAndMapped = reversed.map { (x) -> Int in calls += 1; return x }
|
|
expectEqual(0, calls)
|
|
checkRandomAccessCollection(0...11, reversedAndMapped)
|
|
expectNotEqual(0, calls)
|
|
}
|
|
|
|
do {
|
|
let base = "foobar".lazy.map { $0 }
|
|
typealias Base = LazyMapCollection<String, Character>
|
|
ExpectType<Base>.test(base)
|
|
|
|
typealias LazyReversedBase = ReversedCollection<Base>
|
|
|
|
let reversed = base.reversed()
|
|
ExpectType<LazyReversedBase>.test(reversed)
|
|
|
|
var calls = 0
|
|
let reversedAndMapped = reversed.map { (x) -> Character in calls += 1; return x }
|
|
expectEqual(0, calls)
|
|
checkBidirectionalCollection("raboof", reversedAndMapped)
|
|
expectNotEqual(0, calls)
|
|
}
|
|
}
|
|
|
|
// Given a couple of sequences backed by FilterGenerator's, check that
|
|
// the first selects even numbers and the second selects odd numbers,
|
|
// both from an underlying sequence of whole numbers.
|
|
func checkFilterIteratorBase< S : Sequence, I>(_ s1: S, _ s2: S)
|
|
where S.Iterator == LazyFilterSequence<I>.Iterator, I.Element == OpaqueValue<Int> {
|
|
var iter1 = s1.makeIterator()
|
|
expectEqual(0, iter1.next()!.value)
|
|
expectEqual(2, iter1.next()!.value)
|
|
expectEqual(4, iter1.next()!.value)
|
|
var h1 = iter1.base
|
|
expectEqual(5, h1.next()!.value)
|
|
expectEqual(6, h1.next()!.value)
|
|
expectEqual(7, h1.next()!.value)
|
|
|
|
var iter2 = s2.makeIterator()
|
|
expectEqual(1, iter2.next()!.value)
|
|
expectEqual(3, iter2.next()!.value)
|
|
expectEqual(5, iter2.next()!.value)
|
|
var h2 = iter2.base
|
|
expectEqual(6, h2.next()!.value)
|
|
expectEqual(7, h2.next()!.value)
|
|
expectEqual(8, h2.next()!.value)
|
|
}
|
|
|
|
tests.test("LazyFilterSequence") {
|
|
let base = (0..<100).map(OpaqueValue.init)
|
|
|
|
var calls = 0
|
|
var filtered = MinimalSequence(elements: base).lazy.filter {
|
|
x in calls += 1;
|
|
return x.value % 2 == 0
|
|
}
|
|
expectEqual(calls, 0, "filtering was eager!")
|
|
|
|
ExpectType<
|
|
LazyFilterSequence<MinimalSequence<OpaqueValue<Int>>>
|
|
>.test(filtered)
|
|
|
|
let evens = stride(from: 0, to: 100, by: 2).map(OpaqueValue.init)
|
|
checkSequence(evens, filtered, resiliencyChecks: .none) {
|
|
$0.value == $1.value
|
|
}
|
|
expectEqual(100, calls)
|
|
|
|
// Check that it works when the first element doesn't satisfy the predicate
|
|
let odds = stride(from: 1, to: 100, by: 2).map(OpaqueValue.init)
|
|
filtered =
|
|
MinimalSequence(elements: base).lazy.filter { $0.value % 2 != 0 }
|
|
checkSequence(odds, filtered, resiliencyChecks: .none) {
|
|
$0.value == $1.value
|
|
}
|
|
|
|
// Try again using explicit construction
|
|
filtered = LazyFilterSequence(
|
|
_base: MinimalSequence(elements: base),
|
|
{ x in calls += 1; return x.value % 2 == 0})
|
|
|
|
expectEqual(100, calls)
|
|
|
|
// Check that it constructs the same sequence
|
|
checkSequence(evens, filtered, resiliencyChecks: .none) {
|
|
$0.value == $1.value
|
|
}
|
|
|
|
expectEqual(200, calls)
|
|
|
|
checkFilterIteratorBase(
|
|
MinimalSequence(elements: base).lazy.filter { $0.value % 2 == 0 },
|
|
MinimalSequence(elements: base).lazy.filter { $0.value % 2 != 0 })
|
|
}
|
|
|
|
tests.test("LazyFilterIndex/base") {
|
|
let base = MinimalCollection(elements: (0..<100).map(OpaqueValue.init))
|
|
let evens = base.lazy.filter { $0.value % 2 == 0 }
|
|
let odds = base.lazy.filter { $0.value % 2 != 0 }
|
|
|
|
expectEqual(base.startIndex, evens.startIndex)
|
|
expectEqual(base.index(after: base.startIndex), odds.startIndex)
|
|
|
|
expectEqual(
|
|
base.index(after: base.index(after: base.startIndex)),
|
|
evens.index(after: evens.startIndex))
|
|
|
|
expectEqual(
|
|
base.index(after: base.index(after: base.index(after: base.startIndex))),
|
|
odds.index(after: odds.startIndex))
|
|
}
|
|
|
|
tests.test("LazyFilterCollection") {
|
|
let base = MinimalCollection(elements: (0..<100).map(OpaqueValue.init))
|
|
|
|
var calls = 0
|
|
let filtered = base.lazy.filter {
|
|
x in calls += 1;
|
|
return x.value % 2 == 0
|
|
}
|
|
expectEqual(calls, 0, "filtering was eager!")
|
|
|
|
ExpectType<
|
|
LazyFilterCollection<MinimalCollection<OpaqueValue<Int>>>
|
|
>.test(filtered)
|
|
|
|
checkOneLevelOfForwardCollection(
|
|
stride(from: 0, to: 100, by: 2).map(OpaqueValue.init), filtered,
|
|
resiliencyChecks: .none
|
|
) {
|
|
$0.value == $1.value
|
|
}
|
|
|
|
expectGE(calls, 100)
|
|
let oldCalls = calls
|
|
_ = filtered.first
|
|
expectLT(oldCalls, calls)
|
|
expectGE(oldCalls + 2, calls)
|
|
|
|
checkFilterIteratorBase(
|
|
base.lazy.filter { $0.value % 2 == 0 },
|
|
base.lazy.filter { $0.value % 2 != 0 })
|
|
}
|
|
|
|
tests.test("LazyFilterSequence/AssociatedTypes") {
|
|
typealias Base = MinimalSequence<OpaqueValue<Int>>
|
|
typealias Subject = LazyFilterSequence<Base>
|
|
expectSequenceAssociatedTypes(
|
|
sequenceType: Subject.self,
|
|
iteratorType: LazyFilterSequence<Base>.Iterator.self)
|
|
}
|
|
|
|
tests.test("LazyFilterCollection/AssociatedTypes") {
|
|
typealias Base = MinimalCollection<OpaqueValue<Int>>
|
|
typealias Subject = LazyFilterCollection<Base>
|
|
expectCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: LazyFilterCollection<Base>.Iterator.self,
|
|
subSequenceType: LazyFilterCollection<Base.SubSequence>.self,
|
|
indexType: Base.Index.self,
|
|
indicesType: DefaultIndices<Subject>.self)
|
|
}
|
|
|
|
tests.test("LazyFilterBidirectionalCollection/AssociatedTypes") {
|
|
typealias Base = MinimalBidirectionalCollection<OpaqueValue<Int>>
|
|
typealias Subject = LazyFilterCollection<Base>
|
|
expectBidirectionalCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: LazyFilterCollection<Base>.Iterator.self,
|
|
subSequenceType: LazyFilterCollection<Base.SubSequence>.self,
|
|
indexType: Base.Index.self,
|
|
indicesType: DefaultIndices<Subject>.self)
|
|
}
|
|
|
|
tests.test("lazy.filter/TypeInference") {
|
|
let baseArray: [OpaqueValue<Int>] = (0..<10).map(OpaqueValue.init)
|
|
do {
|
|
var filtered = MinimalSequence(elements: baseArray)
|
|
.lazy.filter { _ in true }
|
|
expectType(
|
|
LazyFilterSequence<MinimalSequence<OpaqueValue<Int>>>.self,
|
|
&filtered)
|
|
}
|
|
do {
|
|
var filtered = MinimalCollection(elements: baseArray)
|
|
.lazy.filter { _ in true }
|
|
expectType(
|
|
LazyFilterCollection<MinimalCollection<OpaqueValue<Int>>>.self,
|
|
&filtered)
|
|
}
|
|
do {
|
|
var filtered = MinimalBidirectionalCollection(elements: baseArray)
|
|
.lazy.filter { _ in true }
|
|
expectType(
|
|
LazyFilterCollection<
|
|
MinimalBidirectionalCollection<OpaqueValue<Int>>
|
|
>.self,
|
|
&filtered)
|
|
}
|
|
do {
|
|
var filtered = MinimalRandomAccessCollection(elements: baseArray)
|
|
.lazy.filter { _ in true }
|
|
expectType(
|
|
LazyFilterCollection<
|
|
MinimalRandomAccessCollection<OpaqueValue<Int>>
|
|
>.self,
|
|
&filtered)
|
|
}
|
|
}
|
|
|
|
do {
|
|
struct Sample {
|
|
var expected: Range<Int>
|
|
var data: [Range<Int>]
|
|
}
|
|
|
|
let flattenSamples: [Sample] = [
|
|
Sample(
|
|
expected: 0..<8, data: [ 1..<1, 0..<5, 7..<7, 5..<7, 7..<8 ]),
|
|
Sample(expected: 0..<8, data: [ 0..<5, 7..<7, 5..<7, 7..<8 ]),
|
|
Sample(
|
|
expected: 0..<8, data: [ 1..<1, 0..<5, 7..<7, 5..<7, 7..<8, 11..<11 ]),
|
|
Sample(
|
|
expected: 0..<16, data: [ 0..<10, 14..<14, 10..<14, 14..<16, 22..<22 ]),
|
|
Sample(expected: 0..<0, data: [ 11..<11 ]),
|
|
Sample(expected: 0..<0, data: [ 3..<3, 11..<11 ]),
|
|
Sample(expected: 0..<0, data: []),
|
|
]
|
|
|
|
for sample in flattenSamples {
|
|
let expected = sample.expected
|
|
let data = sample.data
|
|
|
|
tests.test("FlattenSequence/\(data)") {
|
|
var base = MinimalSequence(
|
|
elements: data.map { MinimalSequence(elements: $0) })
|
|
checkSequence(expected, base.joined(), resiliencyChecks: .none)
|
|
|
|
// Checking that flatten doesn't introduce laziness
|
|
|
|
// checkSequence consumed base, so reassign
|
|
base = MinimalSequence(
|
|
elements: data.map { MinimalSequence(elements: $0) })
|
|
let flattened = base.joined()
|
|
var calls = 0
|
|
_ = flattened.map { _ in calls += 1 }
|
|
expectEqual(
|
|
expected.count, calls,
|
|
"unexpected laziness in \(type(of: flattened))")
|
|
}
|
|
|
|
tests.test("FlattenSequence/Lazy/\(data)") {
|
|
// Checking that flatten doesn't remove laziness
|
|
let base = MinimalSequence(
|
|
elements: data.map { MinimalSequence(elements: $0) }
|
|
).lazy.map { $0 }
|
|
|
|
let flattened = base.joined()
|
|
var calls = 0
|
|
_ = flattened.map { _ in calls += 1 }
|
|
expectEqual(0, calls, "unexpected eagerness in \(type(of: flattened))")
|
|
}
|
|
|
|
% for Traversal in 'Forward', 'Bidirectional':
|
|
% TraversalCollection = collectionForTraversal(Traversal)
|
|
|
|
tests.test("FlattenCollection/${Traversal}/\(data)") {
|
|
let base = Minimal${TraversalCollection}(
|
|
elements: data.map { Minimal${TraversalCollection}(elements: $0) })
|
|
|
|
let flattened = base.joined()
|
|
check${Traversal}Collection(expected, flattened, resiliencyChecks: .none)
|
|
|
|
// Checking that flatten doesn't introduce laziness
|
|
var calls = 0
|
|
_ = flattened.map { _ in calls += 1 }
|
|
expectLE(
|
|
expected.count, calls,
|
|
"unexpected laziness in \(type(of: flattened))")
|
|
}
|
|
|
|
tests.test("FlattenCollection/${Traversal}/Lazy\(data)") {
|
|
// Checking that flatten doesn't remove laziness
|
|
let base = Minimal${TraversalCollection}(
|
|
elements: data.map { Minimal${TraversalCollection}(elements: $0) }
|
|
).lazy.map { $0 }
|
|
|
|
let flattened = base.joined()
|
|
|
|
var calls = 0
|
|
_ = flattened.map { _ in calls += 1 }
|
|
expectEqual(0, calls, "unexpected eagerness in \(type(of: flattened))")
|
|
}
|
|
% end
|
|
}
|
|
}
|
|
|
|
struct TryFlattenIndex<C: Collection> where C.Element: Collection {
|
|
typealias FlattenedIndex = FlattenCollection<C>.Index
|
|
}
|
|
|
|
|
|
//===--- LazyPrefixWhile --------------------------------------------------===//
|
|
|
|
let prefixDropWhileTests: [(data: [Int], value: Int, pivot: Int)]
|
|
|
|
prefixDropWhileTests = [
|
|
([], 0, 0),
|
|
([0], 0, 0),
|
|
([0], 99, 1),
|
|
([0, 10], 0, 0),
|
|
([0, 10], 10, 1),
|
|
([0, 10], 99, 2),
|
|
([0, 10, 20, 30, 40], 0, 0),
|
|
([0, 10, 20, 30, 40], 10, 1),
|
|
([0, 10, 20, 30, 40], 20, 2),
|
|
([0, 10, 20, 30, 40], 30, 3),
|
|
([0, 10, 20, 30, 40], 40, 4),
|
|
([0, 10, 20, 30, 40], 99, 5)
|
|
]
|
|
|
|
% for Kind in 'Sequence', 'Forward', 'Bidirectional':
|
|
% Self = 'Sequence' if Kind == 'Sequence' else collectionForTraversal(Kind)
|
|
% checkKind = 'ForwardCollection' if Kind == 'Forward' else Self
|
|
tests.test("LazyPrefixWhile${Self}").forEach(in: prefixDropWhileTests) {
|
|
(data, value, pivot) in
|
|
|
|
let base = Minimal${Self}(elements: data)
|
|
|
|
var calls1 = 0
|
|
let prefixed = base.lazy.prefix(while: { calls1 += 1; return $0 != value })
|
|
let expected = data.prefix(upTo: pivot)
|
|
expectEqual(0, calls1)
|
|
check${checkKind}(expected, prefixed)
|
|
|
|
var calls2 = 0
|
|
_ = prefixed.map { _ in calls2 += 1 }
|
|
expectEqual(0, calls2, "unexpected eagerness in \(type(of: prefixed))")
|
|
|
|
% if Kind == 'Bidirectional':
|
|
check${checkKind}(expected.reversed(), prefixed.reversed())
|
|
% end
|
|
}
|
|
% end
|
|
|
|
tests.test("LazyPrefixWhileSequence/AssociatedTypes") {
|
|
typealias Base = MinimalSequence<OpaqueValue<Int>>
|
|
typealias Subject = LazyPrefixWhileSequence<Base>
|
|
expectSequenceAssociatedTypes(
|
|
sequenceType: Subject.self,
|
|
iteratorType: LazyPrefixWhileSequence<Base>.Iterator.self)
|
|
}
|
|
|
|
tests.test("LazyPrefixWhileCollection/AssociatedTypes") {
|
|
typealias Base = MinimalCollection<OpaqueValue<Int>>
|
|
typealias Subject = LazyPrefixWhileCollection<Base>
|
|
expectCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: LazyPrefixWhileSequence<Base>.Iterator.self,
|
|
subSequenceType: Slice<Subject>.self,
|
|
indexType: LazyPrefixWhileCollection<Base>.Index.self,
|
|
indicesType: DefaultIndices<Subject>.self)
|
|
}
|
|
|
|
tests.test("LazyPrefixWhileBidirectionalCollection/AssociatedTypes") {
|
|
typealias Base = MinimalBidirectionalCollection<OpaqueValue<Int>>
|
|
typealias Subject = LazyPrefixWhileCollection<Base>
|
|
expectBidirectionalCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: LazyPrefixWhileCollection<Base>.Iterator.self,
|
|
// FIXME(ABI)#82 (Associated Types with where clauses): SubSequence should be `LazyFilterBidirectionalCollection<Base.Slice>`.
|
|
subSequenceType: Slice<Subject>.self,
|
|
indexType: LazyPrefixWhileCollection<Base>.Index.self,
|
|
indicesType: DefaultIndices<Subject>.self)
|
|
}
|
|
|
|
//===--- LazyDropWhile ----------------------------------------------------===//
|
|
|
|
% for Kind in 'Sequence', 'Forward', 'Bidirectional':
|
|
% Self = 'Sequence' if Kind == 'Sequence' else collectionForTraversal(Kind)
|
|
% checkKind = 'ForwardCollection' if Kind == 'Forward' else Self
|
|
tests.test("LazyDropWhile${Self}").forEach(in: prefixDropWhileTests) {
|
|
(data, value, pivot) in
|
|
|
|
let base = Minimal${Self}(elements: data)
|
|
|
|
var calls1 = 0
|
|
let dropped = base.lazy.drop(while: { calls1 += 1; return $0 != value })
|
|
let expected = data.suffix(from: pivot)
|
|
expectEqual(0, calls1)
|
|
check${checkKind}(expected, dropped)
|
|
|
|
var calls2 = 0
|
|
_ = dropped.map { _ in calls2 += 1 }
|
|
expectEqual(0, calls2, "unexpected eagerness in \(type(of: dropped))")
|
|
|
|
% if Kind == 'Bidirectional':
|
|
check${checkKind}(expected.reversed(), dropped.reversed())
|
|
% end
|
|
}
|
|
% end
|
|
|
|
tests.test("LazyDropWhileSequence/AssociatedTypes") {
|
|
typealias Base = MinimalSequence<OpaqueValue<Int>>
|
|
typealias Subject = LazyDropWhileSequence<Base>
|
|
expectSequenceAssociatedTypes(
|
|
sequenceType: Subject.self,
|
|
iteratorType: LazyDropWhileSequence<Base>.Iterator.self)
|
|
}
|
|
|
|
tests.test("LazyDropWhileCollection/AssociatedTypes") {
|
|
typealias Base = MinimalCollection<OpaqueValue<Int>>
|
|
typealias Subject = LazyDropWhileCollection<Base>
|
|
expectCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: LazyDropWhileSequence<Base>.Iterator.self,
|
|
subSequenceType: Slice<Subject>.self,
|
|
indexType: LazyDropWhileCollection<Base>.Index.self,
|
|
indicesType: DefaultIndices<Subject>.self)
|
|
}
|
|
|
|
tests.test("LazyDropWhileBidirectionalCollection/AssociatedTypes") {
|
|
typealias Base = MinimalBidirectionalCollection<OpaqueValue<Int>>
|
|
typealias Subject = LazyDropWhileCollection<Base>
|
|
expectBidirectionalCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: LazyDropWhileSequence<Base>.Iterator.self,
|
|
// FIXME(ABI)#83 (Associated Types with where clauses): SubSequence should be `LazyFilterBidirectionalCollection<Base.Slice>`.
|
|
subSequenceType: Slice<Subject>.self,
|
|
indexType: LazyDropWhileCollection<Base>.Index.self,
|
|
indicesType: DefaultIndices<Subject>.self)
|
|
}
|
|
|
|
runAllTests()
|