File: LEB.swift

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (83 lines) | stat: -rw-r--r-- 2,615 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
@usableFromInline
enum LEBError: Swift.Error, Equatable {
    case overflow
    case integerRepresentationTooLong
    case insufficientBytes
}

@inlinable
func decodeLEB128<IntType, Stream>(
    stream: Stream
) throws -> IntType where IntType: FixedWidthInteger, IntType: UnsignedInteger, Stream: ByteStream {
    let firstByte = try stream.consumeAny()
    var result: IntType = IntType(firstByte & 0b0111_1111)
    if _fastPath(firstByte & 0b1000_0000 == 0) {
        return result
    }

    var shift: UInt = 7

    while true {
        let byte = try stream.consumeAny()
        let slice = IntType(byte & 0b0111_1111)
        let nextShift = shift + 7
        if nextShift >= IntType.bitWidth, (byte >> (UInt(IntType.bitWidth) - shift)) != 0 {
            throw LEBError.integerRepresentationTooLong
        }
        result |= slice << shift
        shift = nextShift

        guard byte & 0b1000_0000 != 0 else { break }
    }

    return result
}

@inlinable
func decodeLEB128<IntType, Stream>(
    stream: Stream, bitWidth: Int = IntType.bitWidth
) throws -> IntType where IntType: FixedWidthInteger, IntType: RawSignedInteger, Stream: ByteStream {
    let firstByte = try stream.consumeAny()
    var result = IntType.Unsigned(firstByte & 0b0111_1111)
    if _fastPath(firstByte & 0b1000_0000 == 0) {
        // Interpret Int${Self.bitWidth-1} as Int${Self.bitWidth}
        return (IntType(bitPattern: result) << (IntType.bitWidth - 7)) >> (IntType.bitWidth - 7)
    }

    var shift: IntType = 7

    var byte: UInt8
    repeat {
        byte = try stream.consumeAny()

        let slice = IntType.Unsigned(byte & 0b0111_1111)
        result |= slice << shift

        // When we don't have enough bit width
        if shift > (bitWidth - 7) {
            let remainingBitWidth = bitWidth - Int(shift)
            let continuationBit = (byte & 0b1000_0000) != 0
            // When a next byte is expected
            if continuationBit {
                throw LEBError.integerRepresentationTooLong
            }

            let signAndDiscardingBits = Int8(bitPattern: byte << 1) >> remainingBitWidth
            // When meaningful bits are discarded
            if signAndDiscardingBits != 0 && signAndDiscardingBits != -1 {
                throw LEBError.overflow
            }
            return IntType(bitPattern: result)
        }

        shift += 7
    } while byte & 0b1000_0000 != 0

    // Sign flag is second high-order bit
    if byte & 0b0100_0000 != 0 {
        // Sign extend
        result |= IntType.Unsigned(bitPattern: ~0) << shift
    }

    return IntType(bitPattern: result)
}