@@ -271,7 +271,7 @@ public struct ChunkedByCount<Base: Collection> {
271271 internal let chunkCount : Int
272272
273273 @usableFromInline
274- internal var computedStartIndex : Index
274+ internal var startUpperBound : Base . Index
275275
276276 /// Creates a view instance that presents the elements of `base`
277277 /// in `SubSequence` chunks of the given count.
@@ -284,13 +284,10 @@ public struct ChunkedByCount<Base: Collection> {
284284
285285 // Compute the start index upfront in order to make
286286 // start index a O(1) lookup.
287- let baseEnd = _base. index (
287+ self . startUpperBound = _base. index (
288288 _base. startIndex, offsetBy: _chunkCount,
289289 limitedBy: _base. endIndex
290290 ) ?? _base. endIndex
291-
292- self . computedStartIndex =
293- Index ( _baseRange: _base. startIndex..< baseEnd)
294291 }
295292}
296293
@@ -307,7 +304,9 @@ extension ChunkedByCount: Collection {
307304
308305 /// - Complexity: O(1)
309306 @inlinable
310- public var startIndex : Index { computedStartIndex }
307+ public var startIndex : Index {
308+ Index ( _baseRange: base. startIndex..< startUpperBound)
309+ }
311310 @inlinable
312311 public var endIndex : Index {
313312 Index ( _baseRange: base. endIndex..< base. endIndex)
@@ -331,6 +330,12 @@ extension ChunkedByCount: Collection {
331330}
332331
333332extension ChunkedByCount . Index : Comparable {
333+ @inlinable
334+ public static func == ( lhs: ChunkedByCount . Index ,
335+ rhs: ChunkedByCount . Index ) -> Bool {
336+ lhs. baseRange. lowerBound == rhs. baseRange. lowerBound
337+ }
338+
334339 @inlinable
335340 public static func < ( lhs: ChunkedByCount . Index ,
336341 rhs: ChunkedByCount . Index ) -> Bool {
@@ -359,6 +364,25 @@ where Base: RandomAccessCollection {
359364 ) ?? base. startIndex
360365 return Index ( _baseRange: baseIdx..< i. baseRange. lowerBound)
361366 }
367+ }
368+
369+ extension ChunkedByCount {
370+ @inlinable
371+ public func distance( from start: Index , to end: Index ) -> Int {
372+ let distance =
373+ base. distance ( from: start. baseRange. lowerBound,
374+ to: end. baseRange. lowerBound)
375+ let ( quotient, remainder) =
376+ distance. quotientAndRemainder ( dividingBy: chunkCount)
377+ return quotient + remainder. signum ( )
378+ }
379+
380+ @inlinable
381+ public var count : Int {
382+ let ( quotient, remainder) =
383+ base. count. quotientAndRemainder ( dividingBy: chunkCount)
384+ return quotient + remainder. signum ( )
385+ }
362386
363387 @inlinable
364388 public func index(
@@ -391,72 +415,51 @@ where Base: RandomAccessCollection {
391415
392416 @usableFromInline
393417 internal func offsetForward( _ i: Index , offsetBy distance: Int ) -> Index {
418+ assert ( distance > 0 )
394419 return makeOffsetIndex (
395- from: i, baseBound: base. endIndex, distance : distance
420+ from: i, baseBound: base. endIndex, baseDistance : distance * chunkCount
396421 )
397422 }
398423
399424 @usableFromInline
400425 internal func offsetBackward( _ i: Index , offsetBy distance: Int ) -> Index {
401- var idx = i
402- var distance = distance
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- // since all remaining chunks have the same size.
426+ assert ( distance < 0 )
408427 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
428+ let remainder = base. count% chunkCount
429+ // We have to take it into account when calculating offsets.
430+ if remainder != 0 {
431+ // Distance "minus" one(at this point distance is negative) because we
432+ // need to adjust for the last position that have a variadic(remainder)
433+ // number of elements.
434+ let baseDistance = ( ( distance + 1 ) * chunkCount) - remainder
435+ return makeOffsetIndex (
436+ from: i, baseBound: base. startIndex, baseDistance: baseDistance
437+ )
414438 }
415439 }
416-
417440 return makeOffsetIndex (
418- from: idx , baseBound: base. startIndex, distance : distance
441+ from: i , baseBound: base. startIndex, baseDistance : distance * chunkCount
419442 )
420443 }
421444
422445 // Helper to compute index(offsetBy:) index.
423446 @inline ( __always)
424447 private func makeOffsetIndex(
425- from i: Index , baseBound: Base . Index , distance : Int
448+ from i: Index , baseBound: Base . Index , baseDistance : Int
426449 ) -> Index {
427450 let baseStartIdx = base. index (
428- i. baseRange. lowerBound, offsetBy: distance * chunkCount ,
451+ i. baseRange. lowerBound, offsetBy: baseDistance ,
429452 limitedBy: baseBound
430453 ) ?? baseBound
431454
432455 let baseEndIdx = base. index (
433- i. baseRange. lowerBound, offsetBy: ( distance + 1 ) * chunkCount,
434- limitedBy: base. endIndex
456+ baseStartIdx, offsetBy: chunkCount, limitedBy: base. endIndex
435457 ) ?? base. endIndex
436458
437459 return Index ( _baseRange: baseStartIdx..< baseEndIdx)
438460 }
439461}
440462
441- extension ChunkedByCount {
442- @inlinable
443- public func distance( from start: Index , to end: Index ) -> Int {
444- let distance =
445- base. distance ( from: start. baseRange. lowerBound,
446- to: end. baseRange. lowerBound)
447- let ( quotient, remainder) =
448- distance. quotientAndRemainder ( dividingBy: chunkCount)
449- return quotient + remainder. signum ( )
450- }
451-
452- @inlinable
453- public var count : Int {
454- let ( quotient, remainder) =
455- base. count. quotientAndRemainder ( dividingBy: chunkCount)
456- return quotient + remainder. signum ( )
457- }
458- }
459-
460463extension Collection {
461464 /// Returns a `ChunkedCollection<Self>` view presenting the elements
462465 /// in chunks with count of the given count parameter.
0 commit comments