Repository: danielgindi/Charts
File: Source/Charts/Renderers/LineChartRenderer.swift (Swift)

Code before:
        _xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator)
        
        // if drawing filled is enabled
        if dataSet.isDrawFilledEnabled && entryCount > 0
        {
            drawLinearFill(context: context, dataSet: dataSet, trans: trans, bounds: _xBounds)
        }
        
        context.saveGState()

            if _lineSegments.count != pointsPerEntryPair
            {
                // Allocate once in correct size
                _lineSegments = [CGPoint](repeating: CGPoint(), count: pointsPerEntryPair)
            }
            
        for j in stride(from: _xBounds.min, through: _xBounds.range + _xBounds.min, by: 1)
        {
            var e: ChartDataEntry! = dataSet.entryForIndex(j)
            
            if e == nil { continue }
            
            _lineSegments[0].x = CGFloat(e.x)
            _lineSegments[0].y = CGFloat(e.y * phaseY)
            
            if j < _xBounds.max
            {
                e = dataSet.entryForIndex(j + 1)
                
                if e == nil { break }
                
                if isDrawSteppedEnabled
                {
                    _lineSegments[1] = CGPoint(x: CGFloat(e.x), y: _lineSegments[0].y)
                    _lineSegments[2] = _lineSegments[1]
                    _lineSegments[3] = CGPoint(x: CGFloat(e.x), y: CGFloat(e.y * phaseY))
                }
                else
                {
                    _lineSegments[1] = CGPoint(x: CGFloat(e.x), y: CGFloat(e.y * phaseY))
                }
            }
            else
            {
                _lineSegments[1] = _lineSegments[0]
            }

            for i in 0..<_lineSegments.count
            {
                _lineSegments[i] = _lineSegments[i].applying(valueToPixelMatrix)
            }

Review comment (bug):
This is somewhat incorrect, and the iterator in `XBounds` is theoretically incorrect.
As the point is to iterate through `min + range` - where range *could* go over `max` due to a bouncing animation or something similar.

The thing is that this `XBounds` represents (in all current cases) a range of entries, and going over `max` could mean an `IndexOutOfBounds`.
That's why the check is there.

If the iterator only iterates until `max` - then it's a bug and it's not respecting the animation (range is basically `(max - min) * animation.PhaseX`). 

Also I would change the iterator's `fileprivate init(min: Int, max: Int) {` to `fileprivate init(min: Int, through: Int) {`, as it's really confusing right now, both with the `max` property and with `to vs through` semantics.

Code after:
        // if drawing filled is enabled
        if dataSet.isDrawFilledEnabled && entryCount > 0
        {
            drawLinearFill(context: context, dataSet: dataSet, trans: trans, bounds: _xBounds)
        }
        
        context.saveGState()

            if _lineSegments.count != pointsPerEntryPair
            {
                // Allocate once in correct size
                _lineSegments = [CGPoint](repeating: CGPoint(), count: pointsPerEntryPair)
            }

        for j in _xBounds.dropLast()
        {
            var e: ChartDataEntry! = dataSet.entryForIndex(j)
            
            if e == nil { continue }
            
            _lineSegments[0].x = CGFloat(e.x)
            _lineSegments[0].y = CGFloat(e.y * phaseY)
            
            if j < _xBounds.max
            {
                // TODO: remove the check.
                // With the new XBounds iterator, j is always smaller than _xBounds.max
                // Keeping this check for a while, if xBounds have no further breaking changes, it should be safe to remove the check
                e = dataSet.entryForIndex(j + 1)
                
                if e == nil { break }
                
                if isDrawSteppedEnabled
                {
                    _lineSegments[1] = CGPoint(x: CGFloat(e.x), y: _lineSegments[0].y)
                    _lineSegments[2] = _lineSegments[1]
                    _lineSegments[3] = CGPoint(x: CGFloat(e.x), y: CGFloat(e.y * phaseY))
                }
                else
                {
                    _lineSegments[1] = CGPoint(x: CGFloat(e.x), y: CGFloat(e.y * phaseY))
                }
            }
            else
            {
                _lineSegments[1] = _lineSegments[0]
            }

            for i in 0..<_lineSegments.count
            {
                _lineSegments[i] = _lineSegments[i].applying(valueToPixelMatrix)