Skip to content

Commit bda824b

Browse files
authored
flate: Add examples (#1102)
Fixes minor difference to stdlib, which doesn't do a 0 byte write.
1 parent f44517c commit bda824b

File tree

2 files changed

+248
-1
lines changed

2 files changed

+248
-1
lines changed

flate/example_test.go

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
// Copyright 2016 The Go Authors. 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+
5+
package flate_test
6+
7+
import (
8+
"bytes"
9+
"fmt"
10+
"io"
11+
"log"
12+
"os"
13+
"strings"
14+
"sync"
15+
16+
"github.com/klauspost/compress/flate"
17+
)
18+
19+
// In performance critical applications, Reset can be used to discard the
20+
// current compressor or decompressor state and reinitialize them quickly
21+
// by taking advantage of previously allocated memory.
22+
func Example_reset() {
23+
proverbs := []string{
24+
"Don't communicate by sharing memory, share memory by communicating.\n",
25+
"Concurrency is not parallelism.\n",
26+
"The bigger the interface, the weaker the abstraction.\n",
27+
"Documentation is for users.\n",
28+
}
29+
30+
var r strings.Reader
31+
var b bytes.Buffer
32+
buf := make([]byte, 32<<10)
33+
34+
zw, err := flate.NewWriter(nil, flate.DefaultCompression)
35+
if err != nil {
36+
log.Fatal(err)
37+
}
38+
zr := flate.NewReader(nil)
39+
40+
for _, s := range proverbs {
41+
r.Reset(s)
42+
b.Reset()
43+
44+
// Reset the compressor and encode from some input stream.
45+
zw.Reset(&b)
46+
if _, err := io.CopyBuffer(zw, &r, buf); err != nil {
47+
log.Fatal(err)
48+
}
49+
if err := zw.Close(); err != nil {
50+
log.Fatal(err)
51+
}
52+
53+
// Reset the decompressor and decode to some output stream.
54+
if err := zr.(flate.Resetter).Reset(&b, nil); err != nil {
55+
log.Fatal(err)
56+
}
57+
if _, err := io.CopyBuffer(os.Stdout, zr, buf); err != nil {
58+
log.Fatal(err)
59+
}
60+
if err := zr.Close(); err != nil {
61+
log.Fatal(err)
62+
}
63+
}
64+
65+
// Output:
66+
// Don't communicate by sharing memory, share memory by communicating.
67+
// Concurrency is not parallelism.
68+
// The bigger the interface, the weaker the abstraction.
69+
// Documentation is for users.
70+
}
71+
72+
// A preset dictionary can be used to improve the compression ratio.
73+
// The downside to using a dictionary is that the compressor and decompressor
74+
// must agree in advance what dictionary to use.
75+
func Example_dictionary() {
76+
// The dictionary is a string of bytes. When compressing some input data,
77+
// the compressor will attempt to substitute substrings with matches found
78+
// in the dictionary. As such, the dictionary should only contain substrings
79+
// that are expected to be found in the actual data stream.
80+
const dict = `<?xml version="1.0"?>` + `<book>` + `<data>` + `<meta name="` + `" content="`
81+
82+
// The data to compress should (but is not required to) contain frequent
83+
// substrings that match those in the dictionary.
84+
const data = `<?xml version="1.0"?>
85+
<book>
86+
<meta name="title" content="The Go Programming Language"/>
87+
<meta name="authors" content="Alan Donovan and Brian Kernighan"/>
88+
<meta name="published" content="2015-10-26"/>
89+
<meta name="isbn" content="978-0134190440"/>
90+
<data>...</data>
91+
</book>
92+
`
93+
94+
var b bytes.Buffer
95+
96+
// Compress the data using the specially crafted dictionary.
97+
zw, err := flate.NewWriterDict(&b, flate.BestCompression, []byte(dict))
98+
if err != nil {
99+
log.Fatal(err)
100+
}
101+
if _, err := io.Copy(zw, strings.NewReader(data)); err != nil {
102+
log.Fatal(err)
103+
}
104+
if err := zw.Close(); err != nil {
105+
log.Fatal(err)
106+
}
107+
108+
// The decompressor must use the same dictionary as the compressor.
109+
// Otherwise, the input may appear as corrupted.
110+
fmt.Println("Decompressed output using the dictionary:")
111+
zr := flate.NewReaderDict(bytes.NewReader(b.Bytes()), []byte(dict))
112+
if _, err := io.Copy(os.Stdout, zr); err != nil {
113+
log.Fatal(err)
114+
}
115+
if err := zr.Close(); err != nil {
116+
log.Fatal(err)
117+
}
118+
119+
fmt.Println()
120+
121+
// Substitute all of the bytes in the dictionary with a '#' to visually
122+
// demonstrate the approximate effectiveness of using a preset dictionary.
123+
fmt.Println("Substrings matched by the dictionary are marked with #:")
124+
hashDict := []byte(dict)
125+
for i := range hashDict {
126+
hashDict[i] = '#'
127+
}
128+
zr = flate.NewReaderDict(&b, hashDict)
129+
if _, err := io.Copy(os.Stdout, zr); err != nil {
130+
log.Fatal(err)
131+
}
132+
if err := zr.Close(); err != nil {
133+
log.Fatal(err)
134+
}
135+
136+
// Output:
137+
// Decompressed output using the dictionary:
138+
// <?xml version="1.0"?>
139+
// <book>
140+
// <meta name="title" content="The Go Programming Language"/>
141+
// <meta name="authors" content="Alan Donovan and Brian Kernighan"/>
142+
// <meta name="published" content="2015-10-26"/>
143+
// <meta name="isbn" content="978-0134190440"/>
144+
// <data>...</data>
145+
// </book>
146+
//
147+
// Substrings matched by the dictionary are marked with #:
148+
// #####################
149+
// ######
150+
// ############title###########The Go Programming Language"/#
151+
// ############authors###########Alan Donovan and Brian Kernighan"/#
152+
// ############published###########2015-10-26"/#
153+
// ############isbn###########978-0134190440"/#
154+
// ######...</#####
155+
// </#####
156+
}
157+
158+
// DEFLATE is suitable for transmitting compressed data across the network.
159+
func Example_synchronization() {
160+
var wg sync.WaitGroup
161+
defer wg.Wait()
162+
163+
// Use io.Pipe to simulate a network connection.
164+
// A real network application should take care to properly close the
165+
// underlying connection.
166+
rp, wp := io.Pipe()
167+
168+
// Start a goroutine to act as the transmitter.
169+
wg.Add(1)
170+
go func() {
171+
defer wg.Done()
172+
defer wp.Close()
173+
174+
zw, err := flate.NewWriter(wp, flate.BestSpeed)
175+
if err != nil {
176+
log.Fatal(err)
177+
}
178+
179+
b := make([]byte, 256)
180+
for _, m := range strings.Fields("A long time ago in a galaxy far, far away...") {
181+
// We use a simple framing format where the first byte is the
182+
// message length, followed the message itself.
183+
b[0] = uint8(copy(b[1:], m))
184+
185+
if _, err := zw.Write(b[:1+len(m)]); err != nil {
186+
log.Fatal(err)
187+
}
188+
189+
// Flush ensures that the receiver can read all data sent so far.
190+
if err := zw.Flush(); err != nil {
191+
log.Fatal(err)
192+
}
193+
}
194+
195+
if err := zw.Close(); err != nil {
196+
log.Fatal(err)
197+
}
198+
}()
199+
200+
// Start a goroutine to act as the receiver.
201+
wg.Add(1)
202+
go func() {
203+
defer wg.Done()
204+
205+
zr := flate.NewReader(rp)
206+
207+
b := make([]byte, 256)
208+
for {
209+
// Read the message length.
210+
// This is guaranteed to return for every corresponding
211+
// Flush and Close on the transmitter side.
212+
if _, err := io.ReadFull(zr, b[:1]); err != nil {
213+
if err == io.EOF {
214+
break // The transmitter closed the stream
215+
}
216+
log.Fatal(err)
217+
}
218+
219+
// Read the message content.
220+
n := int(b[0])
221+
if _, err := io.ReadFull(zr, b[:n]); err != nil {
222+
log.Fatal(err)
223+
}
224+
225+
fmt.Printf("Received %d bytes: %s\n", n, b[:n])
226+
}
227+
fmt.Println()
228+
229+
if err := zr.Close(); err != nil {
230+
log.Fatal(err)
231+
}
232+
}()
233+
234+
// Output:
235+
// Received 1 bytes: A
236+
// Received 4 bytes: long
237+
// Received 4 bytes: time
238+
// Received 3 bytes: ago
239+
// Received 2 bytes: in
240+
// Received 1 bytes: a
241+
// Received 6 bytes: galaxy
242+
// Received 4 bytes: far,
243+
// Received 3 bytes: far
244+
// Received 7 bytes: away...
245+
}

flate/huffman_bit_writer.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,9 @@ func (w *huffmanBitWriter) flush() {
211211
n++
212212
}
213213
w.bits = 0
214-
w.write(w.bytes[:n])
214+
if n > 0 {
215+
w.write(w.bytes[:n])
216+
}
215217
w.nbytes = 0
216218
}
217219

0 commit comments

Comments
 (0)