github.com/bir3/gocompiler@v0.9.2202/extra/compress/zstd/enc_base.go (about)

     1  package zstd
     2  
     3  import (
     4  	"fmt"
     5  	"math/bits"
     6  
     7  	"github.com/bir3/gocompiler/extra/compress/zstd/internal/xxhash"
     8  )
     9  
    10  const (
    11  	dictShardBits = 6
    12  )
    13  
    14  type fastBase struct {
    15  	// cur is the offset at the start of hist
    16  	cur int32
    17  	// maximum offset. Should be at least 2x block size.
    18  	maxMatchOff int32
    19  	bufferReset int32
    20  	hist        []byte
    21  	crc         *xxhash.Digest
    22  	tmp         [8]byte
    23  	blk         *blockEnc
    24  	lastDictID  uint32
    25  	lowMem      bool
    26  }
    27  
    28  // CRC returns the underlying CRC writer.
    29  func (e *fastBase) CRC() *xxhash.Digest {
    30  	return e.crc
    31  }
    32  
    33  // AppendCRC will append the CRC to the destination slice and return it.
    34  func (e *fastBase) AppendCRC(dst []byte) []byte {
    35  	crc := e.crc.Sum(e.tmp[:0])
    36  	dst = append(dst, crc[7], crc[6], crc[5], crc[4])
    37  	return dst
    38  }
    39  
    40  // WindowSize returns the window size of the encoder,
    41  // or a window size small enough to contain the input size, if > 0.
    42  func (e *fastBase) WindowSize(size int64) int32 {
    43  	if size > 0 && size < int64(e.maxMatchOff) {
    44  		b := int32(1) << uint(bits.Len(uint(size)))
    45  		// Keep minimum window.
    46  		if b < 1024 {
    47  			b = 1024
    48  		}
    49  		return b
    50  	}
    51  	return e.maxMatchOff
    52  }
    53  
    54  // Block returns the current block.
    55  func (e *fastBase) Block() *blockEnc {
    56  	return e.blk
    57  }
    58  
    59  func (e *fastBase) addBlock(src []byte) int32 {
    60  	if debugAsserts && e.cur > e.bufferReset {
    61  		panic(fmt.Sprintf("ecur (%d) > buffer reset (%d)", e.cur, e.bufferReset))
    62  	}
    63  	// check if we have space already
    64  	if len(e.hist)+len(src) > cap(e.hist) {
    65  		if cap(e.hist) == 0 {
    66  			e.ensureHist(len(src))
    67  		} else {
    68  			if cap(e.hist) < int(e.maxMatchOff+maxCompressedBlockSize) {
    69  				panic(fmt.Errorf("unexpected buffer cap %d, want at least %d with window %d", cap(e.hist), e.maxMatchOff+maxCompressedBlockSize, e.maxMatchOff))
    70  			}
    71  			// Move down
    72  			offset := int32(len(e.hist)) - e.maxMatchOff
    73  			copy(e.hist[0:e.maxMatchOff], e.hist[offset:])
    74  			e.cur += offset
    75  			e.hist = e.hist[:e.maxMatchOff]
    76  		}
    77  	}
    78  	s := int32(len(e.hist))
    79  	e.hist = append(e.hist, src...)
    80  	return s
    81  }
    82  
    83  // ensureHist will ensure that history can keep at least this many bytes.
    84  func (e *fastBase) ensureHist(n int) {
    85  	if cap(e.hist) >= n {
    86  		return
    87  	}
    88  	l := e.maxMatchOff
    89  	if (e.lowMem && e.maxMatchOff > maxCompressedBlockSize) || e.maxMatchOff <= maxCompressedBlockSize {
    90  		l += maxCompressedBlockSize
    91  	} else {
    92  		l += e.maxMatchOff
    93  	}
    94  	// Make it at least 1MB.
    95  	if l < 1<<20 && !e.lowMem {
    96  		l = 1 << 20
    97  	}
    98  	// Make it at least the requested size.
    99  	if l < int32(n) {
   100  		l = int32(n)
   101  	}
   102  	e.hist = make([]byte, 0, l)
   103  }
   104  
   105  // useBlock will replace the block with the provided one,
   106  // but transfer recent offsets from the previous.
   107  func (e *fastBase) UseBlock(enc *blockEnc) {
   108  	enc.reset(e.blk)
   109  	e.blk = enc
   110  }
   111  
   112  func (e *fastBase) matchlen(s, t int32, src []byte) int32 {
   113  	if debugAsserts {
   114  		if s < 0 {
   115  			err := fmt.Sprintf("s (%d) < 0", s)
   116  			panic(err)
   117  		}
   118  		if t < 0 {
   119  			err := fmt.Sprintf("s (%d) < 0", s)
   120  			panic(err)
   121  		}
   122  		if s-t > e.maxMatchOff {
   123  			err := fmt.Sprintf("s (%d) - t (%d) > maxMatchOff (%d)", s, t, e.maxMatchOff)
   124  			panic(err)
   125  		}
   126  		if len(src)-int(s) > maxCompressedBlockSize {
   127  			panic(fmt.Sprintf("len(src)-s (%d) > maxCompressedBlockSize (%d)", len(src)-int(s), maxCompressedBlockSize))
   128  		}
   129  	}
   130  	return int32(matchLen(src[s:], src[t:]))
   131  }
   132  
   133  // Reset the encoding table.
   134  func (e *fastBase) resetBase(d *dict, singleBlock bool) {
   135  	if e.blk == nil {
   136  		e.blk = &blockEnc{lowMem: e.lowMem}
   137  		e.blk.init()
   138  	} else {
   139  		e.blk.reset(nil)
   140  	}
   141  	e.blk.initNewEncode()
   142  	if e.crc == nil {
   143  		e.crc = xxhash.New()
   144  	} else {
   145  		e.crc.Reset()
   146  	}
   147  	if d != nil {
   148  		low := e.lowMem
   149  		if singleBlock {
   150  			e.lowMem = true
   151  		}
   152  		e.ensureHist(d.ContentSize() + maxCompressedBlockSize)
   153  		e.lowMem = low
   154  	}
   155  
   156  	// We offset current position so everything will be out of reach.
   157  	// If above reset line, history will be purged.
   158  	if e.cur < e.bufferReset {
   159  		e.cur += e.maxMatchOff + int32(len(e.hist))
   160  	}
   161  	e.hist = e.hist[:0]
   162  	if d != nil {
   163  		// Set offsets (currently not used)
   164  		for i, off := range d.offsets {
   165  			e.blk.recentOffsets[i] = uint32(off)
   166  			e.blk.prevRecentOffsets[i] = e.blk.recentOffsets[i]
   167  		}
   168  		// Transfer litenc.
   169  		e.blk.dictLitEnc = d.litEnc
   170  		e.hist = append(e.hist, d.content...)
   171  	}
   172  }