Skip to content

Commit 25b10eb

Browse files
authored
Merge pull request #78092 from Azoy/enumerated-collection
[stdlib] Conditionally conform EnumeratedSequence to Collection(s)
2 parents 223ebd2 + a55c9c7 commit 25b10eb

File tree

10 files changed

+522
-91
lines changed

10 files changed

+522
-91
lines changed

Runtimes/Core/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ add_library(swiftCore
7272
DropWhile.swift
7373
Dump.swift
7474
EmptyCollection.swift
75+
EnumeratedSequence.swift
7576
Equatable.swift
7677
ErrorType.swift
7778
ExistentialCollection.swift

stdlib/private/StdlibCollectionUnittest/MinimalCollections.swift

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,6 +1615,167 @@ public struct MinimalBidirectionalCollection<T> : BidirectionalCollection {
16151615
internal let _collectionState: _CollectionState
16161616
}
16171617

1618+
/// A minimal implementation of `Collection` with extra checks.
1619+
public struct MinimalBidirectionalRandomAccessCollection<T> : BidirectionalCollection, RandomAccessCollection {
1620+
/// Creates a collection with given contents, but a unique modification
1621+
/// history. No other instance has the same modification history.
1622+
public init<S : Sequence>(
1623+
elements: S,
1624+
underestimatedCount: UnderestimatedCountBehavior = .value(0)
1625+
) where S.Element == T {
1626+
self._elements = Array(elements)
1627+
1628+
self._collectionState = _CollectionState(
1629+
newRootStateForElementCount: self._elements.count)
1630+
1631+
switch underestimatedCount {
1632+
case .precise:
1633+
self.underestimatedCount = _elements.count
1634+
1635+
case .half:
1636+
self.underestimatedCount = _elements.count / 2
1637+
1638+
case .overestimate:
1639+
self.underestimatedCount = _elements.count * 3 + 5
1640+
1641+
case .value(let count):
1642+
self.underestimatedCount = count
1643+
}
1644+
}
1645+
1646+
1647+
public let timesMakeIteratorCalled = ResettableValue(0)
1648+
1649+
public func makeIterator() -> MinimalIterator<T> {
1650+
timesMakeIteratorCalled.value += 1
1651+
return MinimalIterator(_elements)
1652+
}
1653+
1654+
public typealias Index = MinimalIndex
1655+
1656+
internal func _index(forPosition i: Int) -> MinimalIndex {
1657+
return MinimalIndex(
1658+
collectionState: _collectionState,
1659+
position: i,
1660+
startIndex: _elements.startIndex,
1661+
endIndex: _elements.endIndex)
1662+
}
1663+
1664+
internal func _uncheckedIndex(forPosition i: Int) -> MinimalIndex {
1665+
return MinimalIndex(
1666+
_collectionState: _collectionState,
1667+
uncheckedPosition: i)
1668+
}
1669+
1670+
public let timesStartIndexCalled = ResettableValue(0)
1671+
1672+
public var startIndex: MinimalIndex {
1673+
timesStartIndexCalled.value += 1
1674+
return _uncheckedIndex(forPosition: _elements.startIndex)
1675+
}
1676+
1677+
public let timesEndIndexCalled = ResettableValue(0)
1678+
1679+
public var endIndex: MinimalIndex {
1680+
timesEndIndexCalled.value += 1
1681+
return _uncheckedIndex(forPosition: _elements.endIndex)
1682+
}
1683+
1684+
1685+
public func _failEarlyRangeCheck(
1686+
_ index: MinimalIndex,
1687+
bounds: Range<MinimalIndex>
1688+
) {
1689+
_expectCompatibleIndices(
1690+
_uncheckedIndex(forPosition: index.position),
1691+
index)
1692+
1693+
_expectCompatibleIndices(
1694+
_uncheckedIndex(forPosition: bounds.lowerBound.position),
1695+
bounds.lowerBound)
1696+
_expectCompatibleIndices(
1697+
_uncheckedIndex(forPosition: bounds.upperBound.position),
1698+
bounds.upperBound)
1699+
1700+
expectTrapping(
1701+
index.position,
1702+
in: bounds.lowerBound.position..<bounds.upperBound.position)
1703+
}
1704+
1705+
public func _failEarlyRangeCheck(
1706+
_ range: Range<MinimalIndex>,
1707+
bounds: Range<MinimalIndex>
1708+
) {
1709+
_expectCompatibleIndices(
1710+
_uncheckedIndex(forPosition: range.lowerBound.position),
1711+
range.lowerBound)
1712+
_expectCompatibleIndices(
1713+
_uncheckedIndex(forPosition: range.upperBound.position),
1714+
range.upperBound)
1715+
1716+
_expectCompatibleIndices(
1717+
_uncheckedIndex(forPosition: bounds.lowerBound.position),
1718+
bounds.lowerBound)
1719+
_expectCompatibleIndices(
1720+
_uncheckedIndex(forPosition: bounds.upperBound.position),
1721+
bounds.upperBound)
1722+
1723+
expectTrapping(
1724+
range.lowerBound.position..<range.upperBound.position,
1725+
in: bounds.lowerBound.position..<bounds.upperBound.position)
1726+
}
1727+
1728+
public func index(after i: MinimalIndex) -> MinimalIndex {
1729+
_failEarlyRangeCheck(i, bounds: startIndex..<endIndex)
1730+
return _uncheckedIndex(forPosition: i.position + 1)
1731+
}
1732+
1733+
public func index(before i: MinimalIndex) -> MinimalIndex {
1734+
// FIXME: swift-3-indexing-model: perform a range check and use
1735+
// return _uncheckedIndex(forPosition: i.position - 1)
1736+
return _index(forPosition: i.position - 1)
1737+
}
1738+
1739+
public func distance(from start: MinimalIndex, to end: MinimalIndex)
1740+
-> Int {
1741+
// FIXME: swift-3-indexing-model: perform a range check properly.
1742+
if start != endIndex {
1743+
_failEarlyRangeCheck(start, bounds: startIndex..<endIndex)
1744+
}
1745+
if end != endIndex {
1746+
_failEarlyRangeCheck(end, bounds: startIndex..<endIndex)
1747+
}
1748+
return end.position - start.position
1749+
}
1750+
1751+
public func index(_ i: Index, offsetBy n: Int) -> Index {
1752+
// FIXME: swift-3-indexing-model: perform a range check properly.
1753+
if i != endIndex {
1754+
_failEarlyRangeCheck(i, bounds: startIndex..<endIndex)
1755+
}
1756+
return _index(forPosition: i.position + n)
1757+
}
1758+
1759+
public subscript(i: MinimalIndex) -> T {
1760+
get {
1761+
_failEarlyRangeCheck(i, bounds: startIndex..<endIndex)
1762+
return _elements[i.position]
1763+
}
1764+
}
1765+
1766+
public subscript(bounds: Range<MinimalIndex>) -> Slice<MinimalBidirectionalRandomAccessCollection<T>> {
1767+
get {
1768+
_failEarlyRangeCheck(bounds, bounds: startIndex..<endIndex)
1769+
return Slice(base: self, bounds: bounds)
1770+
}
1771+
}
1772+
1773+
1774+
public var underestimatedCount: Int
1775+
1776+
internal var _elements: [T]
1777+
internal let _collectionState: _CollectionState
1778+
}
16181779

16191780
/// A minimal implementation of `Collection` with extra checks.
16201781
public struct MinimalRangeReplaceableBidirectionalCollection<T> : BidirectionalCollection, RangeReplaceableCollection {

stdlib/public/core/Algorithm.swift

Lines changed: 0 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -74,91 +74,3 @@ public func max<T: Comparable>(_ x: T, _ y: T, _ z: T, _ rest: T...) -> T {
7474
}
7575
return maxValue
7676
}
77-
78-
/// An enumeration of the elements of a sequence or collection.
79-
///
80-
/// `EnumeratedSequence` is a sequence of pairs (*n*, *x*), where *n*s are
81-
/// consecutive `Int` values starting at zero, and *x*s are the elements of a
82-
/// base sequence.
83-
///
84-
/// To create an instance of `EnumeratedSequence`, call `enumerated()` on a
85-
/// sequence or collection. The following example enumerates the elements of
86-
/// an array.
87-
///
88-
/// var s = ["foo", "bar"].enumerated()
89-
/// for (n, x) in s {
90-
/// print("\(n): \(x)")
91-
/// }
92-
/// // Prints "0: foo"
93-
/// // Prints "1: bar"
94-
@frozen
95-
public struct EnumeratedSequence<Base: Sequence> {
96-
@usableFromInline
97-
internal var _base: Base
98-
99-
/// Construct from a `Base` sequence.
100-
@inlinable
101-
internal init(_base: Base) {
102-
self._base = _base
103-
}
104-
}
105-
106-
extension EnumeratedSequence: Sendable where Base: Sendable {}
107-
108-
extension EnumeratedSequence {
109-
/// The iterator for `EnumeratedSequence`.
110-
///
111-
/// An instance of this iterator wraps a base iterator and yields
112-
/// successive `Int` values, starting at zero, along with the elements of the
113-
/// underlying base iterator. The following example enumerates the elements of
114-
/// an array:
115-
///
116-
/// var iterator = ["foo", "bar"].enumerated().makeIterator()
117-
/// iterator.next() // (0, "foo")
118-
/// iterator.next() // (1, "bar")
119-
/// iterator.next() // nil
120-
///
121-
/// To create an instance, call
122-
/// `enumerated().makeIterator()` on a sequence or collection.
123-
@frozen
124-
public struct Iterator {
125-
@usableFromInline
126-
internal var _base: Base.Iterator
127-
@usableFromInline
128-
internal var _count: Int
129-
130-
/// Construct from a `Base` iterator.
131-
@inlinable
132-
internal init(_base: Base.Iterator) {
133-
self._base = _base
134-
self._count = 0
135-
}
136-
}
137-
}
138-
139-
extension EnumeratedSequence.Iterator: Sendable where Base.Iterator: Sendable {}
140-
141-
extension EnumeratedSequence.Iterator: IteratorProtocol, Sequence {
142-
/// The type of element returned by `next()`.
143-
public typealias Element = (offset: Int, element: Base.Element)
144-
145-
/// Advances to the next element and returns it, or `nil` if no next element
146-
/// exists.
147-
///
148-
/// Once `nil` has been returned, all subsequent calls return `nil`.
149-
@inlinable
150-
public mutating func next() -> Element? {
151-
guard let b = _base.next() else { return nil }
152-
let result = (offset: _count, element: b)
153-
_count += 1
154-
return result
155-
}
156-
}
157-
158-
extension EnumeratedSequence: Sequence {
159-
/// Returns an iterator over the elements of this sequence.
160-
@inlinable
161-
public __consuming func makeIterator() -> Iterator {
162-
return Iterator(_base: _base.makeIterator())
163-
}
164-
}

stdlib/public/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ split_embedded_sources(
7676
EMBEDDED DropWhile.swift
7777
NORMAL Dump.swift
7878
EMBEDDED EmptyCollection.swift
79+
EMBEDDED EnumeratedSequence.swift
7980
EMBEDDED Equatable.swift
8081
EMBEDDED ErrorType.swift
8182
EMBEDDED ExistentialCollection.swift

0 commit comments

Comments
 (0)