github.com/bir3/gocompiler@v0.9.2202/extra/compress/fse/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 fse 7 8 import "fmt" 9 10 // bitWriter will write bits. 11 // First bit will be LSB of the first byte of output. 12 type bitWriter struct { 13 bitContainer uint64 14 nBits uint8 15 out []byte 16 } 17 18 // bitMask16 is bitmasks. Has extra to avoid bounds check. 19 var bitMask16 = [32]uint16{ 20 0, 1, 3, 7, 0xF, 0x1F, 21 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 22 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0xFFFF, 23 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 24 0xFFFF, 0xFFFF} /* up to 16 bits */ 25 26 // addBits16NC will add up to 16 bits. 27 // It will not check if there is space for them, 28 // so the caller must ensure that it has flushed recently. 29 func (b *bitWriter) addBits16NC(value uint16, bits uint8) { 30 b.bitContainer |= uint64(value&bitMask16[bits&31]) << (b.nBits & 63) 31 b.nBits += bits 32 } 33 34 // addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated. 35 // It will not check if there is space for them, so the caller must ensure that it has flushed recently. 36 func (b *bitWriter) addBits16Clean(value uint16, bits uint8) { 37 b.bitContainer |= uint64(value) << (b.nBits & 63) 38 b.nBits += bits 39 } 40 41 // addBits16ZeroNC will add up to 16 bits. 42 // It will not check if there is space for them, 43 // so the caller must ensure that it has flushed recently. 44 // This is fastest if bits can be zero. 45 func (b *bitWriter) addBits16ZeroNC(value uint16, bits uint8) { 46 if bits == 0 { 47 return 48 } 49 value <<= (16 - bits) & 15 50 value >>= (16 - bits) & 15 51 b.bitContainer |= uint64(value) << (b.nBits & 63) 52 b.nBits += bits 53 } 54 55 // flush will flush all pending full bytes. 56 // There will be at least 56 bits available for writing when this has been called. 57 // Using flush32 is faster, but leaves less space for writing. 58 func (b *bitWriter) flush() { 59 v := b.nBits >> 3 60 switch v { 61 case 0: 62 case 1: 63 b.out = append(b.out, 64 byte(b.bitContainer), 65 ) 66 case 2: 67 b.out = append(b.out, 68 byte(b.bitContainer), 69 byte(b.bitContainer>>8), 70 ) 71 case 3: 72 b.out = append(b.out, 73 byte(b.bitContainer), 74 byte(b.bitContainer>>8), 75 byte(b.bitContainer>>16), 76 ) 77 case 4: 78 b.out = append(b.out, 79 byte(b.bitContainer), 80 byte(b.bitContainer>>8), 81 byte(b.bitContainer>>16), 82 byte(b.bitContainer>>24), 83 ) 84 case 5: 85 b.out = append(b.out, 86 byte(b.bitContainer), 87 byte(b.bitContainer>>8), 88 byte(b.bitContainer>>16), 89 byte(b.bitContainer>>24), 90 byte(b.bitContainer>>32), 91 ) 92 case 6: 93 b.out = append(b.out, 94 byte(b.bitContainer), 95 byte(b.bitContainer>>8), 96 byte(b.bitContainer>>16), 97 byte(b.bitContainer>>24), 98 byte(b.bitContainer>>32), 99 byte(b.bitContainer>>40), 100 ) 101 case 7: 102 b.out = append(b.out, 103 byte(b.bitContainer), 104 byte(b.bitContainer>>8), 105 byte(b.bitContainer>>16), 106 byte(b.bitContainer>>24), 107 byte(b.bitContainer>>32), 108 byte(b.bitContainer>>40), 109 byte(b.bitContainer>>48), 110 ) 111 case 8: 112 b.out = append(b.out, 113 byte(b.bitContainer), 114 byte(b.bitContainer>>8), 115 byte(b.bitContainer>>16), 116 byte(b.bitContainer>>24), 117 byte(b.bitContainer>>32), 118 byte(b.bitContainer>>40), 119 byte(b.bitContainer>>48), 120 byte(b.bitContainer>>56), 121 ) 122 default: 123 panic(fmt.Errorf("bits (%d) > 64", b.nBits)) 124 } 125 b.bitContainer >>= v << 3 126 b.nBits &= 7 127 } 128 129 // flush32 will flush out, so there are at least 32 bits available for writing. 130 func (b *bitWriter) flush32() { 131 if b.nBits < 32 { 132 return 133 } 134 b.out = append(b.out, 135 byte(b.bitContainer), 136 byte(b.bitContainer>>8), 137 byte(b.bitContainer>>16), 138 byte(b.bitContainer>>24)) 139 b.nBits -= 32 140 b.bitContainer >>= 32 141 } 142 143 // flushAlign will flush remaining full bytes and align to next byte boundary. 144 func (b *bitWriter) flushAlign() { 145 nbBytes := (b.nBits + 7) >> 3 146 for i := uint8(0); i < nbBytes; i++ { 147 b.out = append(b.out, byte(b.bitContainer>>(i*8))) 148 } 149 b.nBits = 0 150 b.bitContainer = 0 151 } 152 153 // close will write the alignment bit and write the final byte(s) 154 // to the output. 155 func (b *bitWriter) close() error { 156 // End mark 157 b.addBits16Clean(1, 1) 158 // flush until next byte. 159 b.flushAlign() 160 return nil 161 } 162 163 // reset and continue writing by appending to out. 164 func (b *bitWriter) reset(out []byte) { 165 b.bitContainer = 0 166 b.nBits = 0 167 b.out = out 168 }