Skip to content

Commit 8c98e2d

Browse files
committed
indexOrNil & formIndexOrNil
1 parent a390691 commit 8c98e2d

File tree

1 file changed

+74
-0
lines changed

1 file changed

+74
-0
lines changed

Sources/SafeCollectionAccess/Safe Collection Access.swift

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,77 @@ public extension RandomAccessCollection {
167167
}
168168
}
169169
}
170+
171+
172+
173+
// MARK: - `nil` or `index(before:)`/`index(after:)`
174+
175+
public extension BidirectionalCollection {
176+
177+
/// Returns the position immediately after the given index, or `nil` if there is none.
178+
///
179+
/// The successor of an index must be well defined. For an index `i` into an immutable
180+
/// collection `c`, calling `c.index(after: i)` returns the same index every
181+
/// time.
182+
///
183+
/// - Parameter i: An index of the collection.
184+
/// - Returns: The index value immediately after `i`, or `nil` if such an index wouldn't be in the collection.
185+
func indexOrNil(after i: Index) -> Index? {
186+
guard i < endIndex else { return nil }
187+
return index(after: i)
188+
}
189+
190+
191+
/// Replaces the given index with its successor, or `nil` if there is none.
192+
///
193+
/// `i` is set to `nil` if the resulting index wouldn't be in the collection.
194+
///
195+
/// - Parameter i: An index of the collection.
196+
func formIndexOrNil(after i: inout Index?) {
197+
guard let nonNilIndex = i else { return }
198+
i = indexOrNil(after: nonNilIndex)
199+
}
200+
201+
202+
/// Returns the position immediately before the given index, or `nil` if there is none.
203+
///
204+
/// - Parameter i: An index of the collection.
205+
/// - Returns: The index value immediately before `i`, or `nil` if such an index wouldn't be in the collection.
206+
func indexOrNil(before i: Index) -> Index? {
207+
guard i > startIndex else { return nil }
208+
return index(before: i)
209+
}
210+
211+
212+
/// Replaces the given index with its predecessor, or `nil` if there is none.
213+
///
214+
/// `i` is set to `nil` if the resulting index wouldn't be in the collection.
215+
///
216+
/// - Parameter i: An index of the collection.
217+
func formIndexOrNil(before i: inout Index?) {
218+
guard let nonNilIndex = i else { return }
219+
i = indexOrNil(before: nonNilIndex)
220+
}
221+
222+
223+
/// Returns an index that is the specified distance from the given index, or `nil` if there isn't one.
224+
///
225+
/// - Parameters:
226+
/// - i: A valid index of the collection.
227+
/// - distance: The distance to offset `i`. `distance` must not be negative unless the collection conforms to the `BidirectionalCollection` protocol.
228+
/// - Returns: An index offset by `distance` from the index `i`.
229+
/// If `distance` is positive, this is the same value as the result of `distance` calls to `index(after:)`.
230+
/// If `distance` is negative, this is the same value as the result of `abs(distance)` calls to `index(before:)`.
231+
/// If the index which would be `distance` from `i` would lie outside this collection, this returns `nil`.
232+
func indexOrNil(_ i: Index, offsetBy distance: Int) -> Index? {
233+
if distance > 0 {
234+
index(i, offsetBy: distance, limitedBy: endIndex)
235+
}
236+
else if distance < 0 {
237+
index(i, offsetBy: distance, limitedBy: startIndex)
238+
}
239+
else {
240+
i
241+
}
242+
}
243+
}

0 commit comments

Comments
 (0)