]> Cypherpunks repositories - gostls13.git/commitdiff
compress/flate: add examples
authorJoe Tsai <joetsai@digital-static.net>
Thu, 22 Sep 2016 20:33:22 +0000 (13:33 -0700)
committerJoe Tsai <thebrokentoaster@gmail.com>
Sat, 12 Nov 2016 18:42:35 +0000 (18:42 +0000)
Updates #16360

Change-Id: I66ff23e0501363f58fe891d5e95806422071f93b
Reviewed-on: https://go-review.googlesource.com/30162
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/compress/flate/example_test.go [new file with mode: 0644]

diff --git a/src/compress/flate/example_test.go b/src/compress/flate/example_test.go
new file mode 100644 (file)
index 0000000..5780092
--- /dev/null
@@ -0,0 +1,243 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate_test
+
+import (
+       "bytes"
+       "compress/flate"
+       "fmt"
+       "io"
+       "log"
+       "os"
+       "strings"
+       "sync"
+)
+
+// In performance critical applications, Reset can be used to discard the
+// current compressor or decompressor state and reinitialize them quickly
+// by taking advantage of previously allocated memory.
+func Example_reset() {
+       proverbs := []string{
+               "Don't communicate by sharing memory, share memory by communicating.\n",
+               "Concurrency is not parallelism.\n",
+               "The bigger the interface, the weaker the abstraction.\n",
+               "Documentation is for users.\n",
+       }
+
+       var r strings.Reader
+       var b bytes.Buffer
+       buf := make([]byte, 32<<10)
+
+       zw, err := flate.NewWriter(nil, flate.DefaultCompression)
+       if err != nil {
+               log.Fatal(err)
+       }
+       zr := flate.NewReader(nil)
+
+       for _, s := range proverbs {
+               r.Reset(s)
+               b.Reset()
+
+               // Reset the compressor and encode from some input stream.
+               zw.Reset(&b)
+               if _, err := io.CopyBuffer(zw, &r, buf); err != nil {
+                       log.Fatal(err)
+               }
+               if err := zw.Close(); err != nil {
+                       log.Fatal(err)
+               }
+
+               // Reset the decompressor and decode to some output stream.
+               if err := zr.(flate.Resetter).Reset(&b, nil); err != nil {
+                       log.Fatal(err)
+               }
+               if _, err := io.CopyBuffer(os.Stdout, zr, buf); err != nil {
+                       log.Fatal(err)
+               }
+               if err := zr.Close(); err != nil {
+                       log.Fatal(err)
+               }
+       }
+
+       // Output:
+       // Don't communicate by sharing memory, share memory by communicating.
+       // Concurrency is not parallelism.
+       // The bigger the interface, the weaker the abstraction.
+       // Documentation is for users.
+}
+
+// A preset dictionary can be used to improve the compression ratio.
+// The downside to using a dictionary is that the compressor and decompressor
+// must agree in advance what dictionary to use.
+func Example_dictionary() {
+       // The dictionary is a string of bytes. When compressing some input data,
+       // the compressor will attempt to substitute substrings with matches found
+       // in the dictionary. As such, the dictionary should only contain substrings
+       // that are expected to be found in the actual data stream.
+       const dict = `<?xml version="1.0"?>` + `<book>` + `<data>` + `<meta name="` + `" content="`
+
+       // The data to compress should (but is not required to) contain frequent
+       // substrings that match those in the dictionary.
+       const data = `<?xml version="1.0"?>
+<book>
+       <meta name="title" content="The Go Programming Language"/>
+       <meta name="authors" content="Alan Donovan and Brian Kernighan"/>
+       <meta name="published" content="2015-10-26"/>
+       <meta name="isbn" content="978-0134190440"/>
+       <data>...</data>
+</book>
+`
+
+       var b bytes.Buffer
+
+       // Compress the data using the specially crafted dictionary.
+       zw, err := flate.NewWriterDict(&b, flate.DefaultCompression, []byte(dict))
+       if err != nil {
+               log.Fatal(err)
+       }
+       if _, err := io.Copy(zw, strings.NewReader(data)); err != nil {
+               log.Fatal(err)
+       }
+       if err := zw.Close(); err != nil {
+               log.Fatal(err)
+       }
+
+       // The decompressor must use the same dictionary as the compressor.
+       // Otherwise, the input may appear as corrupted.
+       fmt.Println("Decompressed output using the dictionary:")
+       zr := flate.NewReaderDict(bytes.NewReader(b.Bytes()), []byte(dict))
+       if _, err := io.Copy(os.Stdout, zr); err != nil {
+               log.Fatal(err)
+       }
+       if err := zr.Close(); err != nil {
+               log.Fatal(err)
+       }
+
+       fmt.Println()
+
+       // Substitute all of the bytes in the dictionary with a '#' to visually
+       // demonstrate the approximate effectiveness of using a preset dictionary.
+       fmt.Println("Substrings matched by the dictionary are marked with #:")
+       hashDict := []byte(dict)
+       for i := range hashDict {
+               hashDict[i] = '#'
+       }
+       zr = flate.NewReaderDict(&b, hashDict)
+       if _, err := io.Copy(os.Stdout, zr); err != nil {
+               log.Fatal(err)
+       }
+       if err := zr.Close(); err != nil {
+               log.Fatal(err)
+       }
+
+       // Output:
+       // Decompressed output using the dictionary:
+       // <?xml version="1.0"?>
+       // <book>
+       //      <meta name="title" content="The Go Programming Language"/>
+       //      <meta name="authors" content="Alan Donovan and Brian Kernighan"/>
+       //      <meta name="published" content="2015-10-26"/>
+       //      <meta name="isbn" content="978-0134190440"/>
+       //      <data>...</data>
+       // </book>
+       //
+       // Substrings matched by the dictionary are marked with #:
+       // #####################
+       // ######
+       //      ############title###########The Go Programming Language"/#
+       //      ############authors###########Alan Donovan and Brian Kernighan"/#
+       //      ############published###########2015-10-26"/#
+       //      ############isbn###########978-0134190440"/#
+       //      ######...</#####
+       // </#####
+}
+
+// DEFLATE is suitable for transmitting compressed data across the network.
+func Example_synchronization() {
+       var wg sync.WaitGroup
+       defer wg.Wait()
+
+       // Use io.Pipe to simulate a network connection.
+       // A real network application should take care to properly close the
+       // underlying connection.
+       rp, wp := io.Pipe()
+
+       // Start a goroutine to act as the transmitter.
+       wg.Add(1)
+       go func() {
+               defer wg.Done()
+
+               zw, err := flate.NewWriter(wp, flate.BestSpeed)
+               if err != nil {
+                       log.Fatal(err)
+               }
+
+               b := make([]byte, 256)
+               for _, m := range strings.Fields("A long time ago in a galaxy far, far away...") {
+                       // We use a simple framing format where the first byte is the
+                       // message length, followed the message itself.
+                       b[0] = uint8(copy(b[1:], m))
+
+                       if _, err := zw.Write(b[:1+len(m)]); err != nil {
+                               log.Fatal(err)
+                       }
+
+                       // Flush ensures that the receiver can read all data sent so far.
+                       if err := zw.Flush(); err != nil {
+                               log.Fatal(err)
+                       }
+               }
+
+               if err := zw.Close(); err != nil {
+                       log.Fatal(err)
+               }
+       }()
+
+       // Start a goroutine to act as the receiver.
+       wg.Add(1)
+       go func() {
+               defer wg.Done()
+
+               zr := flate.NewReader(rp)
+
+               b := make([]byte, 256)
+               for {
+                       // Read the message length.
+                       // This is guaranteed to return for every corresponding
+                       // Flush and Close on the transmitter side.
+                       if _, err := io.ReadFull(zr, b[:1]); err != nil {
+                               if err == io.EOF {
+                                       break // The transmitter closed the stream
+                               }
+                               log.Fatal(err)
+                       }
+
+                       // Read the message content.
+                       n := int(b[0])
+                       if _, err := io.ReadFull(zr, b[:n]); err != nil {
+                               log.Fatal(err)
+                       }
+
+                       fmt.Printf("Received %d bytes: %s\n", n, b[:n])
+               }
+               fmt.Println()
+
+               if err := zr.Close(); err != nil {
+                       log.Fatal(err)
+               }
+       }()
+
+       // Output:
+       // Received 1 bytes: A
+       // Received 4 bytes: long
+       // Received 4 bytes: time
+       // Received 3 bytes: ago
+       // Received 2 bytes: in
+       // Received 1 bytes: a
+       // Received 6 bytes: galaxy
+       // Received 4 bytes: far,
+       // Received 3 bytes: far
+       // Received 7 bytes: away...
+}