package gozstd import ( "io" "sync" ) // StreamCompress compresses src into dst. // // This function doesn't work with interactive network streams, since data read // from src may be buffered before passing to dst for performance reasons. // Use Writer.Flush for interactive network streams. func StreamCompress(dst io.Writer, src io.Reader) error { return streamCompressDictLevel(dst, src, nil, DefaultCompressionLevel) } // StreamCompressLevel compresses src into dst using the given compressionLevel. // // This function doesn't work with interactive network streams, since data read // from src may be buffered before passing to dst for performance reasons. // Use Writer.Flush for interactive network streams. func StreamCompressLevel(dst io.Writer, src io.Reader, compressionLevel int) error { return streamCompressDictLevel(dst, src, nil, compressionLevel) } // StreamCompressDict compresses src into dst using the given dict cd. // // This function doesn't work with interactive network streams, since data read // from src may be buffered before passing to dst for performance reasons. // Use Writer.Flush for interactive network streams. func StreamCompressDict(dst io.Writer, src io.Reader, cd *CDict) error { return streamCompressDictLevel(dst, src, cd, 0) } func streamCompressDictLevel(dst io.Writer, src io.Reader, cd *CDict, compressionLevel int) error { sc := getSCompressor(compressionLevel) sc.zw.Reset(dst, cd, compressionLevel) _, err := sc.zw.ReadFrom(src) if err == nil { err = sc.zw.Close() } putSCompressor(sc) return err } type sCompressor struct { zw *Writer compressionLevel int } func getSCompressor(compressionLevel int) *sCompressor { p := getSCompressorPool(compressionLevel) v := p.Get() if v == nil { return &sCompressor{ zw: NewWriterLevel(nil, compressionLevel), compressionLevel: compressionLevel, } } return v.(*sCompressor) } func putSCompressor(sc *sCompressor) { sc.zw.Reset(nil, nil, sc.compressionLevel) p := getSCompressorPool(sc.compressionLevel) p.Put(sc) } func getSCompressorPool(compressionLevel int) *sync.Pool { // Use per-level compressor pools, since Writer.Reset is expensive // between distinct compression levels. sCompressorPoolLock.Lock() p := sCompressorPool[compressionLevel] if p == nil { p = &sync.Pool{} sCompressorPool[compressionLevel] = p } sCompressorPoolLock.Unlock() return p } var ( sCompressorPoolLock sync.Mutex sCompressorPool = make(map[int]*sync.Pool) ) // StreamDecompress decompresses src into dst. // // This function doesn't work with interactive network streams, since data read // from src may be buffered before passing to dst for performance reasons. // Use Reader for interactive network streams. func StreamDecompress(dst io.Writer, src io.Reader) error { return StreamDecompressDict(dst, src, nil) } // StreamDecompressDict decompresses src into dst using the given dictionary dd. // // This function doesn't work with interactive network streams, since data read // from src may be buffered before passing to dst for performance reasons. // Use Reader for interactive network streams. func StreamDecompressDict(dst io.Writer, src io.Reader, dd *DDict) error { sd := getSDecompressor() sd.zr.Reset(src, dd) _, err := sd.zr.WriteTo(dst) putSDecompressor(sd) return err } type sDecompressor struct { zr *Reader } func getSDecompressor() *sDecompressor { v := sDecompressorPool.Get() if v == nil { return &sDecompressor{ zr: NewReader(nil), } } return v.(*sDecompressor) } func putSDecompressor(sd *sDecompressor) { sd.zr.Reset(nil, nil) sDecompressorPool.Put(sd) } var sDecompressorPool sync.Pool