brrr

package module
v1.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 24, 2026 License: MIT Imports: 8 Imported by: 7

README

go brrr

go-brrr - Brotli compression for Go

CI Go Reference Go Report Card Version

Brotli compression library for Go (RFC 7932), with encoder and decoder support.

Highlights

  • No C toolchain. Builds with standard Go tooling.
  • Faster than other pure-Go brotli libraries at every quality level we measure (see Benchmarks).
  • Faster than CGO brotli (cbrotli) in our benchmarks, for compression at q0-q11 and for one-shot decompression.
  • Compound dictionaries.
  • Encoder tuning. LGWin (window size) and SizeHint (expected total input size) are exposed via WriterOptions. SizeHint lets the encoder pick context modeling and hasher parameters tuned for the actual payload size.

Status

The encoder and decoder are covered by compatibility tests and fuzzing. The public API is stable and follows semantic versioning.

Compatibility

go-brrr implements Brotli RFC 7932 and is tested against the Brotli reference corpus. Encoded output is byte-compatible with the C reference implementation, release v1.2.1. One exception: with a compound dictionary at quality 3 and 4, go-brrr follows upstream commit 54f74c7, which is not in a release yet.

Compared to other Go brotli libraries

go-brrr andybalholm google/brotli/go/brotli cbrotli
Pure Go (no cgo) ✓ ✓ ✓ ✗
Encoder ✓ ✓ ✗ ✓
Decoder ✓ ✓ ✓ ✓
Compound dictionaries (encode) ✓ ✗ n/a ✓
Compound dictionaries (decode) ✓ ✗ ✓ ✓
LGWin tuning ✓ ✓ n/a ✓
SizeHint ✓ ✗ n/a ✗
Writer Reset ✓ ✓ n/a ✗
Reader Reset ✓ ✓ ✗ ✗

If you're using andybalholm/brotli, go-brrr is a near drop-in upgrade with higher throughput on both compression and decompression, plus compound-dictionary and SizeHint support. If you're using cbrotli, go-brrr gives up cgo, adds multi-chunk compound dictionaries, and exposes poolable Writer/Reader instances. cbrotli has no Reset, so each stream allocates a fresh encoder/decoder state, which is noticeable on many-small-file workloads.

Install

go get github.com/molecule-man/go-brrr
import "github.com/molecule-man/go-brrr"

The import path is github.com/molecule-man/go-brrr; the package name is brrr.

Examples

Compression
func Example_compress() {
	input := []byte("Hello, brotli!")

	var compressed bytes.Buffer
	w, err := brrr.NewWriter(&compressed, 6)
	if err != nil {
		log.Fatal(err)
	}
	if _, err := w.Write(input); err != nil {
		log.Fatal(err)
	}
	if err := w.Close(); err != nil {
		log.Fatal(err)
	}
}

More examples are available in example_test.go and the Go package docs: round-trip compression and decompression, one-shot decompression, reusing writers and readers, pooling, and compound dictionaries.

When to use go-brrr

The best use case for brotli is static asset compression - CSS, JS, HTML, fonts, WASM - where you compress once at build time and serve the result millions of times. Use quality 11 for this: speed doesn't matter because you pay the cost once, and brotli q11 delivers ratios that neither gzip nor zstd can match. Every browser shipped since 2016 supports Content-Encoding: br.

For on-the-fly compression, brotli q5–6 is a strong choice if you're already using zstd at its highest level: q5 is often faster with a better ratio, and q6 is only slightly slower with an even better ratio. At lower compression levels, zstd is significantly faster - if throughput is your priority and you don't need the best ratio, zstd is the better tool for the job.

If you compress or decompress repeatedly (e.g. per request in a webserver), keep *brrr.Writer and *brrr.Reader instances in sync.Pools and Reset each one into the next stream rather than allocating new instances each time. See the compiled examples.

Implementation notes

go-brrr is optimized for throughput. Some hot paths intentionally use larger functions, duplicated loops, and specialized code where benchmarks showed measurable wins. These choices stay local to performance-sensitive encoder and decoder internals; public APIs stay small and conventional.

Contributing

Contributions are welcome. Read CONTRIBUTING.md before you start.

The most important rules:

  • One pull request is one logical change. Independent optimizations go into separate pull requests, so each one can be benchmarked, reverted, and bisected on its own.
  • Explain the expected effect and its cause.

The maintainer measures every performance change against a file corpus on dedicated hardware.

For a large optimization, open an issue first and agree on the scope.

Acknowledgments

This library is a port of the Brotli reference implementation by the Brotli Authors, licensed under the MIT License.

Compression Speed vs Ratio

All benchmarks were taken on the following setup with turboboost, etc, being disabled via denoise-amd.sh:

goos: linux
goarch: amd64
cpu: AMD Ryzen 5 7535HS with Radeon Graphics

Each plot uses a set of real-world files of one type, for example 530 HTML pages or 111 JS files of 64 KiB to 1 MiB. The benchmark compresses the files one by one with one reused encoder. This is like a web server that compresses its assets. Compared against klauspost/compress zstd (pure Go) and stdlib gzip, single CPU.

Plots for all file sizes (up to more than 8 MiB), Intel results and the methodology are in docs/plots.md.

Compression Decompression
html 64k-1m html 64k-1m
js 64k-1m js 64k-1m
json 64k-1m json 64k-1m
css 64k-1m css 64k-1m
prose 64k-1m prose 64k-1m

Benchmarks

Compared against other Go brotli libraries. go-brrr is the base in all comparisons. The smaller the number the better.

  • andybalholm - github.com/andybalholm/brotli, pure Go encoder and decoder.
  • google-brotli - github.com/google/brotli/go/brotli, Google's official pure Go decoder, transpiled from the Java reference. Decompression only, no encoder.
  • cbrotli - github.com/google/brotli/go/cbrotli, Google's official cgo bindings to the C reference implementation. Including a cgo library in a pure Go comparison isn't apples-to-apples, but it is a useful comparison against Google's C implementation as exposed through its Go bindings.
One-shot Compression

The table below measures end-to-end throughput through each package's public Go API for many independent brotli streams, not only the inner compression loop. Each payload is written as a complete stream with a fresh public writer instance so cbrotli, which has no resettable writer API, can be included.

go-brrr still benefits from internal reuse in that shape: encoder arenas, hashers, hash tables, and scratch buffers are kept reusable through reset paths and internal sync.Pools. That avoids repeated large allocations and zeroing, which matters for small and mid-size payloads. cbrotli uses the C reference encoder underneath, but each payload creates a new BrotliEncoderState through cbrotli.NewWriter and destroys it on Close, paying setup, teardown, cgo, and allocation costs for every stream.

Read these rows as repeated complete-stream compression through the Go APIs. They are not a claim that every pure-Go hot path is faster than the C implementation. Part of the gap comes from per-stream setup and cgo cost in cbrotli.

go-brrr (sec/op) andybalholm (sec/op) cbrotli (sec/op)
CompressOneshot/q=0/payload=VariedPayloads 6.244m ± 0% 12.401m ± 0% +98.59% (p=0.000) 6.993m ± 0% +11.99% (p=0.000)
CompressOneshot/q=1/payload=VariedPayloads 8.818m ± 0% 20.166m ± 0% +128.71% (p=0.000) 10.770m ± 0% +22.14% (p=0.000)
CompressOneshot/q=2/payload=VariedPayloads 14.68m ± 0% 38.92m ± 2% +165.18% (p=0.000) 18.07m ± 0% +23.10% (p=0.000)
CompressOneshot/q=3/payload=VariedPayloads 16.05m ± 0% 44.61m ± 5% +177.99% (p=0.000) 20.99m ± 0% +30.82% (p=0.000)
CompressOneshot/q=4/payload=VariedPayloads 25.22m ± 0% 63.44m ± 2% +151.58% (p=0.000) 30.02m ± 0% +19.05% (p=0.000)
CompressOneshot/q=5/payload=VariedPayloads 36.43m ± 0% 82.07m ± 2% +125.31% (p=0.000) 47.17m ± 0% +29.50% (p=0.000)
CompressOneshot/q=6/payload=VariedPayloads 43.31m ± 0% 91.75m ± 1% +111.84% (p=0.000) 54.72m ± 0% +26.33% (p=0.000)
CompressOneshot/q=7/payload=VariedPayloads 49.57m ± 0% 126.45m ± 2% +155.12% (p=0.000) 107.89m ± 0% +117.66% (p=0.000)
CompressOneshot/q=8/payload=VariedPayloads 58.22m ± 0% 141.16m ± 1% +142.45% (p=0.000) 81.44m ± 0% +39.88% (p=0.000)
CompressOneshot/q=9/payload=VariedPayloads 73.33m ± 0% 207.21m ± 2% +182.56% (p=0.000) 234.33m ± 0% +219.53% (p=0.000)
CompressOneshot/q=10/payload=VariedPayloads 818.5m ± 0% 1342.6m ± 1% +64.04% (p=0.000) 858.1m ± 0% +4.84% (p=0.000)
CompressOneshot/q=11/payload=VariedPayloads 1.574 ± 0% 3.373 ± 1% +114.30% (p=0.000) 2.266 ± 0% +43.99% (p=0.000)
geomean 47.75m 110.9m +132.31% 67.45m +41.24%
n 8 8 8

Streaming uses brrr.NewReader + io.ReadAll; one-shot uses brrr.Decompress on a complete in-memory blob.

Streaming Decompression

As cbrotli doesn't have the "resettable" API it's not included here.

go-brrr (sec/op) andybalholm (sec/op) diff p
Decompress/q=4/payload=VariedPayloads 3.942m ± 0% 9.574m ± 0% +142.90% 0.000
Decompress/q=5/payload=VariedPayloads 3.736m ± 0% 9.165m ± 0% +145.31% 0.000
Decompress/q=6/payload=VariedPayloads 3.632m ± 0% 8.898m ± 0% +145.02% 0.000
Decompress/q=11/payload=VariedPayloads 4.263m ± 0% 8.932m ± 0% +109.54% 0.000
geomean 3.886m 9.138m +135.18%
n 12 12
One-shot Decompression
go-brrr (sec/op) andybalholm (sec/op) cbrotli (sec/op) google-brotli (sec/op)
DecompressOneshot/q=4/payload=VariedPayloads 4.168m ± 0% 10.051m ± 0% +141.15% (p=0.000) 5.201m ± 0% +24.79% (p=0.000) 10.604m ± 0% +154.39% (p=0.000)
DecompressOneshot/q=5/payload=VariedPayloads 4.047m ± 0% 9.662m ± 0% +138.78% (p=0.000) 5.026m ± 5% +24.20% (p=0.000) 10.497m ± 0% +159.41% (p=0.000)
DecompressOneshot/q=6/payload=VariedPayloads 3.952m ± 0% 9.367m ± 0% +137.00% (p=0.000) 4.902m ± 1% +24.04% (p=0.000) 10.158m ± 1% +157.03% (p=0.000)
DecompressOneshot/q=11/payload=VariedPayloads 4.492m ± 0% 9.544m ± 0% +112.44% (p=0.000) 6.689m ± 1% +48.90% (p=0.000 )
geomean 4.160m 9.653m +132.04% 5.411m +30.07% 10.42m +156.93% ¹
¹ benchmark set differs from baseline; geomeans may not be comparable
n 1..16 16 1..16 16

The VariedPayloads benchmark rotates through a heterogeneous mix of files, guarding against benchmark-shaped optimizations - wins that only show up when the same input is fed back-to-back should not move these rows. Payloads span small JSON API responses, mid-size HTML and JS bundles, and larger English prose, drawn from the Brotli reference test corpus and the local testdata/ directory.

File Size Source
github_events_2k.json 2.2 KB testdata
github_events_5k.json 5.2 KB testdata
github_events_8k.json 8.3 KB testdata
asyoulik.txt 122 KB brotli-ref
alice29.txt 149 KB brotli-ref
gh_172KB.html 167 KB testdata
reactcore_187KB.js 182 KB testdata
lcet10.txt 417 KB brotli-ref
plrabn12.txt 471 KB brotli-ref

Documentation

Overview

Package brrr implements the Brotli compressed data format (RFC 7932).

Brotli is a lossless compression algorithm that typically produces better ratios than gzip and zstd at the cost of slower compression. Decompression is fast at every quality level. Every major browser has accepted Content-Encoding: br since 2016, which makes brotli a good match for static web asset pipelines.

Basic usage

Streaming compression through an io.Writer:

var buf bytes.Buffer
w, err := brrr.NewWriter(&buf, 6)
if err != nil {
	log.Fatal(err)
}
if _, err := w.Write(data); err != nil {
	log.Fatal(err)
}
if err := w.Close(); err != nil {
	log.Fatal(err)
}

Streaming decompression through an io.Reader:

r := brrr.NewReader(src)
if _, err := io.Copy(dst, r); err != nil {
	log.Fatal(err)
}

One-shot decompression of a complete in-memory blob:

out, err := brrr.Decompress(compressed)

Key types

  • Writer implements io.WriteCloser and compresses data written to an underlying io.Writer. Close must be called to finalize the brotli stream.
  • Reader implements io.Reader and decompresses a brotli stream read from an underlying io.Reader.
  • Decompress is a convenience function for one-shot decompression of a complete in-memory blob.

Writer and Reader both expose Reset methods, so the same instance can be reused across payloads without reallocating per-call buffers. Both also accept compound dictionaries — useful when the payloads share content with a known corpus. The encoder takes pre-built PreparedDictionary values via WriterOptions.Dictionaries, so the hash table is built once and may be shared across many Writers and goroutines. The decoder takes raw dictionary bytes via ReaderOptions.Dictionaries.

Choosing a quality level

Quality controls the ratio/speed trade-off on a scale of 0 to 11:

  • Quality 0–1 use fast one-pass and two-pass encoders optimised for throughput.
  • Quality 2–9 use a streaming encoder that spends progressively more work per byte for better ratios.
  • Quality 10–11 use a Zopfli-style optimal-parsing encoder that produces the best ratios but is orders of magnitude slower than the lower levels.

The canonical use case for brotli is static asset compression — CSS, JS, HTML, fonts, WASM — where the data is compressed once at build time and served many times; quality 11 is the right choice there. For on-the-fly compression, quality 5–6 gives a good balance of speed and ratio.

Compatibility

Output is byte-compatible with the reference implementation at https://github.com/google/brotli, release v1.2.1. One exception: with a compound dictionary at quality 3 and 4, this package follows upstream commit 54f74c7, which is not in a release yet. Any conforming brotli decoder can read streams produced by this package, and this package can decode any valid brotli stream.

Example (CompoundDictionary)
package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"strings"

	"github.com/molecule-man/go-brrr"
)

func main() {
	// A compound dictionary supplies extra reference data that both the
	// encoder and decoder can use for backward references. This is useful
	// when compressing data that shares content with a known corpus.
	dict := []byte(strings.Repeat("common dictionary content that appears in many documents. ", 50))
	input := []byte("This document references common dictionary content that appears in many documents. " +
		"It benefits from the shared dictionary because repeated phrases compress better.")

	// Build the encoder-side hash table once. The same *PreparedDictionary
	// can be shared across many Writers, including across goroutines.
	pd, err := brrr.PrepareDictionary(dict)
	if err != nil {
		log.Fatal(err)
	}

	// Compress with compound dictionary.
	var compressed bytes.Buffer
	w, err := brrr.NewWriterOptions(&compressed, 4, brrr.WriterOptions{
		Dictionaries: []*brrr.PreparedDictionary{pd},
	})
	if err != nil {
		log.Fatal(err)
	}
	if _, err := w.Write(input); err != nil {
		log.Fatal(err)
	}
	if err := w.Close(); err != nil {
		log.Fatal(err)
	}

	// Decompress with the same compound dictionary.
	r, err := brrr.NewReaderOptions(&compressed, brrr.ReaderOptions{
		Dictionaries: [][]byte{dict},
	})
	if err != nil {
		log.Fatal(err)
	}
	result, err := io.ReadAll(r)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(result))
}
Output:
This document references common dictionary content that appears in many documents. It benefits from the shared dictionary because repeated phrases compress better.
Example (Compress)
package main

import (
	"bytes"
	"log"

	"github.com/molecule-man/go-brrr"
)

func main() {
	input := []byte("Hello, brotli!")

	var compressed bytes.Buffer
	w, err := brrr.NewWriter(&compressed, 6)
	if err != nil {
		log.Fatal(err)
	}
	if _, err := w.Write(input); err != nil {
		log.Fatal(err)
	}
	if err := w.Close(); err != nil {
		log.Fatal(err)
	}
}
Example (Decompress)
package main

import (
	"bytes"
	"fmt"
	"log"

	"github.com/molecule-man/go-brrr"
)

func main() {
	// Compress some data first.
	original := []byte("Decompress restores the original bytes from a brotli-compressed slice.")
	var compressed bytes.Buffer
	w, err := brrr.NewWriter(&compressed, 4)
	if err != nil {
		log.Fatal(err)
	}
	if _, err = w.Write(original); err != nil {
		log.Fatal(err)
	}
	if err = w.Close(); err != nil {
		log.Fatal(err)
	}

	// One-shot decompression from a byte slice.
	result, err := brrr.Decompress(compressed.Bytes())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(result))
}
Output:
Decompress restores the original bytes from a brotli-compressed slice.
Example (Pool)
package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"sync"

	"github.com/molecule-man/go-brrr"
)

func main() {
	// For repeated compression and decompression (e.g. per-request in an
	// HTTP server, per-message in a stream processor), keep *brrr.Writer
	// and *brrr.Reader instances in sync.Pools. Get, Reset, use, Put back.
	// This avoids allocating encoder hash tables and decoder ring buffers
	// each time.
	writerPool := sync.Pool{
		New: func() any {
			w, err := brrr.NewWriter(io.Discard, 5)
			if err != nil {
				// NewWriter only fails for an invalid level, which is
				// static here.
				panic(err)
			}
			return w
		},
	}
	readerPool := sync.Pool{
		New: func() any { return brrr.NewReader(nil) },
	}

	compress := func(dst io.Writer, payload []byte) error {
		w := writerPool.Get().(*brrr.Writer)
		defer writerPool.Put(w)

		w.Reset(dst)
		if _, err := w.Write(payload); err != nil {
			return err
		}
		return w.Close()
	}

	decompress := func(src io.Reader) ([]byte, error) {
		r := readerPool.Get().(*brrr.Reader)
		defer readerPool.Put(r)

		r.Reset(src)
		return io.ReadAll(r)
	}

	payloads := []string{
		"First response body.",
		"Second response body.",
	}
	for _, p := range payloads {
		var buf bytes.Buffer
		if err := compress(&buf, []byte(p)); err != nil {
			log.Fatal(err)
		}
		out, err := decompress(&buf)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(string(out))
	}
}
Output:
First response body.
Second response body.
Example (Reuse)
package main

import (
	"bytes"
	"fmt"
	"io"
	"log"

	"github.com/molecule-man/go-brrr"
)

func main() {
	// Reset lets you reuse a Writer and Reader across multiple payloads,
	// avoiding repeated allocations.
	payloads := []string{
		"First payload: the quick brown fox jumps over the lazy dog.",
		"Second payload: pack my box with five dozen liquor jugs.",
	}

	var compressed bytes.Buffer
	w, err := brrr.NewWriter(&compressed, 4)
	if err != nil {
		log.Fatal(err)
	}
	r := brrr.NewReader(nil)

	for _, payload := range payloads {
		// Compress
		compressed.Reset()
		w.Reset(&compressed)
		if _, err := w.Write([]byte(payload)); err != nil {
			log.Fatal(err)
		}
		if err := w.Close(); err != nil {
			log.Fatal(err)
		}

		// Decompress
		r.Reset(&compressed)
		result, err := io.ReadAll(r)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(string(result))
	}
}
Output:
First payload: the quick brown fox jumps over the lazy dog.
Second payload: pack my box with five dozen liquor jugs.
Example (Roundtrip)
package main

import (
	"bytes"
	"fmt"
	"io"
	"log"

	"github.com/molecule-man/go-brrr"
)

func main() {
	// Compress
	original := []byte("Hello, brotli! This is a round-trip compression example.")
	var compressed bytes.Buffer
	w, err := brrr.NewWriter(&compressed, 6)
	if err != nil {
		log.Fatal(err)
	}
	if _, err := w.Write(original); err != nil {
		log.Fatal(err)
	}
	if err := w.Close(); err != nil {
		log.Fatal(err)
	}

	// Decompress
	r := brrr.NewReader(&compressed)
	decompressed, err := io.ReadAll(r)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(decompressed))
}
Output:
Hello, brotli! This is a round-trip compression example.

Index

Examples

Constants

View Source
const (
	BestSpeed       = 0
	BestCompression = 11
)

Compression level constants.

Variables

View Source
var ErrExcessiveInput = errors.New("brotli: excessive input")

ErrExcessiveInput reports bytes that follow finalized brotli stream.

Functions

func Compress added in v0.5.1

func Compress(data []byte, level int) ([]byte, error)

Compress compresses data at the given quality level and returns the brotli-compressed bytes. It is the one-shot counterpart to Decompress. Supported levels are 0 (BestSpeed) through 11 (BestCompression). The exact input length is supplied to the encoder as a size hint.

Example
package main

import (
	"fmt"
	"log"

	"github.com/molecule-man/go-brrr"
)

func main() {
	// One-shot compression of a byte slice, paired with Decompress.
	compressed, err := brrr.Compress([]byte("Hello, brotli!"), 6)
	if err != nil {
		log.Fatal(err)
	}

	result, err := brrr.Decompress(compressed)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(result))
}
Output:
Hello, brotli!

func Decompress

func Decompress(data []byte) ([]byte, error)

Decompress decodes the brotli-compressed data and returns the original bytes.

It returns ErrExcessiveInput if bytes follow the stream.

Types

type PreparedDictionary

type PreparedDictionary struct {
	// contains filtered or unexported fields
}

PreparedDictionary is a compound dictionary chunk built once and shared across many Writers. See WriterOptions.Dictionaries. It is an opaque handle; build one with PrepareDictionary.

func PrepareDictionary

func PrepareDictionary(data []byte) (*PreparedDictionary, error)

PrepareDictionary builds an immutable PreparedDictionary from the given source bytes, suitable for use as a compound dictionary chunk via WriterOptions.Dictionaries. The returned dictionary may be shared across any number of Writers and goroutines.

The returned dictionary keeps a reference to data; the caller must not mutate data while any Writer holding the dictionary is still in use.

Returns an error if data is empty.

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader decompresses brotli-compressed data from an underlying io.Reader.

func NewReader

func NewReader(src io.Reader) *Reader

NewReader returns a new Reader reading brotli-compressed data from src.

func NewReaderOptions

func NewReaderOptions(src io.Reader, opts ReaderOptions) (*Reader, error)

NewReaderOptions returns a new Reader reading brotli-compressed data from src with additional options. Compound dictionaries supplied via opts.Dictionaries must match those used by the encoder.

func (*Reader) Close

func (r *Reader) Close() error

Close releases resources held by the Reader.

func (*Reader) Read

func (r *Reader) Read(p []byte) (int, error)

Read decompresses data into p.

Read returns ErrExcessiveInput only for a buffered tail. It does not read src after the stream ends. Decompress checks the complete input for a tail.

After decode success, Read serves all decoded bytes before it returns a terminal error. Later calls return the same error.

func (*Reader) Reset

func (r *Reader) Reset(src io.Reader)

Reset discards internal state and switches to reading from src. Compound dictionaries supplied via ReaderOptions are preserved.

type ReaderOptions

type ReaderOptions struct {
	// Dictionaries are compound dictionary chunks the decoder will use to
	// resolve backward references beyond the ring buffer. They must match
	// the dictionaries supplied to the encoder. Up to 15 chunks are allowed;
	// each must be non-empty. Dictionaries are preserved across Reset.
	Dictionaries [][]byte
}

ReaderOptions configures the brotli decoder.

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

Writer compresses data into brotli format.

Callers must Close the Writer to finalize the brotli stream.

At levels 10 and 11, a Writer uses up to two worker goroutines when GOMAXPROCS is at least 2. This can reduce latency but uses more memory. A Writer does not support concurrent calls.

func NewWriter

func NewWriter(dst io.Writer, level int) (*Writer, error)

NewWriter returns a new Writer compressing data to dst at the given quality level. Supported levels are 0 (BestSpeed) through 11 (BestCompression).

func NewWriterOptions

func NewWriterOptions(dst io.Writer, level int, opts WriterOptions) (*Writer, error)

NewWriterOptions returns a new Writer compressing data to dst at the given quality level with additional tuning options. LGWin range is 10–24; 0 selects the default (22). Compound dictionaries supplied via opts.Dictionaries require level >= 2.

func (*Writer) Close

func (w *Writer) Close() error

Close flushes remaining data, finalizes the brotli stream by writing the final empty meta-block, and writes everything to the underlying writer. Close does not close the underlying writer.

func (*Writer) Flush

func (w *Writer) Flush() error

Flush compresses any buffered data and writes it to the underlying writer as one or more non-final meta-blocks. Flush does not finalize the brotli stream; call Close for that.

func (*Writer) Reset

func (w *Writer) Reset(dst io.Writer)

Reset discards the current stream and sets dst for the next stream. It clears the size hint. The encoder estimates size from the first Write. It keeps compound dictionaries from WriterOptions.

func (*Writer) ResetWithSizeHint added in v1.3.0

func (w *Writer) ResetWithSizeHint(dst io.Writer, sizeHint uint)

ResetWithSizeHint discards the current stream and sets dst for the next stream. It uses sizeHint as the expected input size. A zero hint means unknown size.

func (*Writer) Write

func (w *Writer) Write(p []byte) (int, error)

Write compresses p and writes it to the underlying writer. Data may be buffered internally; call Flush or Close to ensure all data is written.

type WriterOptions

type WriterOptions struct {
	// Dictionaries are compound dictionary chunks the encoder may reference
	// as backward distances beyond the ring buffer, useful when inputs share
	// content with a known corpus. Build each chunk once with
	// [PrepareDictionary] and share the resulting *PreparedDictionary across
	// any number of Writers. Up to 15 chunks are allowed and compound
	// dictionaries require compression level >= 2. Dictionaries are preserved
	// across Reset.
	Dictionaries []*PreparedDictionary

	// LGWin sets the base-2 logarithm of the sliding window size (10–24).
	// 0 selects the default (22).
	LGWin int

	// SizeHint is the expected total input size in bytes. When set, the
	// encoder uses it to make better decisions about context modeling and
	// hasher selection for large inputs. 0 means unknown; the encoder will
	// auto-estimate from the first Write call.
	//
	// SizeHint is advisory: a lower-than-actual value is safe in both
	// correctness and compression ratio. The encoder transparently
	// promotes its internal hasher to the unbounded variant if buffered
	// input crosses the size-tuned threshold, preserving the bucket state
	// that was learned under the small-hint dispatch.
	//
	// SizeHint applies only to the first stream. [Writer.Reset] clears it.
	// [Writer.ResetWithSizeHint] sets the hint for the next stream.
	SizeHint uint
}

WriterOptions configures advanced tuning knobs for the brotli encoder. The compression level is passed positionally to NewWriter / NewWriterOptions.

Directories

Path Synopsis
cmd
genfixedshift command
Command genfixedshift copies a compressor function and makes its hash shift constant.
Command genfixedshift copies a compressor function and makes its hash shift constant.
genstaticdict command
Generates static dictionary lookup tables for the Brotli encoder.
Generates static dictionary lookup tables for the Brotli encoder.
internal
benchcache
Package benchcache stores precomputed compression outputs on disk so that benchmark and test setup does not have to re-run the (slow) C reference encoder or other expensive paths on every run.
Package benchcache stores precomputed compression outputs on disk so that benchmark and test setup does not have to re-run the (slow) C reference encoder or other expensive paths on every run.
core
Package core holds RFC 7932 spec constants, Huffman primitives, and lookup tables shared between the encoder and the decoder.
Package core holds RFC 7932 spec constants, Huffman primitives, and lookup tables shared between the encoder and the decoder.
cref
Package cref wraps the C reference brotli encoder/decoder for use in tests.
Package cref wraps the C reference brotli encoder/decoder for use in tests.
creftest
Package creftest provides shared test helpers that wrap the C reference brotli encoder/decoder.
Package creftest provides shared test helpers that wrap the C reference brotli encoder/decoder.
encoder
Package encoder hosts the brotli streaming/fast encoder implementations and shared codec primitives consumed by the root brrr package's decoder.
Package encoder hosts the brotli streaming/fast encoder implementations and shared codec primitives consumed by the root brrr package's decoder.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL