@@ -305,13 +305,15 @@ extension ChunkedByCount: Collection {
305
305
}
306
306
}
307
307
308
- /// - Complexity: O(n)
308
+ /// - Complexity: O(1)
309
+ @inlinable
309
310
public var startIndex : Index { computedStartIndex }
311
+ @inlinable
310
312
public var endIndex : Index {
311
313
Index ( _baseRange: base. endIndex..< base. endIndex)
312
314
}
313
315
314
- /// - Complexity: O(n )
316
+ /// - Complexity: O(1 )
315
317
public subscript( i: Index ) -> Element {
316
318
precondition ( i < endIndex, " Index out of range " )
317
319
return base [ i. baseRange]
@@ -358,7 +360,81 @@ where Base: RandomAccessCollection {
358
360
return Index ( _baseRange: baseIdx..< i. baseRange. lowerBound)
359
361
}
360
362
361
- // TODO: index(_:offsetBy:) and index(_:offsetBy:limitedBy:)
363
+ @inlinable
364
+ public func index(
365
+ _ i: Index , offsetBy offset: Int , limitedBy limit: Index
366
+ ) -> Index ? {
367
+ guard offset != 0 else { return i }
368
+ guard limit != i else { return nil }
369
+
370
+ if offset > 0 {
371
+ guard limit <= i || distance ( from: i, to: limit) >= offset else {
372
+ return nil
373
+ }
374
+ return offsetForward ( i, offsetBy: offset)
375
+ } else {
376
+ guard limit >= i || distance ( from: i, to: limit) <= offset else {
377
+ return nil
378
+ }
379
+ return offsetBackward ( i, offsetBy: offset)
380
+ }
381
+ }
382
+
383
+ @inlinable
384
+ public func index( _ i: Index , offsetBy distance: Int ) -> Index {
385
+ guard distance != 0 else { return i }
386
+
387
+ return distance > 0
388
+ ? offsetForward ( i, offsetBy: distance)
389
+ : offsetBackward ( i, offsetBy: distance)
390
+ }
391
+
392
+ @usableFromInline
393
+ internal func offsetForward( _ i: Index , offsetBy distance: Int ) -> Index {
394
+ return makeOffsetIndex (
395
+ from: i, baseBound: base. endIndex, distance: distance
396
+ )
397
+ }
398
+
399
+ @usableFromInline
400
+ internal func offsetBackward( _ i: Index , offsetBy n: Int ) -> Index {
401
+ var idx = i
402
+ var distance = n
403
+ // If we know that the last chunk is the only one that can possible
404
+ // have a variadic count. So in order to simplify and avoid another
405
+ // calculation of offsets(that is already done at `index(before:)`)
406
+ // we just move one position already so the index can be calculated
407
+ // assuming all chunks have the same size.
408
+ if i. baseRange. lowerBound == base. endIndex {
409
+ formIndex ( before: & idx)
410
+ distance += 1
411
+ // If the offset was simply one, we are done.
412
+ guard distance != 0 else {
413
+ return idx
414
+ }
415
+ }
416
+
417
+ return makeOffsetIndex (
418
+ from: idx, baseBound: base. startIndex, distance: distance
419
+ )
420
+ }
421
+
422
+ // Helper to compute index(offsetBy:) index.
423
+ internal func makeOffsetIndex(
424
+ from i: Index , baseBound: Base . Index , distance: Int
425
+ ) -> Index {
426
+ let baseStartIdx = base. index (
427
+ i. baseRange. lowerBound, offsetBy: distance * chunkCount,
428
+ limitedBy: baseBound
429
+ ) ?? baseBound
430
+
431
+ let baseEndIdx = base. index (
432
+ i. baseRange. lowerBound, offsetBy: ( distance + 1 ) * chunkCount,
433
+ limitedBy: base. endIndex
434
+ ) ?? base. endIndex
435
+
436
+ return Index ( _baseRange: baseStartIdx..< baseEndIdx)
437
+ }
362
438
}
363
439
364
440
extension ChunkedByCount {
@@ -399,7 +475,7 @@ extension Collection {
399
475
/// - Complexity: O(1)
400
476
@inlinable
401
477
public func chunks( ofCount count: Int ) -> ChunkedByCount < Self > {
402
- precondition ( count > 0 , " Cannot chunk with count <= 0!" )
478
+ precondition ( count > 0 , " Cannot chunk with count <= 0! " )
403
479
return ChunkedByCount ( _base: self , _chunkCount: count)
404
480
}
405
481
}
0 commit comments