Skip to content

Commit a0f0f0d

Browse files
authored
Merge pull request #18233 from moiseev/bidirectional-decl-4.2
[4.2] Add explicit requirements to Bidirectional and RandomAccessCollection
2 parents cb01e10 + c12b766 commit a0f0f0d

File tree

3 files changed

+271
-0
lines changed

3 files changed

+271
-0
lines changed

stdlib/public/core/BidirectionalCollection.swift

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,116 @@ where SubSequence: BidirectionalCollection, Indices: BidirectionalCollection {
7171
/// `startIndex`.
7272
func formIndex(before i: inout Index)
7373

74+
/// Returns the position immediately after the given index.
75+
///
76+
/// The successor of an index must be well defined. For an index `i` into a
77+
/// collection `c`, calling `c.index(after: i)` returns the same index every
78+
/// time.
79+
///
80+
/// - Parameter i: A valid index of the collection. `i` must be less than
81+
/// `endIndex`.
82+
/// - Returns: The index value immediately after `i`.
83+
func index(after i: Index) -> Index
84+
85+
/// Replaces the given index with its successor.
86+
///
87+
/// - Parameter i: A valid index of the collection. `i` must be less than
88+
/// `endIndex`.
89+
func formIndex(after i: inout Index)
90+
91+
/// Returns an index that is the specified distance from the given index.
92+
///
93+
/// The following example obtains an index advanced four positions from a
94+
/// string's starting index and then prints the character at that position.
95+
///
96+
/// let s = "Swift"
97+
/// let i = s.index(s.startIndex, offsetBy: 4)
98+
/// print(s[i])
99+
/// // Prints "t"
100+
///
101+
/// The value passed as `distance` must not offset `i` beyond the bounds of
102+
/// the collection.
103+
///
104+
/// - Parameters:
105+
/// - i: A valid index of the collection.
106+
/// - distance: The distance to offset `i`. `distance` must not be negative
107+
/// unless the collection conforms to the `BidirectionalCollection`
108+
/// protocol.
109+
/// - Returns: An index offset by `distance` from the index `i`. If
110+
/// `distance` is positive, this is the same value as the result of
111+
/// `distance` calls to `index(after:)`. If `distance` is negative, this
112+
/// is the same value as the result of `abs(distance)` calls to
113+
/// `index(before:)`.
114+
///
115+
/// - Complexity: O(1) if the collection conforms to
116+
/// `RandomAccessCollection`; otherwise, O(*k*), where *k* is the absolute
117+
/// value of `distance`.
118+
func index(_ i: Index, offsetBy distance: Int) -> Index
119+
120+
/// Returns an index that is the specified distance from the given index,
121+
/// unless that distance is beyond a given limiting index.
122+
///
123+
/// The following example obtains an index advanced four positions from a
124+
/// string's starting index and then prints the character at that position.
125+
/// The operation doesn't require going beyond the limiting `s.endIndex`
126+
/// value, so it succeeds.
127+
///
128+
/// let s = "Swift"
129+
/// if let i = s.index(s.startIndex, offsetBy: 4, limitedBy: s.endIndex) {
130+
/// print(s[i])
131+
/// }
132+
/// // Prints "t"
133+
///
134+
/// The next example attempts to retrieve an index six positions from
135+
/// `s.startIndex` but fails, because that distance is beyond the index
136+
/// passed as `limit`.
137+
///
138+
/// let j = s.index(s.startIndex, offsetBy: 6, limitedBy: s.endIndex)
139+
/// print(j)
140+
/// // Prints "nil"
141+
///
142+
/// The value passed as `distance` must not offset `i` beyond the bounds of
143+
/// the collection, unless the index passed as `limit` prevents offsetting
144+
/// beyond those bounds.
145+
///
146+
/// - Parameters:
147+
/// - i: A valid index of the collection.
148+
/// - distance: The distance to offset `i`. `distance` must not be negative
149+
/// unless the collection conforms to the `BidirectionalCollection`
150+
/// protocol.
151+
/// - limit: A valid index of the collection to use as a limit. If
152+
/// `distance > 0`, a limit that is less than `i` has no effect.
153+
/// Likewise, if `distance < 0`, a limit that is greater than `i` has no
154+
/// effect.
155+
/// - Returns: An index offset by `distance` from the index `i`, unless that
156+
/// index would be beyond `limit` in the direction of movement. In that
157+
/// case, the method returns `nil`.
158+
///
159+
/// - Complexity: O(1) if the collection conforms to
160+
/// `RandomAccessCollection`; otherwise, O(*k*), where *k* is the absolute
161+
/// value of `distance`.
162+
func index(
163+
_ i: Index, offsetBy distance: Int, limitedBy limit: Index
164+
) -> Index?
165+
166+
/// Returns the distance between two indices.
167+
///
168+
/// Unless the collection conforms to the `BidirectionalCollection` protocol,
169+
/// `start` must be less than or equal to `end`.
170+
///
171+
/// - Parameters:
172+
/// - start: A valid index of the collection.
173+
/// - end: Another valid index of the collection. If `end` is equal to
174+
/// `start`, the result is zero.
175+
/// - Returns: The distance between `start` and `end`. The result can be
176+
/// negative only if the collection conforms to the
177+
/// `BidirectionalCollection` protocol.
178+
///
179+
/// - Complexity: O(1) if the collection conforms to
180+
/// `RandomAccessCollection`; otherwise, O(*k*), where *k* is the
181+
/// resulting distance.
182+
func distance(from start: Index, to end: Index) -> Int
183+
74184
/// The indices that are valid for subscripting the collection, in ascending
75185
/// order.
76186
///

stdlib/public/core/RandomAccessCollection.swift

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,129 @@ where SubSequence: RandomAccessCollection, Indices: RandomAccessCollection
103103

104104
// FIXME(ABI): Associated type inference requires this.
105105
var endIndex: Index { get }
106+
107+
/// Returns the position immediately before the given index.
108+
///
109+
/// - Parameter i: A valid index of the collection. `i` must be greater than
110+
/// `startIndex`.
111+
/// - Returns: The index value immediately before `i`.
112+
func index(before i: Index) -> Index
113+
114+
/// Replaces the given index with its predecessor.
115+
///
116+
/// - Parameter i: A valid index of the collection. `i` must be greater than
117+
/// `startIndex`.
118+
func formIndex(before i: inout Index)
119+
120+
/// Returns the position immediately after the given index.
121+
///
122+
/// The successor of an index must be well defined. For an index `i` into a
123+
/// collection `c`, calling `c.index(after: i)` returns the same index every
124+
/// time.
125+
///
126+
/// - Parameter i: A valid index of the collection. `i` must be less than
127+
/// `endIndex`.
128+
/// - Returns: The index value immediately after `i`.
129+
func index(after i: Index) -> Index
130+
131+
/// Replaces the given index with its successor.
132+
///
133+
/// - Parameter i: A valid index of the collection. `i` must be less than
134+
/// `endIndex`.
135+
func formIndex(after i: inout Index)
136+
137+
/// Returns an index that is the specified distance from the given index.
138+
///
139+
/// The following example obtains an index advanced four positions from a
140+
/// string's starting index and then prints the character at that position.
141+
///
142+
/// let s = "Swift"
143+
/// let i = s.index(s.startIndex, offsetBy: 4)
144+
/// print(s[i])
145+
/// // Prints "t"
146+
///
147+
/// The value passed as `distance` must not offset `i` beyond the bounds of
148+
/// the collection.
149+
///
150+
/// - Parameters:
151+
/// - i: A valid index of the collection.
152+
/// - distance: The distance to offset `i`. `distance` must not be negative
153+
/// unless the collection conforms to the `BidirectionalCollection`
154+
/// protocol.
155+
/// - Returns: An index offset by `distance` from the index `i`. If
156+
/// `distance` is positive, this is the same value as the result of
157+
/// `distance` calls to `index(after:)`. If `distance` is negative, this
158+
/// is the same value as the result of `abs(distance)` calls to
159+
/// `index(before:)`.
160+
///
161+
/// - Complexity: O(1) if the collection conforms to
162+
/// `RandomAccessCollection`; otherwise, O(*k*), where *k* is the absolute
163+
/// value of `distance`.
164+
func index(_ i: Index, offsetBy distance: Int) -> Index
165+
166+
/// Returns an index that is the specified distance from the given index,
167+
/// unless that distance is beyond a given limiting index.
168+
///
169+
/// The following example obtains an index advanced four positions from a
170+
/// string's starting index and then prints the character at that position.
171+
/// The operation doesn't require going beyond the limiting `s.endIndex`
172+
/// value, so it succeeds.
173+
///
174+
/// let s = "Swift"
175+
/// if let i = s.index(s.startIndex, offsetBy: 4, limitedBy: s.endIndex) {
176+
/// print(s[i])
177+
/// }
178+
/// // Prints "t"
179+
///
180+
/// The next example attempts to retrieve an index six positions from
181+
/// `s.startIndex` but fails, because that distance is beyond the index
182+
/// passed as `limit`.
183+
///
184+
/// let j = s.index(s.startIndex, offsetBy: 6, limitedBy: s.endIndex)
185+
/// print(j)
186+
/// // Prints "nil"
187+
///
188+
/// The value passed as `distance` must not offset `i` beyond the bounds of
189+
/// the collection, unless the index passed as `limit` prevents offsetting
190+
/// beyond those bounds.
191+
///
192+
/// - Parameters:
193+
/// - i: A valid index of the collection.
194+
/// - distance: The distance to offset `i`. `distance` must not be negative
195+
/// unless the collection conforms to the `BidirectionalCollection`
196+
/// protocol.
197+
/// - limit: A valid index of the collection to use as a limit. If
198+
/// `distance > 0`, a limit that is less than `i` has no effect.
199+
/// Likewise, if `distance < 0`, a limit that is greater than `i` has no
200+
/// effect.
201+
/// - Returns: An index offset by `distance` from the index `i`, unless that
202+
/// index would be beyond `limit` in the direction of movement. In that
203+
/// case, the method returns `nil`.
204+
///
205+
/// - Complexity: O(1) if the collection conforms to
206+
/// `RandomAccessCollection`; otherwise, O(*k*), where *k* is the absolute
207+
/// value of `distance`.
208+
func index(
209+
_ i: Index, offsetBy distance: Int, limitedBy limit: Index
210+
) -> Index?
211+
212+
/// Returns the distance between two indices.
213+
///
214+
/// Unless the collection conforms to the `BidirectionalCollection` protocol,
215+
/// `start` must be less than or equal to `end`.
216+
///
217+
/// - Parameters:
218+
/// - start: A valid index of the collection.
219+
/// - end: Another valid index of the collection. If `end` is equal to
220+
/// `start`, the result is zero.
221+
/// - Returns: The distance between `start` and `end`. The result can be
222+
/// negative only if the collection conforms to the
223+
/// `BidirectionalCollection` protocol.
224+
///
225+
/// - Complexity: O(1) if the collection conforms to
226+
/// `RandomAccessCollection`; otherwise, O(*k*), where *k* is the
227+
/// resulting distance.
228+
func distance(from start: Index, to end: Index) -> Int
106229
}
107230

108231
// TODO: swift-3-indexing-model - Make sure RandomAccessCollection has
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %target-run-simple-swift
2+
// REQUIRES: executable_test
3+
4+
5+
struct X: BidirectionalCollection {
6+
var startIndex: Int { return 0 }
7+
var endIndex: Int { return 10 }
8+
subscript(position: Int) -> String { return "element" }
9+
subscript(range: Range<Int>) -> X { return X() }
10+
func index(after i: Int) -> Int { return i + 1 }
11+
func index(before i: Int) -> Int { return i - 1 }
12+
}
13+
struct A<C: Collection>: Collection {
14+
let c: C
15+
var startIndex: C.Index { return c.startIndex }
16+
var endIndex: C.Index { return c.endIndex }
17+
subscript(position: C.Index) -> C.Element { return c[position] }
18+
subscript(range: Range<C.Index>) -> A<C.SubSequence> {
19+
return A<C.SubSequence>(c: c[range])
20+
}
21+
func index(after i: C.Index) -> C.Index { return c.index(after: i) }
22+
}
23+
24+
extension A: BidirectionalCollection where C: BidirectionalCollection {
25+
func index(before i: C.Index) -> C.Index { return c.index(before: i) }
26+
}
27+
28+
// SR-8022
29+
func sr8022() {
30+
var c = A(c: X())
31+
_ = c.popLast()
32+
_ = c.removeLast()
33+
c.removeLast(2)
34+
_ = c.dropLast(2)
35+
_ = c.suffix(2)
36+
}
37+
38+
sr8022()

0 commit comments

Comments
 (0)