[swift-4.1-branch][stdlib] Utilize conditional conformances for lazy collections (#13349)
* [stdlib] Conditional conformances for LazyFilterCollection
(cherry picked from commit 833721a1728dcc8321f6a6824da49880c5a37d22)
* [stdlib] Conditional conformances for LazyMapCollection
(cherry picked from commit b927254564ff35154acb76f7835b665000dfee7a)
* Fix tests
(cherry picked from commit a1b1778c53256016079b58905004c3156a1eaf94)
* Conditional conformances for LazyCollection
(cherry picked from commit 6e7b36a66cdbc33ad062009541b06b38d7602286)
* Rearrange code in LazyFilterCollection and provide delegating overrides
(cherry picked from commit 1388064e37828f6b44fed8c8a29efaea0860c0cd)
* Enforce forward collection preconditions in LazyFilterCollection
(cherry picked from commit 229dcd6275a699dea6c533f4c7ca1c3d001d5958)
* [stdlib] Improve default implementation of Collection.distance(from:to:)
(cherry picked from commit 72948cae9af6d4772f9be3f8be30bca63f078c68)
(cherry picked from commit e4f94a318f78957b05354fc1e2f3c0e34eb55eb1)
diff --git a/benchmark/single-source/LazyFilter.swift b/benchmark/single-source/LazyFilter.swift
index 652fe00..2cfdfc8 100644
--- a/benchmark/single-source/LazyFilter.swift
+++ b/benchmark/single-source/LazyFilter.swift
@@ -47,7 +47,7 @@
CheckResults(res == 123)
}
-fileprivate var multiplesOfThree: LazyFilterBidirectionalCollection<Array<Int>>?
+fileprivate var multiplesOfThree: LazyFilterCollection<Array<Int>>?
fileprivate func setup_LazilyFilteredArrayContains() {
multiplesOfThree = Array(1..<5_000).lazy.filter { $0 % 3 == 0 }
diff --git a/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb b/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb
index 7e597d6..00843b0 100644
--- a/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb
+++ b/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb
@@ -1584,11 +1584,6 @@
.forEach(in: distanceFromToTests) {
test in
let c = toCollection(0..<20)
- let backwards = (test.startOffset > test.endOffset)
- if backwards && !collectionIsBidirectional {
- expectCrashLater()
- }
-
let d = c.distance(
from: c.nthIndex(test.startOffset), to: c.nthIndex(test.endOffset))
expectEqual(
diff --git a/stdlib/private/StdlibCollectionUnittest/MinimalCollections.swift.gyb b/stdlib/private/StdlibCollectionUnittest/MinimalCollections.swift.gyb
index 45d8399..bfc4cdd 100644
--- a/stdlib/private/StdlibCollectionUnittest/MinimalCollections.swift.gyb
+++ b/stdlib/private/StdlibCollectionUnittest/MinimalCollections.swift.gyb
@@ -658,8 +658,6 @@
public func distance(from start: ${Index}, to end: ${Index})
-> Int {
% if Traversal == 'Forward':
- _precondition(start <= end,
- "Only BidirectionalCollections can have end come before start")
% end
// FIXME: swift-3-indexing-model: perform a range check properly.
if start != endIndex {
diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt
index 9e17e41..ae2d805 100644
--- a/stdlib/public/core/CMakeLists.txt
+++ b/stdlib/public/core/CMakeLists.txt
@@ -55,7 +55,7 @@
Equatable.swift
ErrorType.swift
Existential.swift
- Filter.swift.gyb
+ Filter.swift
FixedArray.swift.gyb
FlatMap.swift
Flatten.swift.gyb
@@ -83,7 +83,7 @@
LazySequence.swift
LifetimeManager.swift
ManagedBuffer.swift
- Map.swift.gyb
+ Map.swift
MemoryLayout.swift
UnicodeScalar.swift # ORDER DEPENDENCY: Must precede Mirrors.swift
Mirrors.swift.gyb
diff --git a/stdlib/public/core/Collection.swift b/stdlib/public/core/Collection.swift
index ea210d2..abd0980 100644
--- a/stdlib/public/core/Collection.swift
+++ b/stdlib/public/core/Collection.swift
@@ -701,16 +701,11 @@
/// Returns the distance between two indices.
///
- /// Unless the collection conforms to the `BidirectionalCollection` protocol,
- /// `start` must be less than or equal to `end`.
- ///
/// - Parameters:
/// - start: A valid index of the collection.
/// - end: Another valid index of the collection. If `end` is equal to
/// `start`, the result is zero.
- /// - Returns: The distance between `start` and `end`. The result can be
- /// negative only if the collection conforms to the
- /// `BidirectionalCollection` protocol.
+ /// - Returns: The distance between `start` and `end`.
///
/// - Complexity: O(1) if the collection conforms to
/// `RandomAccessCollection`; otherwise, O(*n*), where *n* is the
@@ -962,30 +957,34 @@
/// Returns the distance between two indices.
///
- /// Unless the collection conforms to the `BidirectionalCollection` protocol,
- /// `start` must be less than or equal to `end`.
- ///
/// - Parameters:
/// - start: A valid index of the collection.
/// - end: Another valid index of the collection. If `end` is equal to
/// `start`, the result is zero.
- /// - Returns: The distance between `start` and `end`. The result can be
- /// negative only if the collection conforms to the
- /// `BidirectionalCollection` protocol.
+ /// - Returns: The distance between `start` and `end`.
///
/// - Complexity: O(1) if the collection conforms to
/// `RandomAccessCollection`; otherwise, O(*n*), where *n* is the
/// resulting distance.
@_inlineable
public func distance(from start: Index, to end: Index) -> Int {
- _precondition(start <= end,
- "Only BidirectionalCollections can have end come before start")
-
- var start = start
+ var _start: Index
+ let _end: Index
+ let step: Int
+ if start > end {
+ _start = end
+ _end = start
+ step = -1
+ }
+ else {
+ _start = start
+ _end = end
+ step = 1
+ }
var count = 0
- while start != end {
- count = count + 1
- formIndex(after: &start)
+ while _start != _end {
+ count += step
+ formIndex(after: &_start)
}
return count
}
diff --git a/stdlib/public/core/Filter.swift.gyb b/stdlib/public/core/Filter.swift
similarity index 75%
rename from stdlib/public/core/Filter.swift.gyb
rename to stdlib/public/core/Filter.swift
index 86d5d94..668311c 100644
--- a/stdlib/public/core/Filter.swift.gyb
+++ b/stdlib/public/core/Filter.swift
@@ -1,4 +1,4 @@
-//===--- Filter.swift.gyb -------------------------------------*- swift -*-===//
+//===--- Filter.swift -----------------------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
@@ -10,12 +10,6 @@
//
//===----------------------------------------------------------------------===//
-%{
-from gyb_stdlib_support import (
- collectionForTraversal
-)
-}%
-
/// An iterator over the elements traversed by some base iterator that also
/// satisfy a given predicate.
///
@@ -122,14 +116,6 @@
@available(swift, deprecated: 3.1, obsoleted: 4.0, message: "Use Base.Index")
public typealias LazyFilterIndex<Base : Collection> = Base.Index
-// FIXME(ABI)#27 (Conditional Conformance): `LazyFilter*Collection` types should be
-// collapsed into one `LazyFilterCollection` using conditional conformances.
-// Maybe even combined with `LazyFilterSequence`.
-// rdar://problem/17144340
-
-% for Traversal in ['Forward', 'Bidirectional']:
-% Self = "LazyFilter" + collectionForTraversal(Traversal)
-
/// A lazy `Collection` wrapper that includes the elements of an
/// underlying collection that satisfy a predicate.
///
@@ -140,17 +126,11 @@
/// general operations on `LazyFilterCollection` instances may not have the
/// documented complexity.
@_fixed_layout // FIXME(sil-serialize-all)
-public struct ${Self}<
- Base : ${collectionForTraversal(Traversal)}
-> : LazyCollectionProtocol, ${collectionForTraversal(Traversal)}
-{
-
- /// A type that represents a valid position in the collection.
- ///
- /// Valid indices consist of the position of every element and a
- /// "past the end" position that's not valid for use as a subscript.
- public typealias Index = Base.Index
-
+public struct LazyFilterCollection<Base : Collection> {
+ @_versioned // FIXME(sil-serialize-all)
+ internal var _base: Base
+ @_versioned // FIXME(sil-serialize-all)
+ internal let _predicate: (Base.Element) -> Bool
/// Creates an instance containing the elements of `base` that
/// satisfy `isIncluded`.
@@ -163,6 +143,38 @@
self._base = _base
self._predicate = isIncluded
}
+}
+
+extension LazyFilterCollection : Sequence {
+ public typealias SubSequence = LazyFilterCollection<Base.SubSequence>
+ public typealias Element = Base.Element
+
+ // Any estimate of the number of elements that pass `_predicate` requires
+ // iterating the collection and evaluating each element, which can be costly,
+ // is unexpected, and usually doesn't pay for itself in saving time through
+ // preventing intermediate reallocations. (SR-4164)
+ @_inlineable // FIXME(sil-serialize-all)
+ public var underestimatedCount: Int { return 0 }
+
+ @_inlineable // FIXME(sil-serialize-all)
+ public func _copyToContiguousArray()
+ -> ContiguousArray<Base.Iterator.Element> {
+
+ // The default implementation of `_copyToContiguousArray` queries the
+ // `count` property, which evaluates `_predicate` for every element --
+ // see the note above `underestimatedCount`. Here we treat `self` as a
+ // sequence and only rely on underestimated count.
+ return _copySequenceToContiguousArray(self)
+ }
+
+ /// Returns an iterator over the elements of this sequence.
+ ///
+ /// - Complexity: O(1).
+ @_inlineable // FIXME(sil-serialize-all)
+ public func makeIterator() -> LazyFilterIterator<Base.Iterator> {
+ return LazyFilterIterator(
+ _base: _base.makeIterator(), _predicate)
+ }
@_inlineable
public func _customContainsEquatableElement(
@@ -176,6 +188,14 @@
}
return nil
}
+}
+
+extension LazyFilterCollection : LazyCollectionProtocol, Collection {
+ /// A type that represents a valid position in the collection.
+ ///
+ /// Valid indices consist of the position of every element and a
+ /// "past the end" position that's not valid for use as a subscript.
+ public typealias Index = Base.Index
/// The position of the first element in a non-empty collection.
///
@@ -221,7 +241,98 @@
i = index
}
-% if Traversal == 'Bidirectional':
+ @inline(__always)
+ @_inlineable // FIXME(sil-serialize-all)
+ @_versioned // FIXME(sil-serialize-all)
+ internal func _advanceIndex(_ i: inout Index, step: Int) {
+ repeat {
+ _base.formIndex(&i, offsetBy: step)
+ } while i != _base.endIndex && !_predicate(_base[i])
+ }
+
+ @inline(__always)
+ @_inlineable // FIXME(sil-serialize-all)
+ @_versioned // FIXME(sil-serialize-all)
+ internal func _ensureBidirectional(step: Int) {
+ // FIXME: This seems to be the best way of checking whether _base is
+ // forward only without adding an extra protocol requirement.
+ // index(_:offsetBy:limitedBy:) is chosen becuase it is supposed to return
+ // nil when the resulting index lands outside the collection boundaries,
+ // and therefore likely does not trap in these cases.
+ if step < 0 {
+ _ = _base.index(
+ _base.endIndex, offsetBy: step, limitedBy: _base.startIndex)
+ }
+ }
+
+ @_inlineable // FIXME(sil-serialize-all)
+ public func index(_ i: Index, offsetBy n: Int) -> Index {
+ var i = i
+ let step = n.signum()
+ // The following line makes sure that index(_:offsetBy:) is invoked on the
+ // _base at least once, to trigger a _precondition in forward only
+ // collections.
+ _ensureBidirectional(step: step)
+ for _ in 0 ..< abs(numericCast(n)) {
+ _advanceIndex(&i, step: step)
+ }
+ return i
+ }
+
+ @_inlineable // FIXME(sil-serialize-all)
+ public func formIndex(_ i: inout Index, offsetBy n: Int) {
+ i = index(i, offsetBy: n)
+ }
+
+ @_inlineable // FIXME(sil-serialize-all)
+ public func index(
+ _ i: Index, offsetBy n: Int, limitedBy limit: Index
+ ) -> Index? {
+ var i = i
+ let step = n.signum()
+ // The following line makes sure that index(_:offsetBy:limitedBy:) is
+ // invoked on the _base at least once, to trigger a _precondition in
+ // forward only collections.
+ _ensureBidirectional(step: step)
+ for _ in 0 ..< abs(numericCast(n)) {
+ if i == limit {
+ return nil
+ }
+ _advanceIndex(&i, step: step)
+ }
+ return i
+ }
+
+ @_inlineable // FIXME(sil-serialize-all)
+ public func formIndex(
+ _ i: inout Index, offsetBy n: Int, limitedBy limit: Index
+ ) -> Bool {
+ if let advancedIndex = index(i, offsetBy: n, limitedBy: limit) {
+ i = advancedIndex
+ return true
+ }
+ i = limit
+ return false
+ }
+
+ /// Accesses the element at `position`.
+ ///
+ /// - Precondition: `position` is a valid position in `self` and
+ /// `position != endIndex`.
+ @_inlineable // FIXME(sil-serialize-all)
+ public subscript(position: Index) -> Base.Element {
+ return _base[position]
+ }
+
+ @_inlineable // FIXME(sil-serialize-all)
+ public subscript(bounds: Range<Index>) -> SubSequence {
+ return SubSequence(_base: _base[bounds], _predicate)
+ }
+}
+
+extension LazyFilterCollection : BidirectionalCollection
+ where Base : BidirectionalCollection {
+
@_inlineable // FIXME(sil-serialize-all)
public func index(before i: Index) -> Index {
var i = i
@@ -239,59 +350,8 @@
} while !_predicate(_base[index])
i = index
}
-% end
-
- /// Accesses the element at `position`.
- ///
- /// - Precondition: `position` is a valid position in `self` and
- /// `position != endIndex`.
- @_inlineable // FIXME(sil-serialize-all)
- public subscript(position: Index) -> Base.Element {
- return _base[position]
- }
-
- public typealias SubSequence = ${Self}<Base.SubSequence>
-
- @_inlineable // FIXME(sil-serialize-all)
- public subscript(bounds: Range<Index>) -> SubSequence {
- return SubSequence(_base: _base[bounds], _predicate)
- }
-
- // Any estimate of the number of elements that pass `_predicate` requires
- // iterating the collection and evaluating each element, which can be costly,
- // is unexpected, and usually doesn't pay for itself in saving time through
- // preventing intermediate reallocations. (SR-4164)
- @_inlineable // FIXME(sil-serialize-all)
- public var underestimatedCount: Int { return 0 }
-
- @_inlineable // FIXME(sil-serialize-all)
- public func _copyToContiguousArray()
- -> ContiguousArray<Base.Iterator.Element> {
-
- // The default implementation of `_copyToContiguousArray` queries the
- // `count` property, which evaluates `_predicate` for every element --
- // see the note above `underestimatedCount`. Here we treat `self` as a
- // sequence and only rely on underestimated count.
- return _copySequenceToContiguousArray(self)
- }
-
- /// Returns an iterator over the elements of this sequence.
- ///
- /// - Complexity: O(1).
- @_inlineable // FIXME(sil-serialize-all)
- public func makeIterator() -> LazyFilterIterator<Base.Iterator> {
- return LazyFilterIterator(
- _base: _base.makeIterator(), _predicate)
- }
-
- @_versioned // FIXME(sil-serialize-all)
- internal var _base: Base
- @_versioned // FIXME(sil-serialize-all)
- internal let _predicate: (Base.Element) -> Bool
}
-% end
-
extension LazySequenceProtocol {
/// Returns the elements of `self` that satisfy `isIncluded`.
///
@@ -303,20 +363,11 @@
public func filter(
_ isIncluded: @escaping (Elements.Element) -> Bool
) -> LazyFilterSequence<Self.Elements> {
- return LazyFilterSequence(
- _base: self.elements, isIncluded)
+ return LazyFilterSequence(_base: self.elements, isIncluded)
}
}
-% for Traversal in ['Forward', 'Bidirectional']:
-
-extension LazyCollectionProtocol
-% if Traversal != 'Forward':
- where
- Self : ${collectionForTraversal(Traversal)},
- Elements : ${collectionForTraversal(Traversal)}
-% end
-{
+extension LazyCollectionProtocol {
/// Returns the elements of `self` that satisfy `predicate`.
///
/// - Note: The elements of the result are computed on-demand, as
@@ -326,14 +377,10 @@
@_inlineable // FIXME(sil-serialize-all)
public func filter(
_ isIncluded: @escaping (Elements.Element) -> Bool
- ) -> LazyFilter${collectionForTraversal(Traversal)}<Self.Elements> {
- return LazyFilter${collectionForTraversal(Traversal)}(
- _base: self.elements, isIncluded)
+ ) -> LazyFilterCollection<Self.Elements> {
+ return LazyFilterCollection(_base: self.elements, isIncluded)
}
}
-% end
-
-// ${'Local Variables'}:
-// eval: (read-only-mode 1)
-// End:
+@available(*, deprecated, renamed: "LazyFilterCollection")
+public typealias LazyFilterBidirectionalCollection<T> = LazyFilterCollection<T> where T : BidirectionalCollection
diff --git a/stdlib/public/core/FlatMap.swift b/stdlib/public/core/FlatMap.swift
index 61e6483..33b2757 100644
--- a/stdlib/public/core/FlatMap.swift
+++ b/stdlib/public/core/FlatMap.swift
@@ -95,8 +95,7 @@
extension LazyCollectionProtocol
where
Self : BidirectionalCollection,
- Elements : BidirectionalCollection
-{
+ Elements : BidirectionalCollection {
/// Returns the concatenated results of mapping the given transformation over
/// this collection.
///
@@ -111,7 +110,7 @@
_ transform: @escaping (Elements.Element) -> SegmentOfResult
) -> LazyCollection<
FlattenBidirectionalCollection<
- LazyMapBidirectionalCollection<Elements, SegmentOfResult>>> {
+ LazyMapCollection<Elements, SegmentOfResult>>> {
return self.map(transform).joined()
}
@@ -128,9 +127,9 @@
@_inlineable // FIXME(sil-serialize-all)
public func flatMap<ElementOfResult>(
_ transform: @escaping (Elements.Element) -> ElementOfResult?
- ) -> LazyMapBidirectionalCollection<
- LazyFilterBidirectionalCollection<
- LazyMapBidirectionalCollection<Elements, ElementOfResult?>>,
+ ) -> LazyMapCollection<
+ LazyFilterCollection<
+ LazyMapCollection<Elements, ElementOfResult?>>,
ElementOfResult
> {
return self.map(transform).filter { $0 != nil }.map { $0! }
diff --git a/stdlib/public/core/LazyCollection.swift.gyb b/stdlib/public/core/LazyCollection.swift.gyb
index 2ea4e0c..c50d741 100644
--- a/stdlib/public/core/LazyCollection.swift.gyb
+++ b/stdlib/public/core/LazyCollection.swift.gyb
@@ -38,18 +38,13 @@
public var elements: Self { return self }
}
-% for Traversal in TRAVERSALS:
-% TraversalCollection = collectionForTraversal(Traversal)
-% Self = 'Lazy' + TraversalCollection
-% Slice = TraversalCollection.replace('Collection', 'Slice')
-
/// A collection containing the same elements as a `Base` collection,
/// but on which some operations such as `map` and `filter` are
/// implemented lazily.
///
/// - See also: `LazySequenceProtocol`, `LazyCollection`
@_fixed_layout
-public struct ${Self}<Base : ${TraversalCollection}> : LazyCollectionProtocol {
+public struct LazyCollection<Base : Collection> : LazyCollectionProtocol {
/// The type of the underlying collection.
public typealias Elements = Base
@@ -78,7 +73,7 @@
/// Forward implementations to the base collection, to pick up any
/// optimizations it might implement.
-extension ${Self} : Sequence {
+extension LazyCollection : Sequence {
public typealias Iterator = Base.Iterator
@@ -118,7 +113,7 @@
}
}
-extension ${Self} : ${TraversalCollection} {
+extension LazyCollection : Collection {
/// The position of the first element in a non-empty collection.
///
/// In an empty collection, `startIndex == endIndex`.
@@ -162,7 +157,7 @@
///
/// - Complexity: O(1)
@_inlineable
- public subscript(bounds: Range<Index>) -> Slice<${Self}<Base>> {
+ public subscript(bounds: Range<Index>) -> Slice<LazyCollection<Base>> {
return Slice(base: self, bounds: bounds)
}
@@ -226,8 +221,10 @@
return _base.distance(from:start, to: end)
}
-% if Traversal != 'Forward':
+}
+extension LazyCollection : BidirectionalCollection
+ where Base : BidirectionalCollection {
@_inlineable
public func index(before i: Base.Index) -> Base.Index {
return _base.index(before: i)
@@ -237,11 +234,13 @@
public var last: Base.Element? {
return _base.last
}
-% end
}
+extension LazyCollection : RandomAccessCollection
+ where Base : RandomAccessCollection {}
+
/// Augment `self` with lazy methods such as `map`, `filter`, etc.
-extension ${TraversalCollection} {
+extension Collection {
/// A view onto this collection that provides lazy implementations of
/// normally eager operations, such as `map` and `filter`.
///
@@ -249,11 +248,13 @@
/// intermediate operations from allocating storage, or when you only
/// need a part of the final collection to avoid unnecessary computation.
@_inlineable
- public var lazy: ${Self}<Self> {
- return ${Self}(_base: self)
+ public var lazy: LazyCollection<Self> {
+ return LazyCollection(_base: self)
}
}
+% for Traversal in TRAVERSALS:
+% TraversalCollection = collectionForTraversal(Traversal)
// Without this specific overload the non-re-wrapping extension on
// LazyCollectionProtocol (below) is not selected for some reason.
extension ${TraversalCollection} where Self : LazyCollectionProtocol {
@@ -263,12 +264,15 @@
return self
}
}
-
% end
extension Slice: LazySequenceProtocol where Base: LazySequenceProtocol { }
extension Slice: LazyCollectionProtocol where Base: LazyCollectionProtocol { }
+@available(*, deprecated, renamed: "LazyCollection")
+public typealias LazyBidirectionalCollection<T> = LazyCollection<T> where T : BidirectionalCollection
+@available(*, deprecated, renamed: "LazyCollection")
+public typealias LazyRandomAccessCollection<T> = LazyCollection<T> where T : RandomAccessCollection
// ${'Local Variables'}:
// eval: (read-only-mode 1)
// End:
diff --git a/stdlib/public/core/Map.swift.gyb b/stdlib/public/core/Map.swift
similarity index 85%
rename from stdlib/public/core/Map.swift.gyb
rename to stdlib/public/core/Map.swift
index 1a73442..a8a0d90 100644
--- a/stdlib/public/core/Map.swift.gyb
+++ b/stdlib/public/core/Map.swift
@@ -1,4 +1,4 @@
-//===--- Map.swift.gyb - Lazily map over a Sequence -----------*- swift -*-===//
+//===--- Map.swift - Lazily map over a Sequence ---------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
@@ -10,13 +10,6 @@
//
//===----------------------------------------------------------------------===//
-%{
-from gyb_stdlib_support import (
- TRAVERSALS,
- collectionForTraversal
-)
-}%
-
/// The `IteratorProtocol` used by `MapSequence` and `MapCollection`.
/// Produces each element by passing the output of the `Base`
/// `IteratorProtocol` through a transform function returning `Element`.
@@ -96,22 +89,14 @@
//===--- Collections ------------------------------------------------------===//
-// FIXME(ABI)#45 (Conditional Conformance): `LazyMap*Collection` types should be
-// collapsed into one `LazyMapCollection` using conditional conformances.
-// Maybe even combined with `LazyMapSequence`.
-// rdar://problem/17144340
-
-% for Traversal in TRAVERSALS:
-% Self = "LazyMap" + collectionForTraversal(Traversal)
-
/// A `Collection` whose elements consist of those in a `Base`
/// `Collection` passed through a transform function returning `Element`.
/// These elements are computed lazily, each time they're read, by
/// calling the transform function on a base element.
@_fixed_layout
-public struct ${Self}<
- Base : ${collectionForTraversal(Traversal)}, Element
-> : LazyCollectionProtocol, ${collectionForTraversal(Traversal)} {
+public struct LazyMapCollection<
+ Base : Collection, Element
+> : LazyCollectionProtocol, Collection {
// FIXME(compiler limitation): should be inferable.
public typealias Index = Base.Index
@@ -129,16 +114,6 @@
_base.formIndex(after: &i)
}
-% if Traversal in ['Bidirectional', 'RandomAccess']:
- @_inlineable
- public func index(before i: Index) -> Index { return _base.index(before: i) }
-
- @_inlineable
- public func formIndex(before i: inout Index) {
- _base.formIndex(before: &i)
- }
-% end
-
/// Accesses the element at `position`.
///
/// - Precondition: `position` is a valid position in `self` and
@@ -148,7 +123,7 @@
return _transform(_base[position])
}
- public typealias SubSequence = ${Self}<Base.SubSequence, Element>
+ public typealias SubSequence = LazyMapCollection<Base.SubSequence, Element>
@_inlineable
public subscript(bounds: Range<Base.Index>) -> SubSequence {
@@ -183,11 +158,6 @@
@_inlineable
public var first: Element? { return _base.first.map(_transform) }
-% if Traversal in ['Bidirectional', 'RandomAccess']:
- @_inlineable
- public var last: Element? { return _base.last.map(_transform) }
-% end
-
@_inlineable
public func index(_ i: Index, offsetBy n: Int) -> Index {
return _base.index(i, offsetBy: n)
@@ -233,7 +203,24 @@
internal let _transform: (Base.Element) -> Element
}
-% end
+extension LazyMapCollection : BidirectionalCollection
+ where Base : BidirectionalCollection {
+
+ @_inlineable
+ public func index(before i: Index) -> Index { return _base.index(before: i) }
+
+ @_inlineable
+ public func formIndex(before i: inout Index) {
+ _base.formIndex(before: &i)
+ }
+
+ @_inlineable
+ public var last: Element? { return _base.last.map(_transform) }
+}
+
+extension LazyMapCollection : RandomAccessCollection
+ where Base : RandomAccessCollection {}
+
//===--- Support for s.lazy -----------------------------------------------===//
@@ -249,30 +236,18 @@
}
}
-% for Traversal in TRAVERSALS:
-
-extension LazyCollectionProtocol
-% if Traversal != 'Forward':
- where
- Self : ${collectionForTraversal(Traversal)},
- Elements : ${collectionForTraversal(Traversal)}
-% end
-{
+extension LazyCollectionProtocol {
/// Returns a `LazyMapCollection` over this `Collection`. The elements of
/// the result are computed lazily, each time they are read, by
/// calling `transform` function on a base element.
@_inlineable
public func map<U>(
_ transform: @escaping (Elements.Element) -> U
- ) -> LazyMap${collectionForTraversal(Traversal)}<Self.Elements, U> {
- return LazyMap${collectionForTraversal(Traversal)}(
- _base: self.elements,
- transform: transform)
+ ) -> LazyMapCollection<Self.Elements, U> {
+ return LazyMapCollection(_base: self.elements, transform: transform)
}
}
-% end
-
extension LazyMapCollection {
// This overload is needed to re-enable Swift 3 source compatibility related
// to a bugfix in ranking behavior of the constraint solver.
@@ -289,6 +264,7 @@
}
}
-// ${'Local Variables'}:
-// eval: (read-only-mode 1)
-// End:
+@available(*, deprecated, renamed: "LazyMapCollection")
+public typealias LazyMapBidirectionalCollection<T, E> = LazyMapCollection<T, E> where T : BidirectionalCollection
+@available(*, deprecated, renamed: "LazyMapCollection")
+public typealias LazyMapRandomAccessCollection<T, E> = LazyMapCollection<T, E> where T : RandomAccessCollection
diff --git a/stdlib/public/core/Reverse.swift b/stdlib/public/core/Reverse.swift
index f9303ad..da7c0c9 100644
--- a/stdlib/public/core/Reverse.swift
+++ b/stdlib/public/core/Reverse.swift
@@ -312,25 +312,7 @@
///
/// - Complexity: O(1)
@_inlineable
- public func reversed() -> LazyBidirectionalCollection<
- ReversedCollection<Elements>
- > {
- return ReversedCollection(_base: elements).lazy
- }
-}
-
-extension LazyCollectionProtocol
- where
- Self : RandomAccessCollection,
- Elements : RandomAccessCollection {
-
- /// Returns the elements of the collection in reverse order.
- ///
- /// - Complexity: O(1)
- @_inlineable
- public func reversed() -> LazyRandomAccessCollection<
- ReversedCollection<Elements>
- > {
+ public func reversed() -> LazyCollection<ReversedCollection<Elements>> {
return ReversedCollection(_base: elements).lazy
}
}
diff --git a/validation-test/stdlib/Collection/LazyFilterCollection.swift.gyb b/validation-test/stdlib/Collection/LazyFilterCollection.swift.gyb
index ff3513f..0aa6967 100644
--- a/validation-test/stdlib/Collection/LazyFilterCollection.swift.gyb
+++ b/validation-test/stdlib/Collection/LazyFilterCollection.swift.gyb
@@ -15,12 +15,12 @@
// Test collections using value types as elements.
% for (traversal, kind) in variations:
CollectionTests.add${traversal}${kind}Tests(
- make${kind}: { (elements: [OpaqueValue<Int>]) -> LazyFilter${traversal}${kind}<Minimal${traversal}${kind}<OpaqueValue<Int>>> in
+ make${kind}: { (elements: [OpaqueValue<Int>]) -> LazyFilter${kind}<Minimal${traversal}${kind}<OpaqueValue<Int>>> in
Minimal${traversal}${kind}(elements: elements).lazy.filter { _ in return true }
},
wrapValue: identity,
extractValue: identity,
- make${kind}OfEquatable: { (elements: [MinimalEquatableValue]) -> LazyFilter${traversal}${kind}<Minimal${traversal}${kind}<MinimalEquatableValue>> in
+ make${kind}OfEquatable: { (elements: [MinimalEquatableValue]) -> LazyFilter${kind}<Minimal${traversal}${kind}<MinimalEquatableValue>> in
Minimal${traversal}${kind}(elements: elements).lazy.filter { _ in return true }
},
wrapValueIntoEquatable: identityEq,
@@ -31,7 +31,7 @@
// Test collections using reference types as elements.
% for (traversal, kind) in variations:
CollectionTests.add${traversal}${kind}Tests(
- make${kind}: { (elements: [LifetimeTracked]) -> LazyFilter${traversal}${kind}<Minimal${traversal}${kind}<LifetimeTracked>> in
+ make${kind}: { (elements: [LifetimeTracked]) -> LazyFilter${kind}<Minimal${traversal}${kind}<LifetimeTracked>> in
// FIXME: create a better sequence and filter
Minimal${traversal}${kind}(elements: elements).lazy.filter { _ in return true }
},
@@ -41,7 +41,7 @@
extractValue: { (element: LifetimeTracked) in
OpaqueValue(element.value, identity: element.identity)
},
- make${kind}OfEquatable: { (elements: [LifetimeTracked]) -> LazyFilter${traversal}${kind}<Minimal${traversal}${kind}<LifetimeTracked>> in
+ make${kind}OfEquatable: { (elements: [LifetimeTracked]) -> LazyFilter${kind}<Minimal${traversal}${kind}<LifetimeTracked>> in
// FIXME: create a better sequence and filter
Minimal${traversal}${kind}(elements: elements).lazy.filter { _ in return true }
},
diff --git a/validation-test/stdlib/Collection/LazyMapBidirectionalCollection.swift b/validation-test/stdlib/Collection/LazyMapBidirectionalCollection.swift
index de4162b..38acd9b 100644
--- a/validation-test/stdlib/Collection/LazyMapBidirectionalCollection.swift
+++ b/validation-test/stdlib/Collection/LazyMapBidirectionalCollection.swift
@@ -15,12 +15,12 @@
// Test collections using value types as elements.
CollectionTests.addBidirectionalCollectionTests(
- makeCollection: { (elements: [OpaqueValue<Int>]) -> LazyMapBidirectionalCollection<MinimalBidirectionalCollection<OpaqueValue<Int>>, OpaqueValue<Int>> in
+ makeCollection: { (elements: [OpaqueValue<Int>]) -> LazyMapCollection<MinimalBidirectionalCollection<OpaqueValue<Int>>, OpaqueValue<Int>> in
MinimalBidirectionalCollection(elements: elements).lazy.map(identity)
},
wrapValue: identity,
extractValue: identity,
- makeCollectionOfEquatable: { (elements: [MinimalEquatableValue]) -> LazyMapBidirectionalCollection<MinimalBidirectionalCollection<MinimalEquatableValue>, MinimalEquatableValue> in
+ makeCollectionOfEquatable: { (elements: [MinimalEquatableValue]) -> LazyMapCollection<MinimalBidirectionalCollection<MinimalEquatableValue>, MinimalEquatableValue> in
MinimalBidirectionalCollection(elements: elements).lazy.map(identityEq)
},
wrapValueIntoEquatable: identityEq,
@@ -29,7 +29,7 @@
// Test collections using reference types as elements.
CollectionTests.addBidirectionalCollectionTests(
- makeCollection: { (elements: [LifetimeTracked]) -> LazyMapBidirectionalCollection<MinimalBidirectionalCollection<LifetimeTracked>, LifetimeTracked> in
+ makeCollection: { (elements: [LifetimeTracked]) -> LazyMapCollection<MinimalBidirectionalCollection<LifetimeTracked>, LifetimeTracked> in
MinimalBidirectionalCollection(elements: elements).lazy.map { $0 }
},
wrapValue: { (element: OpaqueValue<Int>) in
@@ -38,7 +38,7 @@
extractValue: { (element: LifetimeTracked) in
OpaqueValue(element.value, identity: element.identity)
},
- makeCollectionOfEquatable: { (elements: [LifetimeTracked]) -> LazyMapBidirectionalCollection<MinimalBidirectionalCollection<LifetimeTracked>, LifetimeTracked> in
+ makeCollectionOfEquatable: { (elements: [LifetimeTracked]) -> LazyMapCollection<MinimalBidirectionalCollection<LifetimeTracked>, LifetimeTracked> in
MinimalBidirectionalCollection(elements: elements).lazy.map { $0 }
},
wrapValueIntoEquatable: { (element: MinimalEquatableValue) in
diff --git a/validation-test/stdlib/Lazy.swift.gyb b/validation-test/stdlib/Lazy.swift.gyb
index 58b6e57..22e4a79 100644
--- a/validation-test/stdlib/Lazy.swift.gyb
+++ b/validation-test/stdlib/Lazy.swift.gyb
@@ -507,7 +507,7 @@
OpaqueValue(Int32(input.value))
}
expectType(
- LazyMap${TraversalCollection}<
+ LazyMapCollection<
Minimal${TraversalCollection}<OpaqueValue<Int>>, OpaqueValue<Int32>
>.self,
&lazyMap)
@@ -810,7 +810,7 @@
expectEqual(0, calls)
expectType(
- LazyMap${TraversalCollection}<
+ LazyMapCollection<
Minimal${TraversalCollection}<OpaqueValue<Int>>,
OpaqueValue<Double>>.self,
&mapped)
@@ -880,22 +880,22 @@
tests.test("LazyMapBidirectionalCollection/AssociatedTypes") {
typealias Base = MinimalBidirectionalCollection<OpaqueValue<Int>>
- typealias Subject = LazyMapBidirectionalCollection<Base, OpaqueValue<Int32>>
+ typealias Subject = LazyMapCollection<Base, OpaqueValue<Int32>>
expectBidirectionalCollectionAssociatedTypes(
collectionType: Subject.self,
iteratorType: LazyMapIterator<Base.Iterator, OpaqueValue<Int32>>.self,
- subSequenceType: LazyMapBidirectionalCollection<Base.SubSequence, OpaqueValue<Int32>>.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 = LazyMapRandomAccessCollection<Base, OpaqueValue<Int32>>
+ typealias Subject = LazyMapCollection<Base, OpaqueValue<Int32>>
expectRandomAccessCollectionAssociatedTypes(
collectionType: Subject.self,
iteratorType: LazyMapIterator<Base.Iterator, OpaqueValue<Int32>>.self,
- subSequenceType: LazyMapRandomAccessCollection<Base.SubSequence, OpaqueValue<Int32>>.self,
+ subSequenceType: LazyMapCollection<Base.SubSequence, OpaqueValue<Int32>>.self,
indexType: Base.Index.self,
indicesType: Base.Indices.self)
}
@@ -926,7 +926,7 @@
var mapped = MinimalBidirectionalCollection(elements: baseArray)
.lazy.map { _ in OpaqueValue<Int8>(0) }
expectType(
- LazyMapBidirectionalCollection<
+ LazyMapCollection<
MinimalBidirectionalCollection<OpaqueValue<Int>>,
OpaqueValue<Int8>
>.self,
@@ -936,7 +936,7 @@
var mapped = MinimalRandomAccessCollection(elements: baseArray)
.lazy.map { _ in OpaqueValue<Int8>(0) }
expectType(
- LazyMapRandomAccessCollection<
+ LazyMapCollection<
MinimalRandomAccessCollection<OpaqueValue<Int>>,
OpaqueValue<Int8>
>.self,
@@ -960,14 +960,14 @@
}
checkBidirectionalCollection(
- "raboof".characters,
- "foobar".characters.reversed())
+ "raboof",
+ "foobar".reversed())
// Check that the reverse collection is still eager
do {
var calls = 0
- _ = "foobar".characters.reversed().map { _ in calls += 1 }
- expectEqual("foobar".characters.count, calls)
+ _ = "foobar".reversed().map { _ in calls += 1 }
+ expectEqual("foobar".count, calls)
}
}
@@ -985,11 +985,10 @@
let base = Array(stride(from: 11, through: 0, by: -1)).lazy.map { $0 }
- typealias Base = LazyMapRandomAccessCollection<[Int], Int>
+ typealias Base = LazyMapCollection<[Int], Int>
ExpectType<Base>.test(base)
- typealias LazyReversedBase = LazyRandomAccessCollection<
- ReversedCollection<Base>>
+ typealias LazyReversedBase = LazyCollection<ReversedCollection<Base>>
let reversed = base.reversed()
ExpectType<LazyReversedBase>.test(reversed)
@@ -1002,17 +1001,11 @@
}
do {
- typealias Expected = LazyBidirectionalCollection<
- ReversedCollection<String.CharacterView>
- >
-
- let base = "foobar".characters.lazy.map { $0 }
- typealias Base = LazyMapBidirectionalCollection<
- String.CharacterView, Character>
+ let base = "foobar".lazy.map { $0 }
+ typealias Base = LazyMapCollection<String, Character>
ExpectType<Base>.test(base)
- typealias LazyReversedBase = LazyBidirectionalCollection<
- ReversedCollection<Base>>
+ typealias LazyReversedBase = LazyCollection<ReversedCollection<Base>>
let reversed = base.reversed()
ExpectType<LazyReversedBase>.test(reversed)
@@ -1020,7 +1013,7 @@
var calls = 0
let reversedAndMapped = reversed.map { (x) -> Character in calls += 1; return x }
expectEqual(0, calls)
- checkBidirectionalCollection("raboof".characters, reversedAndMapped)
+ checkBidirectionalCollection("raboof", reversedAndMapped)
expectNotEqual(0, calls)
}
}
@@ -1161,18 +1154,18 @@
collectionType: Subject.self,
iteratorType: LazyFilterIterator<Base.Iterator>.self,
subSequenceType: LazyFilterCollection<Base.SubSequence>.self,
- indexType: LazyFilterIndex<Base>.self,
+ indexType: Base.Index.self,
indicesType: DefaultIndices<Subject>.self)
}
tests.test("LazyFilterBidirectionalCollection/AssociatedTypes") {
typealias Base = MinimalBidirectionalCollection<OpaqueValue<Int>>
- typealias Subject = LazyFilterBidirectionalCollection<Base>
+ typealias Subject = LazyFilterCollection<Base>
expectBidirectionalCollectionAssociatedTypes(
collectionType: Subject.self,
iteratorType: LazyFilterIterator<Base.Iterator>.self,
- subSequenceType: LazyFilterBidirectionalCollection<Base.SubSequence>.self,
- indexType: LazyFilterIndex<Base>.self,
+ subSequenceType: LazyFilterCollection<Base.SubSequence>.self,
+ indexType: Base.Index.self,
indicesType: DefaultBidirectionalIndices<Subject>.self)
}
@@ -1196,7 +1189,7 @@
var filtered = MinimalBidirectionalCollection(elements: baseArray)
.lazy.filter { _ in true }
expectType(
- LazyFilterBidirectionalCollection<
+ LazyFilterCollection<
MinimalBidirectionalCollection<OpaqueValue<Int>>
>.self,
&filtered)
@@ -1205,7 +1198,7 @@
var filtered = MinimalRandomAccessCollection(elements: baseArray)
.lazy.filter { _ in true }
expectType(
- LazyFilterBidirectionalCollection<
+ LazyFilterCollection<
MinimalRandomAccessCollection<OpaqueValue<Int>>
>.self,
&filtered)
diff --git a/validation-test/stdlib/Range.swift.gyb b/validation-test/stdlib/Range.swift.gyb
index d94930d..a9675e2 100644
--- a/validation-test/stdlib/Range.swift.gyb
+++ b/validation-test/stdlib/Range.swift.gyb
@@ -784,7 +784,7 @@
MiscTestSuite.test("reversed()") {
var result = (0..<10).lazy.reversed()
- typealias Expected = LazyRandomAccessCollection<
+ typealias Expected = LazyCollection<
ReversedRandomAccessCollection<CountableRange<Int>>>
expectType(Expected.self, &result)
expectEqualSequence(