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  }