github.com/bir3/gocompiler@v0.9.2202/extra/compress/huff0/bitwriter.go (about) 1 // Copyright 2018 Klaus Post. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 // Based on work Copyright (c) 2013, Yann Collet, released under BSD License. 5 6 package huff0 7 8 // bitWriter will write bits. 9 // First bit will be LSB of the first byte of output. 10 type bitWriter struct { 11 bitContainer uint64 12 nBits uint8 13 out []byte 14 } 15 16 // bitMask16 is bitmasks. Has extra to avoid bounds check. 17 var bitMask16 = [32]uint16{ 18 0, 1, 3, 7, 0xF, 0x1F, 19 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 20 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0xFFFF, 21 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 22 0xFFFF, 0xFFFF} /* up to 16 bits */ 23 24 // addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated. 25 // It will not check if there is space for them, so the caller must ensure that it has flushed recently. 26 func (b *bitWriter) addBits16Clean(value uint16, bits uint8) { 27 b.bitContainer |= uint64(value) << (b.nBits & 63) 28 b.nBits += bits 29 } 30 31 // encSymbol will add up to 16 bits. value may not contain more set bits than indicated. 32 // It will not check if there is space for them, so the caller must ensure that it has flushed recently. 33 func (b *bitWriter) encSymbol(ct cTable, symbol byte) { 34 enc := ct[symbol] 35 b.bitContainer |= uint64(enc.val) << (b.nBits & 63) 36 if false { 37 if enc.nBits == 0 { 38 panic("nbits 0") 39 } 40 } 41 b.nBits += enc.nBits 42 } 43 44 // encTwoSymbols will add up to 32 bits. value may not contain more set bits than indicated. 45 // It will not check if there is space for them, so the caller must ensure that it has flushed recently. 46 func (b *bitWriter) encTwoSymbols(ct cTable, av, bv byte) { 47 encA := ct[av] 48 encB := ct[bv] 49 sh := b.nBits & 63 50 combined := uint64(encA.val) | (uint64(encB.val) << (encA.nBits & 63)) 51 b.bitContainer |= combined << sh 52 if false { 53 if encA.nBits == 0 { 54 panic("nbitsA 0") 55 } 56 if encB.nBits == 0 { 57 panic("nbitsB 0") 58 } 59 } 60 b.nBits += encA.nBits + encB.nBits 61 } 62 63 // encFourSymbols adds up to 32 bits from four symbols. 64 // It will not check if there is space for them, 65 // so the caller must ensure that b has been flushed recently. 66 func (b *bitWriter) encFourSymbols(encA, encB, encC, encD cTableEntry) { 67 bitsA := encA.nBits 68 bitsB := bitsA + encB.nBits 69 bitsC := bitsB + encC.nBits 70 bitsD := bitsC + encD.nBits 71 combined := uint64(encA.val) | 72 (uint64(encB.val) << (bitsA & 63)) | 73 (uint64(encC.val) << (bitsB & 63)) | 74 (uint64(encD.val) << (bitsC & 63)) 75 b.bitContainer |= combined << (b.nBits & 63) 76 b.nBits += bitsD 77 } 78 79 // flush32 will flush out, so there are at least 32 bits available for writing. 80 func (b *bitWriter) flush32() { 81 if b.nBits < 32 { 82 return 83 } 84 b.out = append(b.out, 85 byte(b.bitContainer), 86 byte(b.bitContainer>>8), 87 byte(b.bitContainer>>16), 88 byte(b.bitContainer>>24)) 89 b.nBits -= 32 90 b.bitContainer >>= 32 91 } 92 93 // flushAlign will flush remaining full bytes and align to next byte boundary. 94 func (b *bitWriter) flushAlign() { 95 nbBytes := (b.nBits + 7) >> 3 96 for i := uint8(0); i < nbBytes; i++ { 97 b.out = append(b.out, byte(b.bitContainer>>(i*8))) 98 } 99 b.nBits = 0 100 b.bitContainer = 0 101 } 102 103 // close will write the alignment bit and write the final byte(s) 104 // to the output. 105 func (b *bitWriter) close() error { 106 // End mark 107 b.addBits16Clean(1, 1) 108 // flush until next byte. 109 b.flushAlign() 110 return nil 111 }