github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/compress/flate/gen.go (about)

     1  // Copyright 2012 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  // +build ignore
     6  
     7  // This program generates fixedhuff.go
     8  // Invoke as
     9  //
    10  //	go run gen.go -output fixedhuff.go
    11  
    12  package main
    13  
    14  import (
    15  	"bytes"
    16  	"flag"
    17  	"fmt"
    18  	"go/format"
    19  	"io/ioutil"
    20  	"log"
    21  )
    22  
    23  var filename = flag.String("output", "fixedhuff.go", "output file name")
    24  
    25  const maxCodeLen = 16
    26  
    27  // Note: the definition of the huffmanDecoder struct is copied from
    28  // inflate.go, as it is private to the implementation.
    29  
    30  // chunk & 15 is number of bits
    31  // chunk >> 4 is value, including table link
    32  
    33  const (
    34  	huffmanChunkBits  = 9
    35  	huffmanNumChunks  = 1 << huffmanChunkBits
    36  	huffmanCountMask  = 15
    37  	huffmanValueShift = 4
    38  )
    39  
    40  type huffmanDecoder struct {
    41  	min      int                      // the minimum code length
    42  	chunks   [huffmanNumChunks]uint32 // chunks as described above
    43  	links    [][]uint32               // overflow links
    44  	linkMask uint32                   // mask the width of the link table
    45  }
    46  
    47  // Initialize Huffman decoding tables from array of code lengths.
    48  func (h *huffmanDecoder) init(bits []int) bool {
    49  	// Sanity enables additional runtime tests during Huffman
    50  	// table construction.  It's intended to be used during
    51  	// development to supplement the currently ad-hoc unit tests.
    52  	const sanity = false
    53  
    54  	if h.min != 0 {
    55  		*h = huffmanDecoder{}
    56  	}
    57  
    58  	// Count number of codes of each length,
    59  	// compute min and max length.
    60  	var count [maxCodeLen]int
    61  	var min, max int
    62  	for _, n := range bits {
    63  		if n == 0 {
    64  			continue
    65  		}
    66  		if min == 0 || n < min {
    67  			min = n
    68  		}
    69  		if n > max {
    70  			max = n
    71  		}
    72  		count[n]++
    73  	}
    74  	if max == 0 {
    75  		return false
    76  	}
    77  
    78  	code := 0
    79  	var nextcode [maxCodeLen]int
    80  	for i := min; i <= max; i++ {
    81  		code <<= 1
    82  		nextcode[i] = code
    83  		code += count[i]
    84  	}
    85  
    86  	// Check that the coding is complete (i.e., that we've
    87  	// assigned all 2-to-the-max possible bit sequences).
    88  	// Exception: To be compatible with zlib, we also need to
    89  	// accept degenerate single-code codings.  See also
    90  	// TestDegenerateHuffmanCoding.
    91  	if code != 1<<uint(max) && !(code == 1 && max == 1) {
    92  		return false
    93  	}
    94  
    95  	h.min = min
    96  	if max > huffmanChunkBits {
    97  		numLinks := 1 << (uint(max) - huffmanChunkBits)
    98  		h.linkMask = uint32(numLinks - 1)
    99  
   100  		// create link tables
   101  		link := nextcode[huffmanChunkBits+1] >> 1
   102  		h.links = make([][]uint32, huffmanNumChunks-link)
   103  		for j := uint(link); j < huffmanNumChunks; j++ {
   104  			reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
   105  			reverse >>= uint(16 - huffmanChunkBits)
   106  			off := j - uint(link)
   107  			if sanity && h.chunks[reverse] != 0 {
   108  				panic("impossible: overwriting existing chunk")
   109  			}
   110  			h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1))
   111  			h.links[off] = make([]uint32, numLinks)
   112  		}
   113  	}
   114  
   115  	for i, n := range bits {
   116  		if n == 0 {
   117  			continue
   118  		}
   119  		code := nextcode[n]
   120  		nextcode[n]++
   121  		chunk := uint32(i<<huffmanValueShift | n)
   122  		reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8
   123  		reverse >>= uint(16 - n)
   124  		if n <= huffmanChunkBits {
   125  			for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
   126  				// We should never need to overwrite
   127  				// an existing chunk.  Also, 0 is
   128  				// never a valid chunk, because the
   129  				// lower 4 "count" bits should be
   130  				// between 1 and 15.
   131  				if sanity && h.chunks[off] != 0 {
   132  					panic("impossible: overwriting existing chunk")
   133  				}
   134  				h.chunks[off] = chunk
   135  			}
   136  		} else {
   137  			j := reverse & (huffmanNumChunks - 1)
   138  			if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 {
   139  				// Longer codes should have been
   140  				// associated with a link table above.
   141  				panic("impossible: not an indirect chunk")
   142  			}
   143  			value := h.chunks[j] >> huffmanValueShift
   144  			linktab := h.links[value]
   145  			reverse >>= huffmanChunkBits
   146  			for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) {
   147  				if sanity && linktab[off] != 0 {
   148  					panic("impossible: overwriting existing chunk")
   149  				}
   150  				linktab[off] = chunk
   151  			}
   152  		}
   153  	}
   154  
   155  	if sanity {
   156  		// Above we've sanity checked that we never overwrote
   157  		// an existing entry.  Here we additionally check that
   158  		// we filled the tables completely.
   159  		for i, chunk := range h.chunks {
   160  			if chunk == 0 {
   161  				// As an exception, in the degenerate
   162  				// single-code case, we allow odd
   163  				// chunks to be missing.
   164  				if code == 1 && i%2 == 1 {
   165  					continue
   166  				}
   167  				panic("impossible: missing chunk")
   168  			}
   169  		}
   170  		for _, linktab := range h.links {
   171  			for _, chunk := range linktab {
   172  				if chunk == 0 {
   173  					panic("impossible: missing chunk")
   174  				}
   175  			}
   176  		}
   177  	}
   178  
   179  	return true
   180  }
   181  
   182  func main() {
   183  	flag.Parse()
   184  
   185  	var h huffmanDecoder
   186  	var bits [288]int
   187  	initReverseByte()
   188  	for i := 0; i < 144; i++ {
   189  		bits[i] = 8
   190  	}
   191  	for i := 144; i < 256; i++ {
   192  		bits[i] = 9
   193  	}
   194  	for i := 256; i < 280; i++ {
   195  		bits[i] = 7
   196  	}
   197  	for i := 280; i < 288; i++ {
   198  		bits[i] = 8
   199  	}
   200  	h.init(bits[:])
   201  	if h.links != nil {
   202  		log.Fatal("Unexpected links table in fixed Huffman decoder")
   203  	}
   204  
   205  	var buf bytes.Buffer
   206  
   207  	fmt.Fprintf(&buf, `// Copyright 2013 The Go Authors. All rights reserved.
   208  // Use of this source code is governed by a BSD-style
   209  // license that can be found in the LICENSE file.`+"\n\n")
   210  
   211  	fmt.Fprintln(&buf, "package flate")
   212  	fmt.Fprintln(&buf)
   213  	fmt.Fprintln(&buf, "// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT")
   214  	fmt.Fprintln(&buf)
   215  	fmt.Fprintln(&buf, "var fixedHuffmanDecoder = huffmanDecoder{")
   216  	fmt.Fprintf(&buf, "\t%d,\n", h.min)
   217  	fmt.Fprintln(&buf, "\t[huffmanNumChunks]uint32{")
   218  	for i := 0; i < huffmanNumChunks; i++ {
   219  		if i&7 == 0 {
   220  			fmt.Fprintf(&buf, "\t\t")
   221  		} else {
   222  			fmt.Fprintf(&buf, " ")
   223  		}
   224  		fmt.Fprintf(&buf, "0x%04x,", h.chunks[i])
   225  		if i&7 == 7 {
   226  			fmt.Fprintln(&buf)
   227  		}
   228  	}
   229  	fmt.Fprintln(&buf, "\t},")
   230  	fmt.Fprintln(&buf, "\tnil, 0,")
   231  	fmt.Fprintln(&buf, "}")
   232  
   233  	data, err := format.Source(buf.Bytes())
   234  	if err != nil {
   235  		log.Fatal(err)
   236  	}
   237  	err = ioutil.WriteFile(*filename, data, 0644)
   238  	if err != nil {
   239  		log.Fatal(err)
   240  	}
   241  }
   242  
   243  var reverseByte [256]byte
   244  
   245  func initReverseByte() {
   246  	for x := 0; x < 256; x++ {
   247  		var result byte
   248  		for i := uint(0); i < 8; i++ {
   249  			result |= byte(((x >> i) & 1) << (7 - i))
   250  		}
   251  		reverseByte[x] = result
   252  	}
   253  }