A crash when using subscript on a Data instance

Here is some sample code.

extension Data{
    var blah:UInt8?{
        mutating get{
            let partial = self[0]
            guard let fdsa = self[1..<self.count].blif else{
                return nil
            }
            return partial/fdsa
        }
    }
}

extension Data{
    var blif:UInt8?{
        mutating get{
            guard self.count >= 1 else{
                return nil
            }
            let result = self[0]
            self = self[1..<self.count]
            return result
        }
    }
}

When this test is run, let result = self[0] in blif crashes.

func testBlah(){
        var initial = Data([UInt8(12),UInt8(4)])
        let quotient = initial.blah
        XCTAssertEqual(3, quotient)
    }

Why is this, and what would be a better approach?

the 0 and 1..<self.count are not correct for generality of random access collections. Data is it's own slice type so those index parameters should be made in relation to the startIndex and endIndex

3 Likes

So here is a version that works. Apparently it is not only unwise to use mutating getters, but Data slices, being Datas themselves, work a little strangely.

extension Data{
    var qwert:(UInt8,Data)?{
        get{
            let partial = self[0]
            guard let (fdsa,shortenedData) = Data(self[1..<self.count]).fdsa else{
                return nil
            }
            return (partial/fdsa,shortenedData)
        }
    }
}

extension Data{
    var fdsa:(UInt8,Data)?{
        get{
            guard self.count >= 1 else{
                return nil
            }
            let result = self[0]
            return (result,self[1..<self.count])
        }
    }
}


   func testQwert(){
        var initial = Data([UInt8(12),UInt8(4)])
        let (quotient, smaller) = initial.qwert!
        XCTAssertEqual(3, quotient)
        XCTAssertEqual(0, smaller.count)
    }

My experience with Data is that you get into a lot less trouble if you use the various Sequence methods. For example, my reading of fdsa is that you’re trying to split the value into a head element and a tail sequence. For that, I’d do this:

extension Data {
    var fdsa: (UInt8, Data)? {
        guard let first = self.first else { return nil }
        return (first, self.dropFirst())
    }
}

Once you have that, you can make it generic:

extension Collection {
    var fdsa: (Element, SubSequence)? {
        guard let first = self.first else { return nil }
        return (first, self.dropFirst())
    }
}

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

2 Likes